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;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 worktree_store::{WorktreeStore, WorktreeStoreEvent},
42 yarn::YarnPathStore,
43};
44use anyhow::{Context as _, Result, anyhow};
45use async_trait::async_trait;
46use client::{TypedEnvelope, proto};
47use clock::Global;
48use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
49use futures::{
50 AsyncWriteExt, Future, FutureExt, StreamExt,
51 future::{Either, Shared, join_all, pending, select},
52 select, select_biased,
53 stream::FuturesUnordered,
54};
55use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
56use gpui::{
57 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
58 WeakEntity,
59};
60use http_client::HttpClient;
61use itertools::Itertools as _;
62use language::{
63 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
64 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
65 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
66 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
67 Transaction, Unclipped,
68 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
69 point_to_lsp,
70 proto::{
71 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
72 serialize_lsp_edit, serialize_version,
73 },
74 range_from_lsp, range_to_lsp,
75 row_chunk::RowChunk,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use serde_json::Value;
97use settings::{Settings, SettingsLocation, SettingsStore};
98use sha2::{Digest, Sha256};
99use smol::channel::Sender;
100use snippet::Snippet;
101use std::{
102 any::TypeId,
103 borrow::Cow,
104 cell::RefCell,
105 cmp::{Ordering, Reverse},
106 convert::TryInto,
107 ffi::OsStr,
108 future::ready,
109 iter, mem,
110 ops::{ControlFlow, Range},
111 path::{self, Path, PathBuf},
112 pin::pin,
113 rc::Rc,
114 sync::{
115 Arc,
116 atomic::{self, AtomicUsize},
117 },
118 time::{Duration, Instant},
119 vec,
120};
121use sum_tree::Dimensions;
122use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
123
124use util::{
125 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
126 paths::{PathStyle, SanitizedPath},
127 post_inc,
128 rel_path::RelPath,
129};
130
131pub use fs::*;
132pub use language::Location;
133pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
134#[cfg(any(test, feature = "test-support"))]
135pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
136pub use worktree::{
137 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
138 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
139};
140
141const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
142pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
143const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
144const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
145
146#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
147pub enum ProgressToken {
148 Number(i32),
149 String(SharedString),
150}
151
152impl std::fmt::Display for ProgressToken {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 match self {
155 Self::Number(number) => write!(f, "{number}"),
156 Self::String(string) => write!(f, "{string}"),
157 }
158 }
159}
160
161impl ProgressToken {
162 fn from_lsp(value: lsp::NumberOrString) -> Self {
163 match value {
164 lsp::NumberOrString::Number(number) => Self::Number(number),
165 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
166 }
167 }
168
169 fn to_lsp(&self) -> lsp::NumberOrString {
170 match self {
171 Self::Number(number) => lsp::NumberOrString::Number(*number),
172 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
173 }
174 }
175
176 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
177 Some(match value.value? {
178 proto::progress_token::Value::Number(number) => Self::Number(number),
179 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
180 })
181 }
182
183 fn to_proto(&self) -> proto::ProgressToken {
184 proto::ProgressToken {
185 value: Some(match self {
186 Self::Number(number) => proto::progress_token::Value::Number(*number),
187 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
188 }),
189 }
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194pub enum FormatTrigger {
195 Save,
196 Manual,
197}
198
199pub enum LspFormatTarget {
200 Buffers,
201 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
202}
203
204#[derive(Clone, PartialEq, Eq, Hash)]
205pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
206
207struct OpenLspBuffer(Entity<Buffer>);
208
209impl FormatTrigger {
210 fn from_proto(value: i32) -> FormatTrigger {
211 match value {
212 0 => FormatTrigger::Save,
213 1 => FormatTrigger::Manual,
214 _ => FormatTrigger::Save,
215 }
216 }
217}
218
219#[derive(Clone)]
220struct UnifiedLanguageServer {
221 id: LanguageServerId,
222 project_roots: HashSet<Arc<RelPath>>,
223}
224
225#[derive(Clone, Debug, Hash, PartialEq, Eq)]
226struct LanguageServerSeed {
227 worktree_id: WorktreeId,
228 name: LanguageServerName,
229 toolchain: Option<Toolchain>,
230 settings: Arc<LspSettings>,
231}
232
233#[derive(Debug)]
234pub struct DocumentDiagnosticsUpdate<'a, D> {
235 pub diagnostics: D,
236 pub result_id: Option<SharedString>,
237 pub registration_id: Option<SharedString>,
238 pub server_id: LanguageServerId,
239 pub disk_based_sources: Cow<'a, [String]>,
240}
241
242pub struct DocumentDiagnostics {
243 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
244 document_abs_path: PathBuf,
245 version: Option<i32>,
246}
247
248#[derive(Default, Debug)]
249struct DynamicRegistrations {
250 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
251 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
252}
253
254pub struct LocalLspStore {
255 weak: WeakEntity<LspStore>,
256 worktree_store: Entity<WorktreeStore>,
257 toolchain_store: Entity<LocalToolchainStore>,
258 http_client: Arc<dyn HttpClient>,
259 environment: Entity<ProjectEnvironment>,
260 fs: Arc<dyn Fs>,
261 languages: Arc<LanguageRegistry>,
262 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
263 yarn: Entity<YarnPathStore>,
264 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
265 buffers_being_formatted: HashSet<BufferId>,
266 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
267 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
268 watched_manifest_filenames: HashSet<ManifestName>,
269 language_server_paths_watched_for_rename:
270 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
271 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
272 supplementary_language_servers:
273 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
274 prettier_store: Entity<PrettierStore>,
275 next_diagnostic_group_id: usize,
276 diagnostics: HashMap<
277 WorktreeId,
278 HashMap<
279 Arc<RelPath>,
280 Vec<(
281 LanguageServerId,
282 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
283 )>,
284 >,
285 >,
286 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
287 _subscription: gpui::Subscription,
288 lsp_tree: LanguageServerTree,
289 registered_buffers: HashMap<BufferId, usize>,
290 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
291 buffer_pull_diagnostics_result_ids: HashMap<
292 LanguageServerId,
293 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
294 >,
295 workspace_pull_diagnostics_result_ids: HashMap<
296 LanguageServerId,
297 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
298 >,
299}
300
301impl LocalLspStore {
302 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
303 pub fn running_language_server_for_id(
304 &self,
305 id: LanguageServerId,
306 ) -> Option<&Arc<LanguageServer>> {
307 let language_server_state = self.language_servers.get(&id)?;
308
309 match language_server_state {
310 LanguageServerState::Running { server, .. } => Some(server),
311 LanguageServerState::Starting { .. } => None,
312 }
313 }
314
315 fn get_or_insert_language_server(
316 &mut self,
317 worktree_handle: &Entity<Worktree>,
318 delegate: Arc<LocalLspAdapterDelegate>,
319 disposition: &Arc<LaunchDisposition>,
320 language_name: &LanguageName,
321 cx: &mut App,
322 ) -> LanguageServerId {
323 let key = LanguageServerSeed {
324 worktree_id: worktree_handle.read(cx).id(),
325 name: disposition.server_name.clone(),
326 settings: disposition.settings.clone(),
327 toolchain: disposition.toolchain.clone(),
328 };
329 if let Some(state) = self.language_server_ids.get_mut(&key) {
330 state.project_roots.insert(disposition.path.path.clone());
331 state.id
332 } else {
333 let adapter = self
334 .languages
335 .lsp_adapters(language_name)
336 .into_iter()
337 .find(|adapter| adapter.name() == disposition.server_name)
338 .expect("To find LSP adapter");
339 let new_language_server_id = self.start_language_server(
340 worktree_handle,
341 delegate,
342 adapter,
343 disposition.settings.clone(),
344 key.clone(),
345 cx,
346 );
347 if let Some(state) = self.language_server_ids.get_mut(&key) {
348 state.project_roots.insert(disposition.path.path.clone());
349 } else {
350 debug_assert!(
351 false,
352 "Expected `start_language_server` to ensure that `key` exists in a map"
353 );
354 }
355 new_language_server_id
356 }
357 }
358
359 fn start_language_server(
360 &mut self,
361 worktree_handle: &Entity<Worktree>,
362 delegate: Arc<LocalLspAdapterDelegate>,
363 adapter: Arc<CachedLspAdapter>,
364 settings: Arc<LspSettings>,
365 key: LanguageServerSeed,
366 cx: &mut App,
367 ) -> LanguageServerId {
368 let worktree = worktree_handle.read(cx);
369
370 let root_path = worktree.abs_path();
371 let toolchain = key.toolchain.clone();
372 let override_options = settings.initialization_options.clone();
373
374 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
375
376 let server_id = self.languages.next_language_server_id();
377 log::trace!(
378 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
379 adapter.name.0
380 );
381
382 let binary = self.get_language_server_binary(
383 adapter.clone(),
384 settings,
385 toolchain.clone(),
386 delegate.clone(),
387 true,
388 cx,
389 );
390 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
391
392 let pending_server = cx.spawn({
393 let adapter = adapter.clone();
394 let server_name = adapter.name.clone();
395 let stderr_capture = stderr_capture.clone();
396 #[cfg(any(test, feature = "test-support"))]
397 let lsp_store = self.weak.clone();
398 let pending_workspace_folders = pending_workspace_folders.clone();
399 async move |cx| {
400 let binary = binary.await?;
401 #[cfg(any(test, feature = "test-support"))]
402 if let Some(server) = lsp_store
403 .update(&mut cx.clone(), |this, cx| {
404 this.languages.create_fake_language_server(
405 server_id,
406 &server_name,
407 binary.clone(),
408 &mut cx.to_async(),
409 )
410 })
411 .ok()
412 .flatten()
413 {
414 return Ok(server);
415 }
416
417 let code_action_kinds = adapter.code_action_kinds();
418 lsp::LanguageServer::new(
419 stderr_capture,
420 server_id,
421 server_name,
422 binary,
423 &root_path,
424 code_action_kinds,
425 Some(pending_workspace_folders),
426 cx,
427 )
428 .await
429 }
430 });
431
432 let startup = {
433 let server_name = adapter.name.0.clone();
434 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
435 let key = key.clone();
436 let adapter = adapter.clone();
437 let lsp_store = self.weak.clone();
438 let pending_workspace_folders = pending_workspace_folders.clone();
439
440 let pull_diagnostics = ProjectSettings::get_global(cx)
441 .diagnostics
442 .lsp_pull_diagnostics
443 .enabled;
444 cx.spawn(async move |cx| {
445 let result = async {
446 let language_server = pending_server.await?;
447
448 let workspace_config = Self::workspace_configuration_for_adapter(
449 adapter.adapter.clone(),
450 &delegate,
451 toolchain,
452 None,
453 cx,
454 )
455 .await?;
456
457 let mut initialization_options = Self::initialization_options_for_adapter(
458 adapter.adapter.clone(),
459 &delegate,
460 )
461 .await?;
462
463 match (&mut initialization_options, override_options) {
464 (Some(initialization_options), Some(override_options)) => {
465 merge_json_value_into(override_options, initialization_options);
466 }
467 (None, override_options) => initialization_options = override_options,
468 _ => {}
469 }
470
471 let initialization_params = cx.update(|cx| {
472 let mut params =
473 language_server.default_initialize_params(pull_diagnostics, cx);
474 params.initialization_options = initialization_options;
475 adapter.adapter.prepare_initialize_params(params, cx)
476 })??;
477
478 Self::setup_lsp_messages(
479 lsp_store.clone(),
480 &language_server,
481 delegate.clone(),
482 adapter.clone(),
483 );
484
485 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
486 settings: workspace_config,
487 };
488 let language_server = cx
489 .update(|cx| {
490 language_server.initialize(
491 initialization_params,
492 Arc::new(did_change_configuration_params.clone()),
493 cx,
494 )
495 })?
496 .await
497 .inspect_err(|_| {
498 if let Some(lsp_store) = lsp_store.upgrade() {
499 lsp_store
500 .update(cx, |lsp_store, cx| {
501 lsp_store.cleanup_lsp_data(server_id);
502 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
503 })
504 .ok();
505 }
506 })?;
507
508 language_server.notify::<lsp::notification::DidChangeConfiguration>(
509 did_change_configuration_params,
510 )?;
511
512 anyhow::Ok(language_server)
513 }
514 .await;
515
516 match result {
517 Ok(server) => {
518 lsp_store
519 .update(cx, |lsp_store, cx| {
520 lsp_store.insert_newly_running_language_server(
521 adapter,
522 server.clone(),
523 server_id,
524 key,
525 pending_workspace_folders,
526 cx,
527 );
528 })
529 .ok();
530 stderr_capture.lock().take();
531 Some(server)
532 }
533
534 Err(err) => {
535 let log = stderr_capture.lock().take().unwrap_or_default();
536 delegate.update_status(
537 adapter.name(),
538 BinaryStatus::Failed {
539 error: if log.is_empty() {
540 format!("{err:#}")
541 } else {
542 format!("{err:#}\n-- stderr --\n{log}")
543 },
544 },
545 );
546 log::error!("Failed to start language server {server_name:?}: {err:?}");
547 if !log.is_empty() {
548 log::error!("server stderr: {log}");
549 }
550 None
551 }
552 }
553 })
554 };
555 let state = LanguageServerState::Starting {
556 startup,
557 pending_workspace_folders,
558 };
559
560 self.languages
561 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
562
563 self.language_servers.insert(server_id, state);
564 self.language_server_ids
565 .entry(key)
566 .or_insert(UnifiedLanguageServer {
567 id: server_id,
568 project_roots: Default::default(),
569 });
570 server_id
571 }
572
573 fn get_language_server_binary(
574 &self,
575 adapter: Arc<CachedLspAdapter>,
576 settings: Arc<LspSettings>,
577 toolchain: Option<Toolchain>,
578 delegate: Arc<dyn LspAdapterDelegate>,
579 allow_binary_download: bool,
580 cx: &mut App,
581 ) -> Task<Result<LanguageServerBinary>> {
582 if let Some(settings) = &settings.binary
583 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
584 {
585 let settings = settings.clone();
586
587 return cx.background_spawn(async move {
588 let mut env = delegate.shell_env().await;
589 env.extend(settings.env.unwrap_or_default());
590
591 Ok(LanguageServerBinary {
592 path: delegate.resolve_executable_path(path),
593 env: Some(env),
594 arguments: settings
595 .arguments
596 .unwrap_or_default()
597 .iter()
598 .map(Into::into)
599 .collect(),
600 })
601 });
602 }
603 let lsp_binary_options = LanguageServerBinaryOptions {
604 allow_path_lookup: !settings
605 .binary
606 .as_ref()
607 .and_then(|b| b.ignore_system_version)
608 .unwrap_or_default(),
609 allow_binary_download,
610 pre_release: settings
611 .fetch
612 .as_ref()
613 .and_then(|f| f.pre_release)
614 .unwrap_or(false),
615 };
616
617 cx.spawn(async move |cx| {
618 let (existing_binary, maybe_download_binary) = adapter
619 .clone()
620 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
621 .await
622 .await;
623
624 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
625
626 let mut binary = match (existing_binary, maybe_download_binary) {
627 (binary, None) => binary?,
628 (Err(_), Some(downloader)) => downloader.await?,
629 (Ok(existing_binary), Some(downloader)) => {
630 let mut download_timeout = cx
631 .background_executor()
632 .timer(SERVER_DOWNLOAD_TIMEOUT)
633 .fuse();
634 let mut downloader = downloader.fuse();
635 futures::select! {
636 _ = download_timeout => {
637 // Return existing binary and kick the existing work to the background.
638 cx.spawn(async move |_| downloader.await).detach();
639 Ok(existing_binary)
640 },
641 downloaded_or_existing_binary = downloader => {
642 // If download fails, this results in the existing binary.
643 downloaded_or_existing_binary
644 }
645 }?
646 }
647 };
648 let mut shell_env = delegate.shell_env().await;
649
650 shell_env.extend(binary.env.unwrap_or_default());
651
652 if let Some(settings) = settings.binary.as_ref() {
653 if let Some(arguments) = &settings.arguments {
654 binary.arguments = arguments.iter().map(Into::into).collect();
655 }
656 if let Some(env) = &settings.env {
657 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
658 }
659 }
660
661 binary.env = Some(shell_env);
662 Ok(binary)
663 })
664 }
665
666 fn setup_lsp_messages(
667 lsp_store: WeakEntity<LspStore>,
668 language_server: &LanguageServer,
669 delegate: Arc<dyn LspAdapterDelegate>,
670 adapter: Arc<CachedLspAdapter>,
671 ) {
672 let name = language_server.name();
673 let server_id = language_server.server_id();
674 language_server
675 .on_notification::<lsp::notification::PublishDiagnostics, _>({
676 let adapter = adapter.clone();
677 let this = lsp_store.clone();
678 move |mut params, cx| {
679 let adapter = adapter.clone();
680 if let Some(this) = this.upgrade() {
681 this.update(cx, |this, cx| {
682 {
683 let buffer = params
684 .uri
685 .to_file_path()
686 .map(|file_path| this.get_buffer(&file_path, cx))
687 .ok()
688 .flatten();
689 adapter.process_diagnostics(&mut params, server_id, buffer);
690 }
691
692 this.merge_lsp_diagnostics(
693 DiagnosticSourceKind::Pushed,
694 vec![DocumentDiagnosticsUpdate {
695 server_id,
696 diagnostics: params,
697 result_id: None,
698 disk_based_sources: Cow::Borrowed(
699 &adapter.disk_based_diagnostic_sources,
700 ),
701 registration_id: None,
702 }],
703 |_, diagnostic, cx| match diagnostic.source_kind {
704 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
705 adapter.retain_old_diagnostic(diagnostic, cx)
706 }
707 DiagnosticSourceKind::Pulled => true,
708 },
709 cx,
710 )
711 .log_err();
712 })
713 .ok();
714 }
715 }
716 })
717 .detach();
718 language_server
719 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
720 let adapter = adapter.adapter.clone();
721 let delegate = delegate.clone();
722 let this = lsp_store.clone();
723 move |params, cx| {
724 let adapter = adapter.clone();
725 let delegate = delegate.clone();
726 let this = this.clone();
727 let mut cx = cx.clone();
728 async move {
729 let toolchain_for_id = this
730 .update(&mut cx, |this, _| {
731 this.as_local()?.language_server_ids.iter().find_map(
732 |(seed, value)| {
733 (value.id == server_id).then(|| seed.toolchain.clone())
734 },
735 )
736 })?
737 .context("Expected the LSP store to be in a local mode")?;
738
739 let mut scope_uri_to_workspace_config = BTreeMap::new();
740 for item in ¶ms.items {
741 let scope_uri = item.scope_uri.clone();
742 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
743 scope_uri_to_workspace_config.entry(scope_uri.clone())
744 else {
745 // We've already queried workspace configuration of this URI.
746 continue;
747 };
748 let workspace_config = Self::workspace_configuration_for_adapter(
749 adapter.clone(),
750 &delegate,
751 toolchain_for_id.clone(),
752 scope_uri,
753 &mut cx,
754 )
755 .await?;
756 new_scope_uri.insert(workspace_config);
757 }
758
759 Ok(params
760 .items
761 .into_iter()
762 .filter_map(|item| {
763 let workspace_config =
764 scope_uri_to_workspace_config.get(&item.scope_uri)?;
765 if let Some(section) = &item.section {
766 Some(
767 workspace_config
768 .get(section)
769 .cloned()
770 .unwrap_or(serde_json::Value::Null),
771 )
772 } else {
773 Some(workspace_config.clone())
774 }
775 })
776 .collect())
777 }
778 }
779 })
780 .detach();
781
782 language_server
783 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
784 let this = lsp_store.clone();
785 move |_, cx| {
786 let this = this.clone();
787 let cx = cx.clone();
788 async move {
789 let Some(server) =
790 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
791 else {
792 return Ok(None);
793 };
794 let root = server.workspace_folders();
795 Ok(Some(
796 root.into_iter()
797 .map(|uri| WorkspaceFolder {
798 uri,
799 name: Default::default(),
800 })
801 .collect(),
802 ))
803 }
804 }
805 })
806 .detach();
807 // Even though we don't have handling for these requests, respond to them to
808 // avoid stalling any language server like `gopls` which waits for a response
809 // to these requests when initializing.
810 language_server
811 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
812 let this = lsp_store.clone();
813 move |params, cx| {
814 let this = this.clone();
815 let mut cx = cx.clone();
816 async move {
817 this.update(&mut cx, |this, _| {
818 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
819 {
820 status
821 .progress_tokens
822 .insert(ProgressToken::from_lsp(params.token));
823 }
824 })?;
825
826 Ok(())
827 }
828 }
829 })
830 .detach();
831
832 language_server
833 .on_request::<lsp::request::RegisterCapability, _, _>({
834 let lsp_store = lsp_store.clone();
835 move |params, cx| {
836 let lsp_store = lsp_store.clone();
837 let mut cx = cx.clone();
838 async move {
839 lsp_store
840 .update(&mut cx, |lsp_store, cx| {
841 if lsp_store.as_local().is_some() {
842 match lsp_store
843 .register_server_capabilities(server_id, params, cx)
844 {
845 Ok(()) => {}
846 Err(e) => {
847 log::error!(
848 "Failed to register server capabilities: {e:#}"
849 );
850 }
851 };
852 }
853 })
854 .ok();
855 Ok(())
856 }
857 }
858 })
859 .detach();
860
861 language_server
862 .on_request::<lsp::request::UnregisterCapability, _, _>({
863 let lsp_store = lsp_store.clone();
864 move |params, cx| {
865 let lsp_store = lsp_store.clone();
866 let mut cx = cx.clone();
867 async move {
868 lsp_store
869 .update(&mut cx, |lsp_store, cx| {
870 if lsp_store.as_local().is_some() {
871 match lsp_store
872 .unregister_server_capabilities(server_id, params, cx)
873 {
874 Ok(()) => {}
875 Err(e) => {
876 log::error!(
877 "Failed to unregister server capabilities: {e:#}"
878 );
879 }
880 }
881 }
882 })
883 .ok();
884 Ok(())
885 }
886 }
887 })
888 .detach();
889
890 language_server
891 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
892 let this = lsp_store.clone();
893 move |params, cx| {
894 let mut cx = cx.clone();
895 let this = this.clone();
896 async move {
897 LocalLspStore::on_lsp_workspace_edit(
898 this.clone(),
899 params,
900 server_id,
901 &mut cx,
902 )
903 .await
904 }
905 }
906 })
907 .detach();
908
909 language_server
910 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
911 let lsp_store = lsp_store.clone();
912 let request_id = Arc::new(AtomicUsize::new(0));
913 move |(), cx| {
914 let lsp_store = lsp_store.clone();
915 let request_id = request_id.clone();
916 let mut cx = cx.clone();
917 async move {
918 lsp_store
919 .update(&mut cx, |lsp_store, cx| {
920 let request_id =
921 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
922 cx.emit(LspStoreEvent::RefreshInlayHints {
923 server_id,
924 request_id,
925 });
926 lsp_store
927 .downstream_client
928 .as_ref()
929 .map(|(client, project_id)| {
930 client.send(proto::RefreshInlayHints {
931 project_id: *project_id,
932 server_id: server_id.to_proto(),
933 request_id: request_id.map(|id| id as u64),
934 })
935 })
936 })?
937 .transpose()?;
938 Ok(())
939 }
940 }
941 })
942 .detach();
943
944 language_server
945 .on_request::<lsp::request::CodeLensRefresh, _, _>({
946 let this = lsp_store.clone();
947 move |(), cx| {
948 let this = this.clone();
949 let mut cx = cx.clone();
950 async move {
951 this.update(&mut cx, |this, cx| {
952 cx.emit(LspStoreEvent::RefreshCodeLens);
953 this.downstream_client.as_ref().map(|(client, project_id)| {
954 client.send(proto::RefreshCodeLens {
955 project_id: *project_id,
956 })
957 })
958 })?
959 .transpose()?;
960 Ok(())
961 }
962 }
963 })
964 .detach();
965
966 language_server
967 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
968 let this = lsp_store.clone();
969 move |(), cx| {
970 let this = this.clone();
971 let mut cx = cx.clone();
972 async move {
973 this.update(&mut cx, |lsp_store, _| {
974 lsp_store.pull_workspace_diagnostics(server_id);
975 lsp_store
976 .downstream_client
977 .as_ref()
978 .map(|(client, project_id)| {
979 client.send(proto::PullWorkspaceDiagnostics {
980 project_id: *project_id,
981 server_id: server_id.to_proto(),
982 })
983 })
984 })?
985 .transpose()?;
986 Ok(())
987 }
988 }
989 })
990 .detach();
991
992 language_server
993 .on_request::<lsp::request::ShowMessageRequest, _, _>({
994 let this = lsp_store.clone();
995 let name = name.to_string();
996 move |params, cx| {
997 let this = this.clone();
998 let name = name.to_string();
999 let mut cx = cx.clone();
1000 async move {
1001 let actions = params.actions.unwrap_or_default();
1002 let (tx, rx) = smol::channel::bounded(1);
1003 let request = LanguageServerPromptRequest {
1004 level: match params.typ {
1005 lsp::MessageType::ERROR => PromptLevel::Critical,
1006 lsp::MessageType::WARNING => PromptLevel::Warning,
1007 _ => PromptLevel::Info,
1008 },
1009 message: params.message,
1010 actions,
1011 response_channel: tx,
1012 lsp_name: name.clone(),
1013 };
1014
1015 let did_update = this
1016 .update(&mut cx, |_, cx| {
1017 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1018 })
1019 .is_ok();
1020 if did_update {
1021 let response = rx.recv().await.ok();
1022 Ok(response)
1023 } else {
1024 Ok(None)
1025 }
1026 }
1027 }
1028 })
1029 .detach();
1030 language_server
1031 .on_notification::<lsp::notification::ShowMessage, _>({
1032 let this = lsp_store.clone();
1033 let name = name.to_string();
1034 move |params, cx| {
1035 let this = this.clone();
1036 let name = name.to_string();
1037 let mut cx = cx.clone();
1038
1039 let (tx, _) = smol::channel::bounded(1);
1040 let request = LanguageServerPromptRequest {
1041 level: match params.typ {
1042 lsp::MessageType::ERROR => PromptLevel::Critical,
1043 lsp::MessageType::WARNING => PromptLevel::Warning,
1044 _ => PromptLevel::Info,
1045 },
1046 message: params.message,
1047 actions: vec![],
1048 response_channel: tx,
1049 lsp_name: name,
1050 };
1051
1052 let _ = this.update(&mut cx, |_, cx| {
1053 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1054 });
1055 }
1056 })
1057 .detach();
1058
1059 let disk_based_diagnostics_progress_token =
1060 adapter.disk_based_diagnostics_progress_token.clone();
1061
1062 language_server
1063 .on_notification::<lsp::notification::Progress, _>({
1064 let this = lsp_store.clone();
1065 move |params, cx| {
1066 if let Some(this) = this.upgrade() {
1067 this.update(cx, |this, cx| {
1068 this.on_lsp_progress(
1069 params,
1070 server_id,
1071 disk_based_diagnostics_progress_token.clone(),
1072 cx,
1073 );
1074 })
1075 .ok();
1076 }
1077 }
1078 })
1079 .detach();
1080
1081 language_server
1082 .on_notification::<lsp::notification::LogMessage, _>({
1083 let this = lsp_store.clone();
1084 move |params, cx| {
1085 if let Some(this) = this.upgrade() {
1086 this.update(cx, |_, cx| {
1087 cx.emit(LspStoreEvent::LanguageServerLog(
1088 server_id,
1089 LanguageServerLogType::Log(params.typ),
1090 params.message,
1091 ));
1092 })
1093 .ok();
1094 }
1095 }
1096 })
1097 .detach();
1098
1099 language_server
1100 .on_notification::<lsp::notification::LogTrace, _>({
1101 let this = lsp_store.clone();
1102 move |params, cx| {
1103 let mut cx = cx.clone();
1104 if let Some(this) = this.upgrade() {
1105 this.update(&mut cx, |_, cx| {
1106 cx.emit(LspStoreEvent::LanguageServerLog(
1107 server_id,
1108 LanguageServerLogType::Trace {
1109 verbose_info: params.verbose,
1110 },
1111 params.message,
1112 ));
1113 })
1114 .ok();
1115 }
1116 }
1117 })
1118 .detach();
1119
1120 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1121 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1122 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1123 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1124 }
1125
1126 fn shutdown_language_servers_on_quit(
1127 &mut self,
1128 _: &mut Context<LspStore>,
1129 ) -> impl Future<Output = ()> + use<> {
1130 let shutdown_futures = self
1131 .language_servers
1132 .drain()
1133 .map(|(_, server_state)| Self::shutdown_server(server_state))
1134 .collect::<Vec<_>>();
1135
1136 async move {
1137 join_all(shutdown_futures).await;
1138 }
1139 }
1140
1141 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1142 match server_state {
1143 LanguageServerState::Running { server, .. } => {
1144 if let Some(shutdown) = server.shutdown() {
1145 shutdown.await;
1146 }
1147 }
1148 LanguageServerState::Starting { startup, .. } => {
1149 if let Some(server) = startup.await
1150 && let Some(shutdown) = server.shutdown()
1151 {
1152 shutdown.await;
1153 }
1154 }
1155 }
1156 Ok(())
1157 }
1158
1159 fn language_servers_for_worktree(
1160 &self,
1161 worktree_id: WorktreeId,
1162 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1163 self.language_server_ids
1164 .iter()
1165 .filter_map(move |(seed, state)| {
1166 if seed.worktree_id != worktree_id {
1167 return None;
1168 }
1169
1170 if let Some(LanguageServerState::Running { server, .. }) =
1171 self.language_servers.get(&state.id)
1172 {
1173 Some(server)
1174 } else {
1175 None
1176 }
1177 })
1178 }
1179
1180 fn language_server_ids_for_project_path(
1181 &self,
1182 project_path: ProjectPath,
1183 language: &Language,
1184 cx: &mut App,
1185 ) -> Vec<LanguageServerId> {
1186 let Some(worktree) = self
1187 .worktree_store
1188 .read(cx)
1189 .worktree_for_id(project_path.worktree_id, cx)
1190 else {
1191 return Vec::new();
1192 };
1193 let delegate: Arc<dyn ManifestDelegate> =
1194 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1195
1196 self.lsp_tree
1197 .get(
1198 project_path,
1199 language.name(),
1200 language.manifest(),
1201 &delegate,
1202 cx,
1203 )
1204 .collect::<Vec<_>>()
1205 }
1206
1207 fn language_server_ids_for_buffer(
1208 &self,
1209 buffer: &Buffer,
1210 cx: &mut App,
1211 ) -> Vec<LanguageServerId> {
1212 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1213 let worktree_id = file.worktree_id(cx);
1214
1215 let path: Arc<RelPath> = file
1216 .path()
1217 .parent()
1218 .map(Arc::from)
1219 .unwrap_or_else(|| file.path().clone());
1220 let worktree_path = ProjectPath { worktree_id, path };
1221 self.language_server_ids_for_project_path(worktree_path, language, cx)
1222 } else {
1223 Vec::new()
1224 }
1225 }
1226
1227 fn language_servers_for_buffer<'a>(
1228 &'a self,
1229 buffer: &'a Buffer,
1230 cx: &'a mut App,
1231 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1232 self.language_server_ids_for_buffer(buffer, cx)
1233 .into_iter()
1234 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1235 LanguageServerState::Running {
1236 adapter, server, ..
1237 } => Some((adapter, server)),
1238 _ => None,
1239 })
1240 }
1241
1242 async fn execute_code_action_kind_locally(
1243 lsp_store: WeakEntity<LspStore>,
1244 mut buffers: Vec<Entity<Buffer>>,
1245 kind: CodeActionKind,
1246 push_to_history: bool,
1247 cx: &mut AsyncApp,
1248 ) -> anyhow::Result<ProjectTransaction> {
1249 // Do not allow multiple concurrent code actions requests for the
1250 // same buffer.
1251 lsp_store.update(cx, |this, cx| {
1252 let this = this.as_local_mut().unwrap();
1253 buffers.retain(|buffer| {
1254 this.buffers_being_formatted
1255 .insert(buffer.read(cx).remote_id())
1256 });
1257 })?;
1258 let _cleanup = defer({
1259 let this = lsp_store.clone();
1260 let mut cx = cx.clone();
1261 let buffers = &buffers;
1262 move || {
1263 this.update(&mut cx, |this, cx| {
1264 let this = this.as_local_mut().unwrap();
1265 for buffer in buffers {
1266 this.buffers_being_formatted
1267 .remove(&buffer.read(cx).remote_id());
1268 }
1269 })
1270 .ok();
1271 }
1272 });
1273 let mut project_transaction = ProjectTransaction::default();
1274
1275 for buffer in &buffers {
1276 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1277 buffer.update(cx, |buffer, cx| {
1278 lsp_store
1279 .as_local()
1280 .unwrap()
1281 .language_servers_for_buffer(buffer, cx)
1282 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1283 .collect::<Vec<_>>()
1284 })
1285 })?;
1286 for (_, language_server) in adapters_and_servers.iter() {
1287 let actions = Self::get_server_code_actions_from_action_kinds(
1288 &lsp_store,
1289 language_server.server_id(),
1290 vec![kind.clone()],
1291 buffer,
1292 cx,
1293 )
1294 .await?;
1295 Self::execute_code_actions_on_server(
1296 &lsp_store,
1297 language_server,
1298 actions,
1299 push_to_history,
1300 &mut project_transaction,
1301 cx,
1302 )
1303 .await?;
1304 }
1305 }
1306 Ok(project_transaction)
1307 }
1308
1309 async fn format_locally(
1310 lsp_store: WeakEntity<LspStore>,
1311 mut buffers: Vec<FormattableBuffer>,
1312 push_to_history: bool,
1313 trigger: FormatTrigger,
1314 logger: zlog::Logger,
1315 cx: &mut AsyncApp,
1316 ) -> anyhow::Result<ProjectTransaction> {
1317 // Do not allow multiple concurrent formatting requests for the
1318 // same buffer.
1319 lsp_store.update(cx, |this, cx| {
1320 let this = this.as_local_mut().unwrap();
1321 buffers.retain(|buffer| {
1322 this.buffers_being_formatted
1323 .insert(buffer.handle.read(cx).remote_id())
1324 });
1325 })?;
1326
1327 let _cleanup = defer({
1328 let this = lsp_store.clone();
1329 let mut cx = cx.clone();
1330 let buffers = &buffers;
1331 move || {
1332 this.update(&mut cx, |this, cx| {
1333 let this = this.as_local_mut().unwrap();
1334 for buffer in buffers {
1335 this.buffers_being_formatted
1336 .remove(&buffer.handle.read(cx).remote_id());
1337 }
1338 })
1339 .ok();
1340 }
1341 });
1342
1343 let mut project_transaction = ProjectTransaction::default();
1344
1345 for buffer in &buffers {
1346 zlog::debug!(
1347 logger =>
1348 "formatting buffer '{:?}'",
1349 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1350 );
1351 // Create an empty transaction to hold all of the formatting edits.
1352 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1353 // ensure no transactions created while formatting are
1354 // grouped with the previous transaction in the history
1355 // based on the transaction group interval
1356 buffer.finalize_last_transaction();
1357 buffer
1358 .start_transaction()
1359 .context("transaction already open")?;
1360 buffer.end_transaction(cx);
1361 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1362 buffer.finalize_last_transaction();
1363 anyhow::Ok(transaction_id)
1364 })??;
1365
1366 let result = Self::format_buffer_locally(
1367 lsp_store.clone(),
1368 buffer,
1369 formatting_transaction_id,
1370 trigger,
1371 logger,
1372 cx,
1373 )
1374 .await;
1375
1376 buffer.handle.update(cx, |buffer, cx| {
1377 let Some(formatting_transaction) =
1378 buffer.get_transaction(formatting_transaction_id).cloned()
1379 else {
1380 zlog::warn!(logger => "no formatting transaction");
1381 return;
1382 };
1383 if formatting_transaction.edit_ids.is_empty() {
1384 zlog::debug!(logger => "no changes made while formatting");
1385 buffer.forget_transaction(formatting_transaction_id);
1386 return;
1387 }
1388 if !push_to_history {
1389 zlog::trace!(logger => "forgetting format transaction");
1390 buffer.forget_transaction(formatting_transaction.id);
1391 }
1392 project_transaction
1393 .0
1394 .insert(cx.entity(), formatting_transaction);
1395 })?;
1396
1397 result?;
1398 }
1399
1400 Ok(project_transaction)
1401 }
1402
1403 async fn format_buffer_locally(
1404 lsp_store: WeakEntity<LspStore>,
1405 buffer: &FormattableBuffer,
1406 formatting_transaction_id: clock::Lamport,
1407 trigger: FormatTrigger,
1408 logger: zlog::Logger,
1409 cx: &mut AsyncApp,
1410 ) -> Result<()> {
1411 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1412 buffer.handle.update(cx, |buffer, cx| {
1413 let adapters_and_servers = lsp_store
1414 .as_local()
1415 .unwrap()
1416 .language_servers_for_buffer(buffer, cx)
1417 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1418 .collect::<Vec<_>>();
1419 let settings =
1420 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1421 .into_owned();
1422 (adapters_and_servers, settings)
1423 })
1424 })?;
1425
1426 /// Apply edits to the buffer that will become part of the formatting transaction.
1427 /// Fails if the buffer has been edited since the start of that transaction.
1428 fn extend_formatting_transaction(
1429 buffer: &FormattableBuffer,
1430 formatting_transaction_id: text::TransactionId,
1431 cx: &mut AsyncApp,
1432 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1433 ) -> anyhow::Result<()> {
1434 buffer.handle.update(cx, |buffer, cx| {
1435 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1436 if last_transaction_id != Some(formatting_transaction_id) {
1437 anyhow::bail!("Buffer edited while formatting. Aborting")
1438 }
1439 buffer.start_transaction();
1440 operation(buffer, cx);
1441 if let Some(transaction_id) = buffer.end_transaction(cx) {
1442 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1443 }
1444 Ok(())
1445 })?
1446 }
1447
1448 // handle whitespace formatting
1449 if settings.remove_trailing_whitespace_on_save {
1450 zlog::trace!(logger => "removing trailing whitespace");
1451 let diff = buffer
1452 .handle
1453 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1454 .await;
1455 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1456 buffer.apply_diff(diff, cx);
1457 })?;
1458 }
1459
1460 if settings.ensure_final_newline_on_save {
1461 zlog::trace!(logger => "ensuring final newline");
1462 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1463 buffer.ensure_final_newline(cx);
1464 })?;
1465 }
1466
1467 // Formatter for `code_actions_on_format` that runs before
1468 // the rest of the formatters
1469 let mut code_actions_on_format_formatters = None;
1470 let should_run_code_actions_on_format = !matches!(
1471 (trigger, &settings.format_on_save),
1472 (FormatTrigger::Save, &FormatOnSave::Off)
1473 );
1474 if should_run_code_actions_on_format {
1475 let have_code_actions_to_run_on_format = settings
1476 .code_actions_on_format
1477 .values()
1478 .any(|enabled| *enabled);
1479 if have_code_actions_to_run_on_format {
1480 zlog::trace!(logger => "going to run code actions on format");
1481 code_actions_on_format_formatters = Some(
1482 settings
1483 .code_actions_on_format
1484 .iter()
1485 .filter_map(|(action, enabled)| enabled.then_some(action))
1486 .cloned()
1487 .map(Formatter::CodeAction)
1488 .collect::<Vec<_>>(),
1489 );
1490 }
1491 }
1492
1493 let formatters = match (trigger, &settings.format_on_save) {
1494 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1495 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1496 settings.formatter.as_ref()
1497 }
1498 };
1499
1500 let formatters = code_actions_on_format_formatters
1501 .iter()
1502 .flatten()
1503 .chain(formatters);
1504
1505 for formatter in formatters {
1506 let formatter = if formatter == &Formatter::Auto {
1507 if settings.prettier.allowed {
1508 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1509 &Formatter::Prettier
1510 } else {
1511 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1512 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1513 }
1514 } else {
1515 formatter
1516 };
1517 match formatter {
1518 Formatter::Auto => unreachable!("Auto resolved above"),
1519 Formatter::Prettier => {
1520 let logger = zlog::scoped!(logger => "prettier");
1521 zlog::trace!(logger => "formatting");
1522 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1523
1524 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1525 lsp_store.prettier_store().unwrap().downgrade()
1526 })?;
1527 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1528 .await
1529 .transpose()?;
1530 let Some(diff) = diff else {
1531 zlog::trace!(logger => "No changes");
1532 continue;
1533 };
1534
1535 extend_formatting_transaction(
1536 buffer,
1537 formatting_transaction_id,
1538 cx,
1539 |buffer, cx| {
1540 buffer.apply_diff(diff, cx);
1541 },
1542 )?;
1543 }
1544 Formatter::External { command, arguments } => {
1545 let logger = zlog::scoped!(logger => "command");
1546 zlog::trace!(logger => "formatting");
1547 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1548
1549 let diff = Self::format_via_external_command(
1550 buffer,
1551 command.as_ref(),
1552 arguments.as_deref(),
1553 cx,
1554 )
1555 .await
1556 .with_context(|| {
1557 format!("Failed to format buffer via external command: {}", command)
1558 })?;
1559 let Some(diff) = diff else {
1560 zlog::trace!(logger => "No changes");
1561 continue;
1562 };
1563
1564 extend_formatting_transaction(
1565 buffer,
1566 formatting_transaction_id,
1567 cx,
1568 |buffer, cx| {
1569 buffer.apply_diff(diff, cx);
1570 },
1571 )?;
1572 }
1573 Formatter::LanguageServer(specifier) => {
1574 let logger = zlog::scoped!(logger => "language-server");
1575 zlog::trace!(logger => "formatting");
1576 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1577
1578 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1579 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1580 continue;
1581 };
1582
1583 let language_server = match specifier {
1584 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1585 adapters_and_servers.iter().find_map(|(adapter, server)| {
1586 if adapter.name.0.as_ref() == name {
1587 Some(server.clone())
1588 } else {
1589 None
1590 }
1591 })
1592 }
1593 settings::LanguageServerFormatterSpecifier::Current => {
1594 adapters_and_servers.first().map(|e| e.1.clone())
1595 }
1596 };
1597
1598 let Some(language_server) = language_server else {
1599 log::debug!(
1600 "No language server found to format buffer '{:?}'. Skipping",
1601 buffer_path_abs.as_path().to_string_lossy()
1602 );
1603 continue;
1604 };
1605
1606 zlog::trace!(
1607 logger =>
1608 "Formatting buffer '{:?}' using language server '{:?}'",
1609 buffer_path_abs.as_path().to_string_lossy(),
1610 language_server.name()
1611 );
1612
1613 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1614 zlog::trace!(logger => "formatting ranges");
1615 Self::format_ranges_via_lsp(
1616 &lsp_store,
1617 &buffer.handle,
1618 ranges,
1619 buffer_path_abs,
1620 &language_server,
1621 &settings,
1622 cx,
1623 )
1624 .await
1625 .context("Failed to format ranges via language server")?
1626 } else {
1627 zlog::trace!(logger => "formatting full");
1628 Self::format_via_lsp(
1629 &lsp_store,
1630 &buffer.handle,
1631 buffer_path_abs,
1632 &language_server,
1633 &settings,
1634 cx,
1635 )
1636 .await
1637 .context("failed to format via language server")?
1638 };
1639
1640 if edits.is_empty() {
1641 zlog::trace!(logger => "No changes");
1642 continue;
1643 }
1644 extend_formatting_transaction(
1645 buffer,
1646 formatting_transaction_id,
1647 cx,
1648 |buffer, cx| {
1649 buffer.edit(edits, None, cx);
1650 },
1651 )?;
1652 }
1653 Formatter::CodeAction(code_action_name) => {
1654 let logger = zlog::scoped!(logger => "code-actions");
1655 zlog::trace!(logger => "formatting");
1656 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1657
1658 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1659 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1660 continue;
1661 };
1662
1663 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1664 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1665
1666 let mut actions_and_servers = Vec::new();
1667
1668 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1669 let actions_result = Self::get_server_code_actions_from_action_kinds(
1670 &lsp_store,
1671 language_server.server_id(),
1672 vec![code_action_kind.clone()],
1673 &buffer.handle,
1674 cx,
1675 )
1676 .await
1677 .with_context(|| {
1678 format!(
1679 "Failed to resolve code action {:?} with language server {}",
1680 code_action_kind,
1681 language_server.name()
1682 )
1683 });
1684 let Ok(actions) = actions_result else {
1685 // note: it may be better to set result to the error and break formatters here
1686 // but for now we try to execute the actions that we can resolve and skip the rest
1687 zlog::error!(
1688 logger =>
1689 "Failed to resolve code action {:?} with language server {}",
1690 code_action_kind,
1691 language_server.name()
1692 );
1693 continue;
1694 };
1695 for action in actions {
1696 actions_and_servers.push((action, index));
1697 }
1698 }
1699
1700 if actions_and_servers.is_empty() {
1701 zlog::warn!(logger => "No code actions were resolved, continuing");
1702 continue;
1703 }
1704
1705 'actions: for (mut action, server_index) in actions_and_servers {
1706 let server = &adapters_and_servers[server_index].1;
1707
1708 let describe_code_action = |action: &CodeAction| {
1709 format!(
1710 "code action '{}' with title \"{}\" on server {}",
1711 action
1712 .lsp_action
1713 .action_kind()
1714 .unwrap_or("unknown".into())
1715 .as_str(),
1716 action.lsp_action.title(),
1717 server.name(),
1718 )
1719 };
1720
1721 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1722
1723 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1724 zlog::error!(
1725 logger =>
1726 "Failed to resolve {}. Error: {}",
1727 describe_code_action(&action),
1728 err
1729 );
1730 continue;
1731 }
1732
1733 if let Some(edit) = action.lsp_action.edit().cloned() {
1734 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1735 // but filters out and logs warnings for code actions that require unreasonably
1736 // difficult handling on our part, such as:
1737 // - applying edits that call commands
1738 // which can result in arbitrary workspace edits being sent from the server that
1739 // have no way of being tied back to the command that initiated them (i.e. we
1740 // can't know which edits are part of the format request, or if the server is done sending
1741 // actions in response to the command)
1742 // - actions that create/delete/modify/rename files other than the one we are formatting
1743 // as we then would need to handle such changes correctly in the local history as well
1744 // as the remote history through the ProjectTransaction
1745 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1746 // Supporting these actions is not impossible, but not supported as of yet.
1747 if edit.changes.is_none() && edit.document_changes.is_none() {
1748 zlog::trace!(
1749 logger =>
1750 "No changes for code action. Skipping {}",
1751 describe_code_action(&action),
1752 );
1753 continue;
1754 }
1755
1756 let mut operations = Vec::new();
1757 if let Some(document_changes) = edit.document_changes {
1758 match document_changes {
1759 lsp::DocumentChanges::Edits(edits) => operations.extend(
1760 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1761 ),
1762 lsp::DocumentChanges::Operations(ops) => operations = ops,
1763 }
1764 } else if let Some(changes) = edit.changes {
1765 operations.extend(changes.into_iter().map(|(uri, edits)| {
1766 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1767 text_document:
1768 lsp::OptionalVersionedTextDocumentIdentifier {
1769 uri,
1770 version: None,
1771 },
1772 edits: edits.into_iter().map(Edit::Plain).collect(),
1773 })
1774 }));
1775 }
1776
1777 let mut edits = Vec::with_capacity(operations.len());
1778
1779 if operations.is_empty() {
1780 zlog::trace!(
1781 logger =>
1782 "No changes for code action. Skipping {}",
1783 describe_code_action(&action),
1784 );
1785 continue;
1786 }
1787 for operation in operations {
1788 let op = match operation {
1789 lsp::DocumentChangeOperation::Edit(op) => op,
1790 lsp::DocumentChangeOperation::Op(_) => {
1791 zlog::warn!(
1792 logger =>
1793 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1794 describe_code_action(&action),
1795 );
1796 continue 'actions;
1797 }
1798 };
1799 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1800 zlog::warn!(
1801 logger =>
1802 "Failed to convert URI '{:?}' to file path. Skipping {}",
1803 &op.text_document.uri,
1804 describe_code_action(&action),
1805 );
1806 continue 'actions;
1807 };
1808 if &file_path != buffer_path_abs {
1809 zlog::warn!(
1810 logger =>
1811 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1812 file_path,
1813 buffer_path_abs,
1814 describe_code_action(&action),
1815 );
1816 continue 'actions;
1817 }
1818
1819 let mut lsp_edits = Vec::new();
1820 for edit in op.edits {
1821 match edit {
1822 Edit::Plain(edit) => {
1823 if !lsp_edits.contains(&edit) {
1824 lsp_edits.push(edit);
1825 }
1826 }
1827 Edit::Annotated(edit) => {
1828 if !lsp_edits.contains(&edit.text_edit) {
1829 lsp_edits.push(edit.text_edit);
1830 }
1831 }
1832 Edit::Snippet(_) => {
1833 zlog::warn!(
1834 logger =>
1835 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1836 describe_code_action(&action),
1837 );
1838 continue 'actions;
1839 }
1840 }
1841 }
1842 let edits_result = lsp_store
1843 .update(cx, |lsp_store, cx| {
1844 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1845 &buffer.handle,
1846 lsp_edits,
1847 server.server_id(),
1848 op.text_document.version,
1849 cx,
1850 )
1851 })?
1852 .await;
1853 let Ok(resolved_edits) = edits_result else {
1854 zlog::warn!(
1855 logger =>
1856 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1857 buffer_path_abs.as_path(),
1858 describe_code_action(&action),
1859 );
1860 continue 'actions;
1861 };
1862 edits.extend(resolved_edits);
1863 }
1864
1865 if edits.is_empty() {
1866 zlog::warn!(logger => "No edits resolved from LSP");
1867 continue;
1868 }
1869
1870 extend_formatting_transaction(
1871 buffer,
1872 formatting_transaction_id,
1873 cx,
1874 |buffer, cx| {
1875 zlog::info!(
1876 "Applying edits {edits:?}. Content: {:?}",
1877 buffer.text()
1878 );
1879 buffer.edit(edits, None, cx);
1880 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1881 },
1882 )?;
1883 }
1884
1885 if let Some(command) = action.lsp_action.command() {
1886 zlog::warn!(
1887 logger =>
1888 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1889 &command.command,
1890 );
1891
1892 // bail early if command is invalid
1893 let server_capabilities = server.capabilities();
1894 let available_commands = server_capabilities
1895 .execute_command_provider
1896 .as_ref()
1897 .map(|options| options.commands.as_slice())
1898 .unwrap_or_default();
1899 if !available_commands.contains(&command.command) {
1900 zlog::warn!(
1901 logger =>
1902 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1903 command.command,
1904 server.name(),
1905 );
1906 continue;
1907 }
1908
1909 // noop so we just ensure buffer hasn't been edited since resolving code actions
1910 extend_formatting_transaction(
1911 buffer,
1912 formatting_transaction_id,
1913 cx,
1914 |_, _| {},
1915 )?;
1916 zlog::info!(logger => "Executing command {}", &command.command);
1917
1918 lsp_store.update(cx, |this, _| {
1919 this.as_local_mut()
1920 .unwrap()
1921 .last_workspace_edits_by_language_server
1922 .remove(&server.server_id());
1923 })?;
1924
1925 let execute_command_result = server
1926 .request::<lsp::request::ExecuteCommand>(
1927 lsp::ExecuteCommandParams {
1928 command: command.command.clone(),
1929 arguments: command.arguments.clone().unwrap_or_default(),
1930 ..Default::default()
1931 },
1932 )
1933 .await
1934 .into_response();
1935
1936 if execute_command_result.is_err() {
1937 zlog::error!(
1938 logger =>
1939 "Failed to execute command '{}' as part of {}",
1940 &command.command,
1941 describe_code_action(&action),
1942 );
1943 continue 'actions;
1944 }
1945
1946 let mut project_transaction_command =
1947 lsp_store.update(cx, |this, _| {
1948 this.as_local_mut()
1949 .unwrap()
1950 .last_workspace_edits_by_language_server
1951 .remove(&server.server_id())
1952 .unwrap_or_default()
1953 })?;
1954
1955 if let Some(transaction) =
1956 project_transaction_command.0.remove(&buffer.handle)
1957 {
1958 zlog::trace!(
1959 logger =>
1960 "Successfully captured {} edits that resulted from command {}",
1961 transaction.edit_ids.len(),
1962 &command.command,
1963 );
1964 let transaction_id_project_transaction = transaction.id;
1965 buffer.handle.update(cx, |buffer, _| {
1966 // it may have been removed from history if push_to_history was
1967 // false in deserialize_workspace_edit. If so push it so we
1968 // can merge it with the format transaction
1969 // and pop the combined transaction off the history stack
1970 // later if push_to_history is false
1971 if buffer.get_transaction(transaction.id).is_none() {
1972 buffer.push_transaction(transaction, Instant::now());
1973 }
1974 buffer.merge_transactions(
1975 transaction_id_project_transaction,
1976 formatting_transaction_id,
1977 );
1978 })?;
1979 }
1980
1981 if !project_transaction_command.0.is_empty() {
1982 let mut extra_buffers = String::new();
1983 for buffer in project_transaction_command.0.keys() {
1984 buffer
1985 .read_with(cx, |b, cx| {
1986 if let Some(path) = b.project_path(cx) {
1987 if !extra_buffers.is_empty() {
1988 extra_buffers.push_str(", ");
1989 }
1990 extra_buffers.push_str(path.path.as_unix_str());
1991 }
1992 })
1993 .ok();
1994 }
1995 zlog::warn!(
1996 logger =>
1997 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1998 &command.command,
1999 extra_buffers,
2000 );
2001 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2002 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2003 // add it so it's included, and merge it into the format transaction when its created later
2004 }
2005 }
2006 }
2007 }
2008 }
2009 }
2010
2011 Ok(())
2012 }
2013
2014 pub async fn format_ranges_via_lsp(
2015 this: &WeakEntity<LspStore>,
2016 buffer_handle: &Entity<Buffer>,
2017 ranges: &[Range<Anchor>],
2018 abs_path: &Path,
2019 language_server: &Arc<LanguageServer>,
2020 settings: &LanguageSettings,
2021 cx: &mut AsyncApp,
2022 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2023 let capabilities = &language_server.capabilities();
2024 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2025 if range_formatting_provider == Some(&OneOf::Left(false)) {
2026 anyhow::bail!(
2027 "{} language server does not support range formatting",
2028 language_server.name()
2029 );
2030 }
2031
2032 let uri = file_path_to_lsp_url(abs_path)?;
2033 let text_document = lsp::TextDocumentIdentifier::new(uri);
2034
2035 let lsp_edits = {
2036 let mut lsp_ranges = Vec::new();
2037 this.update(cx, |_this, cx| {
2038 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2039 // not have been sent to the language server. This seems like a fairly systemic
2040 // issue, though, the resolution probably is not specific to formatting.
2041 //
2042 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2043 // LSP.
2044 let snapshot = buffer_handle.read(cx).snapshot();
2045 for range in ranges {
2046 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2047 }
2048 anyhow::Ok(())
2049 })??;
2050
2051 let mut edits = None;
2052 for range in lsp_ranges {
2053 if let Some(mut edit) = language_server
2054 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2055 text_document: text_document.clone(),
2056 range,
2057 options: lsp_command::lsp_formatting_options(settings),
2058 work_done_progress_params: Default::default(),
2059 })
2060 .await
2061 .into_response()?
2062 {
2063 edits.get_or_insert_with(Vec::new).append(&mut edit);
2064 }
2065 }
2066 edits
2067 };
2068
2069 if let Some(lsp_edits) = lsp_edits {
2070 this.update(cx, |this, cx| {
2071 this.as_local_mut().unwrap().edits_from_lsp(
2072 buffer_handle,
2073 lsp_edits,
2074 language_server.server_id(),
2075 None,
2076 cx,
2077 )
2078 })?
2079 .await
2080 } else {
2081 Ok(Vec::with_capacity(0))
2082 }
2083 }
2084
2085 async fn format_via_lsp(
2086 this: &WeakEntity<LspStore>,
2087 buffer: &Entity<Buffer>,
2088 abs_path: &Path,
2089 language_server: &Arc<LanguageServer>,
2090 settings: &LanguageSettings,
2091 cx: &mut AsyncApp,
2092 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2093 let logger = zlog::scoped!("lsp_format");
2094 zlog::debug!(logger => "Formatting via LSP");
2095
2096 let uri = file_path_to_lsp_url(abs_path)?;
2097 let text_document = lsp::TextDocumentIdentifier::new(uri);
2098 let capabilities = &language_server.capabilities();
2099
2100 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2101 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2102
2103 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2104 let _timer = zlog::time!(logger => "format-full");
2105 language_server
2106 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2107 text_document,
2108 options: lsp_command::lsp_formatting_options(settings),
2109 work_done_progress_params: Default::default(),
2110 })
2111 .await
2112 .into_response()?
2113 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2114 let _timer = zlog::time!(logger => "format-range");
2115 let buffer_start = lsp::Position::new(0, 0);
2116 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2117 language_server
2118 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2119 text_document: text_document.clone(),
2120 range: lsp::Range::new(buffer_start, buffer_end),
2121 options: lsp_command::lsp_formatting_options(settings),
2122 work_done_progress_params: Default::default(),
2123 })
2124 .await
2125 .into_response()?
2126 } else {
2127 None
2128 };
2129
2130 if let Some(lsp_edits) = lsp_edits {
2131 this.update(cx, |this, cx| {
2132 this.as_local_mut().unwrap().edits_from_lsp(
2133 buffer,
2134 lsp_edits,
2135 language_server.server_id(),
2136 None,
2137 cx,
2138 )
2139 })?
2140 .await
2141 } else {
2142 Ok(Vec::with_capacity(0))
2143 }
2144 }
2145
2146 async fn format_via_external_command(
2147 buffer: &FormattableBuffer,
2148 command: &str,
2149 arguments: Option<&[String]>,
2150 cx: &mut AsyncApp,
2151 ) -> Result<Option<Diff>> {
2152 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2153 let file = File::from_dyn(buffer.file())?;
2154 let worktree = file.worktree.read(cx);
2155 let mut worktree_path = worktree.abs_path().to_path_buf();
2156 if worktree.root_entry()?.is_file() {
2157 worktree_path.pop();
2158 }
2159 Some(worktree_path)
2160 })?;
2161
2162 let mut child = util::command::new_smol_command(command);
2163
2164 if let Some(buffer_env) = buffer.env.as_ref() {
2165 child.envs(buffer_env);
2166 }
2167
2168 if let Some(working_dir_path) = working_dir_path {
2169 child.current_dir(working_dir_path);
2170 }
2171
2172 if let Some(arguments) = arguments {
2173 child.args(arguments.iter().map(|arg| {
2174 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2175 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2176 } else {
2177 arg.replace("{buffer_path}", "Untitled")
2178 }
2179 }));
2180 }
2181
2182 let mut child = child
2183 .stdin(smol::process::Stdio::piped())
2184 .stdout(smol::process::Stdio::piped())
2185 .stderr(smol::process::Stdio::piped())
2186 .spawn()?;
2187
2188 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2189 let text = buffer
2190 .handle
2191 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2192 for chunk in text.chunks() {
2193 stdin.write_all(chunk.as_bytes()).await?;
2194 }
2195 stdin.flush().await?;
2196
2197 let output = child.output().await?;
2198 anyhow::ensure!(
2199 output.status.success(),
2200 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2201 output.status.code(),
2202 String::from_utf8_lossy(&output.stdout),
2203 String::from_utf8_lossy(&output.stderr),
2204 );
2205
2206 let stdout = String::from_utf8(output.stdout)?;
2207 Ok(Some(
2208 buffer
2209 .handle
2210 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2211 .await,
2212 ))
2213 }
2214
2215 async fn try_resolve_code_action(
2216 lang_server: &LanguageServer,
2217 action: &mut CodeAction,
2218 ) -> anyhow::Result<()> {
2219 match &mut action.lsp_action {
2220 LspAction::Action(lsp_action) => {
2221 if !action.resolved
2222 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2223 && lsp_action.data.is_some()
2224 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2225 {
2226 *lsp_action = Box::new(
2227 lang_server
2228 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2229 .await
2230 .into_response()?,
2231 );
2232 }
2233 }
2234 LspAction::CodeLens(lens) => {
2235 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2236 *lens = lang_server
2237 .request::<lsp::request::CodeLensResolve>(lens.clone())
2238 .await
2239 .into_response()?;
2240 }
2241 }
2242 LspAction::Command(_) => {}
2243 }
2244
2245 action.resolved = true;
2246 anyhow::Ok(())
2247 }
2248
2249 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2250 let buffer = buffer_handle.read(cx);
2251
2252 let file = buffer.file().cloned();
2253
2254 let Some(file) = File::from_dyn(file.as_ref()) else {
2255 return;
2256 };
2257 if !file.is_local() {
2258 return;
2259 }
2260 let path = ProjectPath::from_file(file, cx);
2261 let worktree_id = file.worktree_id(cx);
2262 let language = buffer.language().cloned();
2263
2264 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2265 for (server_id, diagnostics) in
2266 diagnostics.get(file.path()).cloned().unwrap_or_default()
2267 {
2268 self.update_buffer_diagnostics(
2269 buffer_handle,
2270 server_id,
2271 None,
2272 None,
2273 None,
2274 Vec::new(),
2275 diagnostics,
2276 cx,
2277 )
2278 .log_err();
2279 }
2280 }
2281 let Some(language) = language else {
2282 return;
2283 };
2284 let Some(snapshot) = self
2285 .worktree_store
2286 .read(cx)
2287 .worktree_for_id(worktree_id, cx)
2288 .map(|worktree| worktree.read(cx).snapshot())
2289 else {
2290 return;
2291 };
2292 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2293
2294 for server_id in
2295 self.lsp_tree
2296 .get(path, language.name(), language.manifest(), &delegate, cx)
2297 {
2298 let server = self
2299 .language_servers
2300 .get(&server_id)
2301 .and_then(|server_state| {
2302 if let LanguageServerState::Running { server, .. } = server_state {
2303 Some(server.clone())
2304 } else {
2305 None
2306 }
2307 });
2308 let server = match server {
2309 Some(server) => server,
2310 None => continue,
2311 };
2312
2313 buffer_handle.update(cx, |buffer, cx| {
2314 buffer.set_completion_triggers(
2315 server.server_id(),
2316 server
2317 .capabilities()
2318 .completion_provider
2319 .as_ref()
2320 .and_then(|provider| {
2321 provider
2322 .trigger_characters
2323 .as_ref()
2324 .map(|characters| characters.iter().cloned().collect())
2325 })
2326 .unwrap_or_default(),
2327 cx,
2328 );
2329 });
2330 }
2331 }
2332
2333 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2334 buffer.update(cx, |buffer, cx| {
2335 let Some(language) = buffer.language() else {
2336 return;
2337 };
2338 let path = ProjectPath {
2339 worktree_id: old_file.worktree_id(cx),
2340 path: old_file.path.clone(),
2341 };
2342 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2343 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2344 buffer.set_completion_triggers(server_id, Default::default(), cx);
2345 }
2346 });
2347 }
2348
2349 fn update_buffer_diagnostics(
2350 &mut self,
2351 buffer: &Entity<Buffer>,
2352 server_id: LanguageServerId,
2353 registration_id: Option<Option<SharedString>>,
2354 result_id: Option<SharedString>,
2355 version: Option<i32>,
2356 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2357 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2358 cx: &mut Context<LspStore>,
2359 ) -> Result<()> {
2360 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2361 Ordering::Equal
2362 .then_with(|| b.is_primary.cmp(&a.is_primary))
2363 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2364 .then_with(|| a.severity.cmp(&b.severity))
2365 .then_with(|| a.message.cmp(&b.message))
2366 }
2367
2368 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2369 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2370 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2371
2372 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2373 Ordering::Equal
2374 .then_with(|| a.range.start.cmp(&b.range.start))
2375 .then_with(|| b.range.end.cmp(&a.range.end))
2376 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2377 });
2378
2379 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2380
2381 let edits_since_save = std::cell::LazyCell::new(|| {
2382 let saved_version = buffer.read(cx).saved_version();
2383 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2384 });
2385
2386 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2387
2388 for (new_diagnostic, entry) in diagnostics {
2389 let start;
2390 let end;
2391 if new_diagnostic && entry.diagnostic.is_disk_based {
2392 // Some diagnostics are based on files on disk instead of buffers'
2393 // current contents. Adjust these diagnostics' ranges to reflect
2394 // any unsaved edits.
2395 // Do not alter the reused ones though, as their coordinates were stored as anchors
2396 // and were properly adjusted on reuse.
2397 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2398 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2399 } else {
2400 start = entry.range.start;
2401 end = entry.range.end;
2402 }
2403
2404 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2405 ..snapshot.clip_point_utf16(end, Bias::Right);
2406
2407 // Expand empty ranges by one codepoint
2408 if range.start == range.end {
2409 // This will be go to the next boundary when being clipped
2410 range.end.column += 1;
2411 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2412 if range.start == range.end && range.end.column > 0 {
2413 range.start.column -= 1;
2414 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2415 }
2416 }
2417
2418 sanitized_diagnostics.push(DiagnosticEntry {
2419 range,
2420 diagnostic: entry.diagnostic,
2421 });
2422 }
2423 drop(edits_since_save);
2424
2425 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2426 buffer.update(cx, |buffer, cx| {
2427 if let Some(registration_id) = registration_id {
2428 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2429 self.buffer_pull_diagnostics_result_ids
2430 .entry(server_id)
2431 .or_default()
2432 .entry(registration_id)
2433 .or_default()
2434 .insert(abs_path, result_id);
2435 }
2436 }
2437
2438 buffer.update_diagnostics(server_id, set, cx)
2439 });
2440
2441 Ok(())
2442 }
2443
2444 fn register_language_server_for_invisible_worktree(
2445 &mut self,
2446 worktree: &Entity<Worktree>,
2447 language_server_id: LanguageServerId,
2448 cx: &mut App,
2449 ) {
2450 let worktree = worktree.read(cx);
2451 let worktree_id = worktree.id();
2452 debug_assert!(!worktree.is_visible());
2453 let Some(mut origin_seed) = self
2454 .language_server_ids
2455 .iter()
2456 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2457 else {
2458 return;
2459 };
2460 origin_seed.worktree_id = worktree_id;
2461 self.language_server_ids
2462 .entry(origin_seed)
2463 .or_insert_with(|| UnifiedLanguageServer {
2464 id: language_server_id,
2465 project_roots: Default::default(),
2466 });
2467 }
2468
2469 fn register_buffer_with_language_servers(
2470 &mut self,
2471 buffer_handle: &Entity<Buffer>,
2472 only_register_servers: HashSet<LanguageServerSelector>,
2473 cx: &mut Context<LspStore>,
2474 ) {
2475 let buffer = buffer_handle.read(cx);
2476 let buffer_id = buffer.remote_id();
2477
2478 let Some(file) = File::from_dyn(buffer.file()) else {
2479 return;
2480 };
2481 if !file.is_local() {
2482 return;
2483 }
2484
2485 let abs_path = file.abs_path(cx);
2486 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2487 return;
2488 };
2489 let initial_snapshot = buffer.text_snapshot();
2490 let worktree_id = file.worktree_id(cx);
2491
2492 let Some(language) = buffer.language().cloned() else {
2493 return;
2494 };
2495 let path: Arc<RelPath> = file
2496 .path()
2497 .parent()
2498 .map(Arc::from)
2499 .unwrap_or_else(|| file.path().clone());
2500 let Some(worktree) = self
2501 .worktree_store
2502 .read(cx)
2503 .worktree_for_id(worktree_id, cx)
2504 else {
2505 return;
2506 };
2507 let language_name = language.name();
2508 let (reused, delegate, servers) = self
2509 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2510 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2511 .unwrap_or_else(|| {
2512 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2513 let delegate: Arc<dyn ManifestDelegate> =
2514 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2515
2516 let servers = self
2517 .lsp_tree
2518 .walk(
2519 ProjectPath { worktree_id, path },
2520 language.name(),
2521 language.manifest(),
2522 &delegate,
2523 cx,
2524 )
2525 .collect::<Vec<_>>();
2526 (false, lsp_delegate, servers)
2527 });
2528 let servers_and_adapters = servers
2529 .into_iter()
2530 .filter_map(|server_node| {
2531 if reused && server_node.server_id().is_none() {
2532 return None;
2533 }
2534 if !only_register_servers.is_empty() {
2535 if let Some(server_id) = server_node.server_id()
2536 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2537 {
2538 return None;
2539 }
2540 if let Some(name) = server_node.name()
2541 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2542 {
2543 return None;
2544 }
2545 }
2546
2547 let server_id = server_node.server_id_or_init(|disposition| {
2548 let path = &disposition.path;
2549
2550 {
2551 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2552
2553 let server_id = self.get_or_insert_language_server(
2554 &worktree,
2555 delegate.clone(),
2556 disposition,
2557 &language_name,
2558 cx,
2559 );
2560
2561 if let Some(state) = self.language_servers.get(&server_id)
2562 && let Ok(uri) = uri
2563 {
2564 state.add_workspace_folder(uri);
2565 };
2566 server_id
2567 }
2568 })?;
2569 let server_state = self.language_servers.get(&server_id)?;
2570 if let LanguageServerState::Running {
2571 server, adapter, ..
2572 } = server_state
2573 {
2574 Some((server.clone(), adapter.clone()))
2575 } else {
2576 None
2577 }
2578 })
2579 .collect::<Vec<_>>();
2580 for (server, adapter) in servers_and_adapters {
2581 buffer_handle.update(cx, |buffer, cx| {
2582 buffer.set_completion_triggers(
2583 server.server_id(),
2584 server
2585 .capabilities()
2586 .completion_provider
2587 .as_ref()
2588 .and_then(|provider| {
2589 provider
2590 .trigger_characters
2591 .as_ref()
2592 .map(|characters| characters.iter().cloned().collect())
2593 })
2594 .unwrap_or_default(),
2595 cx,
2596 );
2597 });
2598
2599 let snapshot = LspBufferSnapshot {
2600 version: 0,
2601 snapshot: initial_snapshot.clone(),
2602 };
2603
2604 let mut registered = false;
2605 self.buffer_snapshots
2606 .entry(buffer_id)
2607 .or_default()
2608 .entry(server.server_id())
2609 .or_insert_with(|| {
2610 registered = true;
2611 server.register_buffer(
2612 uri.clone(),
2613 adapter.language_id(&language.name()),
2614 0,
2615 initial_snapshot.text(),
2616 );
2617
2618 vec![snapshot]
2619 });
2620
2621 self.buffers_opened_in_servers
2622 .entry(buffer_id)
2623 .or_default()
2624 .insert(server.server_id());
2625 if registered {
2626 cx.emit(LspStoreEvent::LanguageServerUpdate {
2627 language_server_id: server.server_id(),
2628 name: None,
2629 message: proto::update_language_server::Variant::RegisteredForBuffer(
2630 proto::RegisteredForBuffer {
2631 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2632 buffer_id: buffer_id.to_proto(),
2633 },
2634 ),
2635 });
2636 }
2637 }
2638 }
2639
2640 fn reuse_existing_language_server<'lang_name>(
2641 &self,
2642 server_tree: &LanguageServerTree,
2643 worktree: &Entity<Worktree>,
2644 language_name: &'lang_name LanguageName,
2645 cx: &mut App,
2646 ) -> Option<(
2647 Arc<LocalLspAdapterDelegate>,
2648 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2649 )> {
2650 if worktree.read(cx).is_visible() {
2651 return None;
2652 }
2653
2654 let worktree_store = self.worktree_store.read(cx);
2655 let servers = server_tree
2656 .instances
2657 .iter()
2658 .filter(|(worktree_id, _)| {
2659 worktree_store
2660 .worktree_for_id(**worktree_id, cx)
2661 .is_some_and(|worktree| worktree.read(cx).is_visible())
2662 })
2663 .flat_map(|(worktree_id, servers)| {
2664 servers
2665 .roots
2666 .iter()
2667 .flat_map(|(_, language_servers)| language_servers)
2668 .map(move |(_, (server_node, server_languages))| {
2669 (worktree_id, server_node, server_languages)
2670 })
2671 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2672 .map(|(worktree_id, server_node, _)| {
2673 (
2674 *worktree_id,
2675 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2676 )
2677 })
2678 })
2679 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2680 acc.entry(worktree_id)
2681 .or_insert_with(Vec::new)
2682 .push(server_node);
2683 acc
2684 })
2685 .into_values()
2686 .max_by_key(|servers| servers.len())?;
2687
2688 let worktree_id = worktree.read(cx).id();
2689 let apply = move |tree: &mut LanguageServerTree| {
2690 for server_node in &servers {
2691 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2692 }
2693 servers
2694 };
2695
2696 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2697 Some((delegate, apply))
2698 }
2699
2700 pub(crate) fn unregister_old_buffer_from_language_servers(
2701 &mut self,
2702 buffer: &Entity<Buffer>,
2703 old_file: &File,
2704 cx: &mut App,
2705 ) {
2706 let old_path = match old_file.as_local() {
2707 Some(local) => local.abs_path(cx),
2708 None => return,
2709 };
2710
2711 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2712 debug_panic!("{old_path:?} is not parseable as an URI");
2713 return;
2714 };
2715 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2716 }
2717
2718 pub(crate) fn unregister_buffer_from_language_servers(
2719 &mut self,
2720 buffer: &Entity<Buffer>,
2721 file_url: &lsp::Uri,
2722 cx: &mut App,
2723 ) {
2724 buffer.update(cx, |buffer, cx| {
2725 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2726
2727 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2728 if snapshots
2729 .as_mut()
2730 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2731 {
2732 language_server.unregister_buffer(file_url.clone());
2733 }
2734 }
2735 });
2736 }
2737
2738 fn buffer_snapshot_for_lsp_version(
2739 &mut self,
2740 buffer: &Entity<Buffer>,
2741 server_id: LanguageServerId,
2742 version: Option<i32>,
2743 cx: &App,
2744 ) -> Result<TextBufferSnapshot> {
2745 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2746
2747 if let Some(version) = version {
2748 let buffer_id = buffer.read(cx).remote_id();
2749 let snapshots = if let Some(snapshots) = self
2750 .buffer_snapshots
2751 .get_mut(&buffer_id)
2752 .and_then(|m| m.get_mut(&server_id))
2753 {
2754 snapshots
2755 } else if version == 0 {
2756 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2757 // We detect this case and treat it as if the version was `None`.
2758 return Ok(buffer.read(cx).text_snapshot());
2759 } else {
2760 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2761 };
2762
2763 let found_snapshot = snapshots
2764 .binary_search_by_key(&version, |e| e.version)
2765 .map(|ix| snapshots[ix].snapshot.clone())
2766 .map_err(|_| {
2767 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2768 })?;
2769
2770 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2771 Ok(found_snapshot)
2772 } else {
2773 Ok((buffer.read(cx)).text_snapshot())
2774 }
2775 }
2776
2777 async fn get_server_code_actions_from_action_kinds(
2778 lsp_store: &WeakEntity<LspStore>,
2779 language_server_id: LanguageServerId,
2780 code_action_kinds: Vec<lsp::CodeActionKind>,
2781 buffer: &Entity<Buffer>,
2782 cx: &mut AsyncApp,
2783 ) -> Result<Vec<CodeAction>> {
2784 let actions = lsp_store
2785 .update(cx, move |this, cx| {
2786 let request = GetCodeActions {
2787 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2788 kinds: Some(code_action_kinds),
2789 };
2790 let server = LanguageServerToQuery::Other(language_server_id);
2791 this.request_lsp(buffer.clone(), server, request, cx)
2792 })?
2793 .await?;
2794 Ok(actions)
2795 }
2796
2797 pub async fn execute_code_actions_on_server(
2798 lsp_store: &WeakEntity<LspStore>,
2799 language_server: &Arc<LanguageServer>,
2800
2801 actions: Vec<CodeAction>,
2802 push_to_history: bool,
2803 project_transaction: &mut ProjectTransaction,
2804 cx: &mut AsyncApp,
2805 ) -> anyhow::Result<()> {
2806 for mut action in actions {
2807 Self::try_resolve_code_action(language_server, &mut action)
2808 .await
2809 .context("resolving a formatting code action")?;
2810
2811 if let Some(edit) = action.lsp_action.edit() {
2812 if edit.changes.is_none() && edit.document_changes.is_none() {
2813 continue;
2814 }
2815
2816 let new = Self::deserialize_workspace_edit(
2817 lsp_store.upgrade().context("project dropped")?,
2818 edit.clone(),
2819 push_to_history,
2820 language_server.clone(),
2821 cx,
2822 )
2823 .await?;
2824 project_transaction.0.extend(new.0);
2825 }
2826
2827 if let Some(command) = action.lsp_action.command() {
2828 let server_capabilities = language_server.capabilities();
2829 let available_commands = server_capabilities
2830 .execute_command_provider
2831 .as_ref()
2832 .map(|options| options.commands.as_slice())
2833 .unwrap_or_default();
2834 if available_commands.contains(&command.command) {
2835 lsp_store.update(cx, |lsp_store, _| {
2836 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2837 mode.last_workspace_edits_by_language_server
2838 .remove(&language_server.server_id());
2839 }
2840 })?;
2841
2842 language_server
2843 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2844 command: command.command.clone(),
2845 arguments: command.arguments.clone().unwrap_or_default(),
2846 ..Default::default()
2847 })
2848 .await
2849 .into_response()
2850 .context("execute command")?;
2851
2852 lsp_store.update(cx, |this, _| {
2853 if let LspStoreMode::Local(mode) = &mut this.mode {
2854 project_transaction.0.extend(
2855 mode.last_workspace_edits_by_language_server
2856 .remove(&language_server.server_id())
2857 .unwrap_or_default()
2858 .0,
2859 )
2860 }
2861 })?;
2862 } else {
2863 log::warn!(
2864 "Cannot execute a command {} not listed in the language server capabilities",
2865 command.command
2866 )
2867 }
2868 }
2869 }
2870 Ok(())
2871 }
2872
2873 pub async fn deserialize_text_edits(
2874 this: Entity<LspStore>,
2875 buffer_to_edit: Entity<Buffer>,
2876 edits: Vec<lsp::TextEdit>,
2877 push_to_history: bool,
2878 _: Arc<CachedLspAdapter>,
2879 language_server: Arc<LanguageServer>,
2880 cx: &mut AsyncApp,
2881 ) -> Result<Option<Transaction>> {
2882 let edits = this
2883 .update(cx, |this, cx| {
2884 this.as_local_mut().unwrap().edits_from_lsp(
2885 &buffer_to_edit,
2886 edits,
2887 language_server.server_id(),
2888 None,
2889 cx,
2890 )
2891 })?
2892 .await?;
2893
2894 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2895 buffer.finalize_last_transaction();
2896 buffer.start_transaction();
2897 for (range, text) in edits {
2898 buffer.edit([(range, text)], None, cx);
2899 }
2900
2901 if buffer.end_transaction(cx).is_some() {
2902 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2903 if !push_to_history {
2904 buffer.forget_transaction(transaction.id);
2905 }
2906 Some(transaction)
2907 } else {
2908 None
2909 }
2910 })?;
2911
2912 Ok(transaction)
2913 }
2914
2915 #[allow(clippy::type_complexity)]
2916 pub(crate) fn edits_from_lsp(
2917 &mut self,
2918 buffer: &Entity<Buffer>,
2919 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2920 server_id: LanguageServerId,
2921 version: Option<i32>,
2922 cx: &mut Context<LspStore>,
2923 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2924 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2925 cx.background_spawn(async move {
2926 let snapshot = snapshot?;
2927 let mut lsp_edits = lsp_edits
2928 .into_iter()
2929 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2930 .collect::<Vec<_>>();
2931
2932 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2933
2934 let mut lsp_edits = lsp_edits.into_iter().peekable();
2935 let mut edits = Vec::new();
2936 while let Some((range, mut new_text)) = lsp_edits.next() {
2937 // Clip invalid ranges provided by the language server.
2938 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2939 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2940
2941 // Combine any LSP edits that are adjacent.
2942 //
2943 // Also, combine LSP edits that are separated from each other by only
2944 // a newline. This is important because for some code actions,
2945 // Rust-analyzer rewrites the entire buffer via a series of edits that
2946 // are separated by unchanged newline characters.
2947 //
2948 // In order for the diffing logic below to work properly, any edits that
2949 // cancel each other out must be combined into one.
2950 while let Some((next_range, next_text)) = lsp_edits.peek() {
2951 if next_range.start.0 > range.end {
2952 if next_range.start.0.row > range.end.row + 1
2953 || next_range.start.0.column > 0
2954 || snapshot.clip_point_utf16(
2955 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2956 Bias::Left,
2957 ) > range.end
2958 {
2959 break;
2960 }
2961 new_text.push('\n');
2962 }
2963 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2964 new_text.push_str(next_text);
2965 lsp_edits.next();
2966 }
2967
2968 // For multiline edits, perform a diff of the old and new text so that
2969 // we can identify the changes more precisely, preserving the locations
2970 // of any anchors positioned in the unchanged regions.
2971 if range.end.row > range.start.row {
2972 let offset = range.start.to_offset(&snapshot);
2973 let old_text = snapshot.text_for_range(range).collect::<String>();
2974 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2975 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2976 (
2977 snapshot.anchor_after(offset + range.start)
2978 ..snapshot.anchor_before(offset + range.end),
2979 replacement,
2980 )
2981 }));
2982 } else if range.end == range.start {
2983 let anchor = snapshot.anchor_after(range.start);
2984 edits.push((anchor..anchor, new_text.into()));
2985 } else {
2986 let edit_start = snapshot.anchor_after(range.start);
2987 let edit_end = snapshot.anchor_before(range.end);
2988 edits.push((edit_start..edit_end, new_text.into()));
2989 }
2990 }
2991
2992 Ok(edits)
2993 })
2994 }
2995
2996 pub(crate) async fn deserialize_workspace_edit(
2997 this: Entity<LspStore>,
2998 edit: lsp::WorkspaceEdit,
2999 push_to_history: bool,
3000 language_server: Arc<LanguageServer>,
3001 cx: &mut AsyncApp,
3002 ) -> Result<ProjectTransaction> {
3003 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3004
3005 let mut operations = Vec::new();
3006 if let Some(document_changes) = edit.document_changes {
3007 match document_changes {
3008 lsp::DocumentChanges::Edits(edits) => {
3009 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3010 }
3011 lsp::DocumentChanges::Operations(ops) => operations = ops,
3012 }
3013 } else if let Some(changes) = edit.changes {
3014 operations.extend(changes.into_iter().map(|(uri, edits)| {
3015 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3016 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3017 uri,
3018 version: None,
3019 },
3020 edits: edits.into_iter().map(Edit::Plain).collect(),
3021 })
3022 }));
3023 }
3024
3025 let mut project_transaction = ProjectTransaction::default();
3026 for operation in operations {
3027 match operation {
3028 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3029 let abs_path = op
3030 .uri
3031 .to_file_path()
3032 .map_err(|()| anyhow!("can't convert URI to path"))?;
3033
3034 if let Some(parent_path) = abs_path.parent() {
3035 fs.create_dir(parent_path).await?;
3036 }
3037 if abs_path.ends_with("/") {
3038 fs.create_dir(&abs_path).await?;
3039 } else {
3040 fs.create_file(
3041 &abs_path,
3042 op.options
3043 .map(|options| fs::CreateOptions {
3044 overwrite: options.overwrite.unwrap_or(false),
3045 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3046 })
3047 .unwrap_or_default(),
3048 )
3049 .await?;
3050 }
3051 }
3052
3053 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3054 let source_abs_path = op
3055 .old_uri
3056 .to_file_path()
3057 .map_err(|()| anyhow!("can't convert URI to path"))?;
3058 let target_abs_path = op
3059 .new_uri
3060 .to_file_path()
3061 .map_err(|()| anyhow!("can't convert URI to path"))?;
3062
3063 let options = fs::RenameOptions {
3064 overwrite: op
3065 .options
3066 .as_ref()
3067 .and_then(|options| options.overwrite)
3068 .unwrap_or(false),
3069 ignore_if_exists: op
3070 .options
3071 .as_ref()
3072 .and_then(|options| options.ignore_if_exists)
3073 .unwrap_or(false),
3074 create_parents: true,
3075 };
3076
3077 fs.rename(&source_abs_path, &target_abs_path, options)
3078 .await?;
3079 }
3080
3081 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3082 let abs_path = op
3083 .uri
3084 .to_file_path()
3085 .map_err(|()| anyhow!("can't convert URI to path"))?;
3086 let options = op
3087 .options
3088 .map(|options| fs::RemoveOptions {
3089 recursive: options.recursive.unwrap_or(false),
3090 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3091 })
3092 .unwrap_or_default();
3093 if abs_path.ends_with("/") {
3094 fs.remove_dir(&abs_path, options).await?;
3095 } else {
3096 fs.remove_file(&abs_path, options).await?;
3097 }
3098 }
3099
3100 lsp::DocumentChangeOperation::Edit(op) => {
3101 let buffer_to_edit = this
3102 .update(cx, |this, cx| {
3103 this.open_local_buffer_via_lsp(
3104 op.text_document.uri.clone(),
3105 language_server.server_id(),
3106 cx,
3107 )
3108 })?
3109 .await?;
3110
3111 let edits = this
3112 .update(cx, |this, cx| {
3113 let path = buffer_to_edit.read(cx).project_path(cx);
3114 let active_entry = this.active_entry;
3115 let is_active_entry = path.is_some_and(|project_path| {
3116 this.worktree_store
3117 .read(cx)
3118 .entry_for_path(&project_path, cx)
3119 .is_some_and(|entry| Some(entry.id) == active_entry)
3120 });
3121 let local = this.as_local_mut().unwrap();
3122
3123 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3124 for edit in op.edits {
3125 match edit {
3126 Edit::Plain(edit) => {
3127 if !edits.contains(&edit) {
3128 edits.push(edit)
3129 }
3130 }
3131 Edit::Annotated(edit) => {
3132 if !edits.contains(&edit.text_edit) {
3133 edits.push(edit.text_edit)
3134 }
3135 }
3136 Edit::Snippet(edit) => {
3137 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3138 else {
3139 continue;
3140 };
3141
3142 if is_active_entry {
3143 snippet_edits.push((edit.range, snippet));
3144 } else {
3145 // Since this buffer is not focused, apply a normal edit.
3146 let new_edit = TextEdit {
3147 range: edit.range,
3148 new_text: snippet.text,
3149 };
3150 if !edits.contains(&new_edit) {
3151 edits.push(new_edit);
3152 }
3153 }
3154 }
3155 }
3156 }
3157 if !snippet_edits.is_empty() {
3158 let buffer_id = buffer_to_edit.read(cx).remote_id();
3159 let version = if let Some(buffer_version) = op.text_document.version
3160 {
3161 local
3162 .buffer_snapshot_for_lsp_version(
3163 &buffer_to_edit,
3164 language_server.server_id(),
3165 Some(buffer_version),
3166 cx,
3167 )
3168 .ok()
3169 .map(|snapshot| snapshot.version)
3170 } else {
3171 Some(buffer_to_edit.read(cx).saved_version().clone())
3172 };
3173
3174 let most_recent_edit =
3175 version.and_then(|version| version.most_recent());
3176 // Check if the edit that triggered that edit has been made by this participant.
3177
3178 if let Some(most_recent_edit) = most_recent_edit {
3179 cx.emit(LspStoreEvent::SnippetEdit {
3180 buffer_id,
3181 edits: snippet_edits,
3182 most_recent_edit,
3183 });
3184 }
3185 }
3186
3187 local.edits_from_lsp(
3188 &buffer_to_edit,
3189 edits,
3190 language_server.server_id(),
3191 op.text_document.version,
3192 cx,
3193 )
3194 })?
3195 .await?;
3196
3197 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3198 buffer.finalize_last_transaction();
3199 buffer.start_transaction();
3200 for (range, text) in edits {
3201 buffer.edit([(range, text)], None, cx);
3202 }
3203
3204 buffer.end_transaction(cx).and_then(|transaction_id| {
3205 if push_to_history {
3206 buffer.finalize_last_transaction();
3207 buffer.get_transaction(transaction_id).cloned()
3208 } else {
3209 buffer.forget_transaction(transaction_id)
3210 }
3211 })
3212 })?;
3213 if let Some(transaction) = transaction {
3214 project_transaction.0.insert(buffer_to_edit, transaction);
3215 }
3216 }
3217 }
3218 }
3219
3220 Ok(project_transaction)
3221 }
3222
3223 async fn on_lsp_workspace_edit(
3224 this: WeakEntity<LspStore>,
3225 params: lsp::ApplyWorkspaceEditParams,
3226 server_id: LanguageServerId,
3227 cx: &mut AsyncApp,
3228 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3229 let this = this.upgrade().context("project project closed")?;
3230 let language_server = this
3231 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3232 .context("language server not found")?;
3233 let transaction = Self::deserialize_workspace_edit(
3234 this.clone(),
3235 params.edit,
3236 true,
3237 language_server.clone(),
3238 cx,
3239 )
3240 .await
3241 .log_err();
3242 this.update(cx, |this, _| {
3243 if let Some(transaction) = transaction {
3244 this.as_local_mut()
3245 .unwrap()
3246 .last_workspace_edits_by_language_server
3247 .insert(server_id, transaction);
3248 }
3249 })?;
3250 Ok(lsp::ApplyWorkspaceEditResponse {
3251 applied: true,
3252 failed_change: None,
3253 failure_reason: None,
3254 })
3255 }
3256
3257 fn remove_worktree(
3258 &mut self,
3259 id_to_remove: WorktreeId,
3260 cx: &mut Context<LspStore>,
3261 ) -> Vec<LanguageServerId> {
3262 self.diagnostics.remove(&id_to_remove);
3263 self.prettier_store.update(cx, |prettier_store, cx| {
3264 prettier_store.remove_worktree(id_to_remove, cx);
3265 });
3266
3267 let mut servers_to_remove = BTreeSet::default();
3268 let mut servers_to_preserve = HashSet::default();
3269 for (seed, state) in &self.language_server_ids {
3270 if seed.worktree_id == id_to_remove {
3271 servers_to_remove.insert(state.id);
3272 } else {
3273 servers_to_preserve.insert(state.id);
3274 }
3275 }
3276 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3277 self.language_server_ids
3278 .retain(|_, state| !servers_to_remove.contains(&state.id));
3279 for server_id_to_remove in &servers_to_remove {
3280 self.language_server_watched_paths
3281 .remove(server_id_to_remove);
3282 self.language_server_paths_watched_for_rename
3283 .remove(server_id_to_remove);
3284 self.last_workspace_edits_by_language_server
3285 .remove(server_id_to_remove);
3286 self.language_servers.remove(server_id_to_remove);
3287 self.buffer_pull_diagnostics_result_ids
3288 .remove(server_id_to_remove);
3289 self.workspace_pull_diagnostics_result_ids
3290 .remove(server_id_to_remove);
3291 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3292 buffer_servers.remove(server_id_to_remove);
3293 }
3294 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3295 }
3296 servers_to_remove.into_iter().collect()
3297 }
3298
3299 fn rebuild_watched_paths_inner<'a>(
3300 &'a self,
3301 language_server_id: LanguageServerId,
3302 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3303 cx: &mut Context<LspStore>,
3304 ) -> LanguageServerWatchedPathsBuilder {
3305 let worktrees = self
3306 .worktree_store
3307 .read(cx)
3308 .worktrees()
3309 .filter_map(|worktree| {
3310 self.language_servers_for_worktree(worktree.read(cx).id())
3311 .find(|server| server.server_id() == language_server_id)
3312 .map(|_| worktree)
3313 })
3314 .collect::<Vec<_>>();
3315
3316 let mut worktree_globs = HashMap::default();
3317 let mut abs_globs = HashMap::default();
3318 log::trace!(
3319 "Processing new watcher paths for language server with id {}",
3320 language_server_id
3321 );
3322
3323 for watcher in watchers {
3324 if let Some((worktree, literal_prefix, pattern)) =
3325 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3326 {
3327 worktree.update(cx, |worktree, _| {
3328 if let Some((tree, glob)) =
3329 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3330 {
3331 tree.add_path_prefix_to_scan(literal_prefix);
3332 worktree_globs
3333 .entry(tree.id())
3334 .or_insert_with(GlobSetBuilder::new)
3335 .add(glob);
3336 }
3337 });
3338 } else {
3339 let (path, pattern) = match &watcher.glob_pattern {
3340 lsp::GlobPattern::String(s) => {
3341 let watcher_path = SanitizedPath::new(s);
3342 let path = glob_literal_prefix(watcher_path.as_path());
3343 let pattern = watcher_path
3344 .as_path()
3345 .strip_prefix(&path)
3346 .map(|p| p.to_string_lossy().into_owned())
3347 .unwrap_or_else(|e| {
3348 debug_panic!(
3349 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3350 s,
3351 path.display(),
3352 e
3353 );
3354 watcher_path.as_path().to_string_lossy().into_owned()
3355 });
3356 (path, pattern)
3357 }
3358 lsp::GlobPattern::Relative(rp) => {
3359 let Ok(mut base_uri) = match &rp.base_uri {
3360 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3361 lsp::OneOf::Right(base_uri) => base_uri,
3362 }
3363 .to_file_path() else {
3364 continue;
3365 };
3366
3367 let path = glob_literal_prefix(Path::new(&rp.pattern));
3368 let pattern = Path::new(&rp.pattern)
3369 .strip_prefix(&path)
3370 .map(|p| p.to_string_lossy().into_owned())
3371 .unwrap_or_else(|e| {
3372 debug_panic!(
3373 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3374 rp.pattern,
3375 path.display(),
3376 e
3377 );
3378 rp.pattern.clone()
3379 });
3380 base_uri.push(path);
3381 (base_uri, pattern)
3382 }
3383 };
3384
3385 if let Some(glob) = Glob::new(&pattern).log_err() {
3386 if !path
3387 .components()
3388 .any(|c| matches!(c, path::Component::Normal(_)))
3389 {
3390 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3391 // rather than adding a new watcher for `/`.
3392 for worktree in &worktrees {
3393 worktree_globs
3394 .entry(worktree.read(cx).id())
3395 .or_insert_with(GlobSetBuilder::new)
3396 .add(glob.clone());
3397 }
3398 } else {
3399 abs_globs
3400 .entry(path.into())
3401 .or_insert_with(GlobSetBuilder::new)
3402 .add(glob);
3403 }
3404 }
3405 }
3406 }
3407
3408 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3409 for (worktree_id, builder) in worktree_globs {
3410 if let Ok(globset) = builder.build() {
3411 watch_builder.watch_worktree(worktree_id, globset);
3412 }
3413 }
3414 for (abs_path, builder) in abs_globs {
3415 if let Ok(globset) = builder.build() {
3416 watch_builder.watch_abs_path(abs_path, globset);
3417 }
3418 }
3419 watch_builder
3420 }
3421
3422 fn worktree_and_path_for_file_watcher(
3423 worktrees: &[Entity<Worktree>],
3424 watcher: &FileSystemWatcher,
3425 cx: &App,
3426 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3427 worktrees.iter().find_map(|worktree| {
3428 let tree = worktree.read(cx);
3429 let worktree_root_path = tree.abs_path();
3430 let path_style = tree.path_style();
3431 match &watcher.glob_pattern {
3432 lsp::GlobPattern::String(s) => {
3433 let watcher_path = SanitizedPath::new(s);
3434 let relative = watcher_path
3435 .as_path()
3436 .strip_prefix(&worktree_root_path)
3437 .ok()?;
3438 let literal_prefix = glob_literal_prefix(relative);
3439 Some((
3440 worktree.clone(),
3441 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3442 relative.to_string_lossy().into_owned(),
3443 ))
3444 }
3445 lsp::GlobPattern::Relative(rp) => {
3446 let base_uri = match &rp.base_uri {
3447 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3448 lsp::OneOf::Right(base_uri) => base_uri,
3449 }
3450 .to_file_path()
3451 .ok()?;
3452 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3453 let mut literal_prefix = relative.to_owned();
3454 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3455 Some((
3456 worktree.clone(),
3457 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3458 rp.pattern.clone(),
3459 ))
3460 }
3461 }
3462 })
3463 }
3464
3465 fn rebuild_watched_paths(
3466 &mut self,
3467 language_server_id: LanguageServerId,
3468 cx: &mut Context<LspStore>,
3469 ) {
3470 let Some(registrations) = self
3471 .language_server_dynamic_registrations
3472 .get(&language_server_id)
3473 else {
3474 return;
3475 };
3476
3477 let watch_builder = self.rebuild_watched_paths_inner(
3478 language_server_id,
3479 registrations.did_change_watched_files.values().flatten(),
3480 cx,
3481 );
3482 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3483 self.language_server_watched_paths
3484 .insert(language_server_id, watcher);
3485
3486 cx.notify();
3487 }
3488
3489 fn on_lsp_did_change_watched_files(
3490 &mut self,
3491 language_server_id: LanguageServerId,
3492 registration_id: &str,
3493 params: DidChangeWatchedFilesRegistrationOptions,
3494 cx: &mut Context<LspStore>,
3495 ) {
3496 let registrations = self
3497 .language_server_dynamic_registrations
3498 .entry(language_server_id)
3499 .or_default();
3500
3501 registrations
3502 .did_change_watched_files
3503 .insert(registration_id.to_string(), params.watchers);
3504
3505 self.rebuild_watched_paths(language_server_id, cx);
3506 }
3507
3508 fn on_lsp_unregister_did_change_watched_files(
3509 &mut self,
3510 language_server_id: LanguageServerId,
3511 registration_id: &str,
3512 cx: &mut Context<LspStore>,
3513 ) {
3514 let registrations = self
3515 .language_server_dynamic_registrations
3516 .entry(language_server_id)
3517 .or_default();
3518
3519 if registrations
3520 .did_change_watched_files
3521 .remove(registration_id)
3522 .is_some()
3523 {
3524 log::info!(
3525 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3526 language_server_id,
3527 registration_id
3528 );
3529 } else {
3530 log::warn!(
3531 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3532 language_server_id,
3533 registration_id
3534 );
3535 }
3536
3537 self.rebuild_watched_paths(language_server_id, cx);
3538 }
3539
3540 async fn initialization_options_for_adapter(
3541 adapter: Arc<dyn LspAdapter>,
3542 delegate: &Arc<dyn LspAdapterDelegate>,
3543 ) -> Result<Option<serde_json::Value>> {
3544 let Some(mut initialization_config) =
3545 adapter.clone().initialization_options(delegate).await?
3546 else {
3547 return Ok(None);
3548 };
3549
3550 for other_adapter in delegate.registered_lsp_adapters() {
3551 if other_adapter.name() == adapter.name() {
3552 continue;
3553 }
3554 if let Ok(Some(target_config)) = other_adapter
3555 .clone()
3556 .additional_initialization_options(adapter.name(), delegate)
3557 .await
3558 {
3559 merge_json_value_into(target_config.clone(), &mut initialization_config);
3560 }
3561 }
3562
3563 Ok(Some(initialization_config))
3564 }
3565
3566 async fn workspace_configuration_for_adapter(
3567 adapter: Arc<dyn LspAdapter>,
3568 delegate: &Arc<dyn LspAdapterDelegate>,
3569 toolchain: Option<Toolchain>,
3570 requested_uri: Option<Uri>,
3571 cx: &mut AsyncApp,
3572 ) -> Result<serde_json::Value> {
3573 let mut workspace_config = adapter
3574 .clone()
3575 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3576 .await?;
3577
3578 for other_adapter in delegate.registered_lsp_adapters() {
3579 if other_adapter.name() == adapter.name() {
3580 continue;
3581 }
3582 if let Ok(Some(target_config)) = other_adapter
3583 .clone()
3584 .additional_workspace_configuration(adapter.name(), delegate, cx)
3585 .await
3586 {
3587 merge_json_value_into(target_config.clone(), &mut workspace_config);
3588 }
3589 }
3590
3591 Ok(workspace_config)
3592 }
3593
3594 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3595 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3596 Some(server.clone())
3597 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3598 Some(Arc::clone(server))
3599 } else {
3600 None
3601 }
3602 }
3603}
3604
3605fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3606 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3607 cx.emit(LspStoreEvent::LanguageServerUpdate {
3608 language_server_id: server.server_id(),
3609 name: Some(server.name()),
3610 message: proto::update_language_server::Variant::MetadataUpdated(
3611 proto::ServerMetadataUpdated {
3612 capabilities: Some(capabilities),
3613 binary: Some(proto::LanguageServerBinaryInfo {
3614 path: server.binary().path.to_string_lossy().into_owned(),
3615 arguments: server
3616 .binary()
3617 .arguments
3618 .iter()
3619 .map(|arg| arg.to_string_lossy().into_owned())
3620 .collect(),
3621 }),
3622 configuration: serde_json::to_string(server.configuration()).ok(),
3623 workspace_folders: server
3624 .workspace_folders()
3625 .iter()
3626 .map(|uri| uri.to_string())
3627 .collect(),
3628 },
3629 ),
3630 });
3631 }
3632}
3633
3634#[derive(Debug)]
3635pub struct FormattableBuffer {
3636 handle: Entity<Buffer>,
3637 abs_path: Option<PathBuf>,
3638 env: Option<HashMap<String, String>>,
3639 ranges: Option<Vec<Range<Anchor>>>,
3640}
3641
3642pub struct RemoteLspStore {
3643 upstream_client: Option<AnyProtoClient>,
3644 upstream_project_id: u64,
3645}
3646
3647pub(crate) enum LspStoreMode {
3648 Local(LocalLspStore), // ssh host and collab host
3649 Remote(RemoteLspStore), // collab guest
3650}
3651
3652impl LspStoreMode {
3653 fn is_local(&self) -> bool {
3654 matches!(self, LspStoreMode::Local(_))
3655 }
3656}
3657
3658pub struct LspStore {
3659 mode: LspStoreMode,
3660 last_formatting_failure: Option<String>,
3661 downstream_client: Option<(AnyProtoClient, u64)>,
3662 nonce: u128,
3663 buffer_store: Entity<BufferStore>,
3664 worktree_store: Entity<WorktreeStore>,
3665 pub languages: Arc<LanguageRegistry>,
3666 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3667 active_entry: Option<ProjectEntryId>,
3668 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3669 _maintain_buffer_languages: Task<()>,
3670 diagnostic_summaries:
3671 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3672 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3673 lsp_data: HashMap<BufferId, BufferLspData>,
3674 next_hint_id: Arc<AtomicUsize>,
3675}
3676
3677#[derive(Debug)]
3678pub struct BufferLspData {
3679 buffer_version: Global,
3680 document_colors: Option<DocumentColorData>,
3681 code_lens: Option<CodeLensData>,
3682 inlay_hints: BufferInlayHints,
3683 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3684 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3685}
3686
3687#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3688struct LspKey {
3689 request_type: TypeId,
3690 server_queried: Option<LanguageServerId>,
3691}
3692
3693impl BufferLspData {
3694 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3695 Self {
3696 buffer_version: buffer.read(cx).version(),
3697 document_colors: None,
3698 code_lens: None,
3699 inlay_hints: BufferInlayHints::new(buffer, cx),
3700 lsp_requests: HashMap::default(),
3701 chunk_lsp_requests: HashMap::default(),
3702 }
3703 }
3704
3705 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3706 if let Some(document_colors) = &mut self.document_colors {
3707 document_colors.colors.remove(&for_server);
3708 document_colors.cache_version += 1;
3709 }
3710
3711 if let Some(code_lens) = &mut self.code_lens {
3712 code_lens.lens.remove(&for_server);
3713 }
3714
3715 self.inlay_hints.remove_server_data(for_server);
3716 }
3717
3718 #[cfg(any(test, feature = "test-support"))]
3719 pub fn inlay_hints(&self) -> &BufferInlayHints {
3720 &self.inlay_hints
3721 }
3722}
3723
3724#[derive(Debug, Default, Clone)]
3725pub struct DocumentColors {
3726 pub colors: HashSet<DocumentColor>,
3727 pub cache_version: Option<usize>,
3728}
3729
3730type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3731type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3732
3733#[derive(Debug, Default)]
3734struct DocumentColorData {
3735 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3736 cache_version: usize,
3737 colors_update: Option<(Global, DocumentColorTask)>,
3738}
3739
3740#[derive(Debug, Default)]
3741struct CodeLensData {
3742 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3743 update: Option<(Global, CodeLensTask)>,
3744}
3745
3746#[derive(Debug)]
3747pub enum LspStoreEvent {
3748 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3749 LanguageServerRemoved(LanguageServerId),
3750 LanguageServerUpdate {
3751 language_server_id: LanguageServerId,
3752 name: Option<LanguageServerName>,
3753 message: proto::update_language_server::Variant,
3754 },
3755 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3756 LanguageServerPrompt(LanguageServerPromptRequest),
3757 LanguageDetected {
3758 buffer: Entity<Buffer>,
3759 new_language: Option<Arc<Language>>,
3760 },
3761 Notification(String),
3762 RefreshInlayHints {
3763 server_id: LanguageServerId,
3764 request_id: Option<usize>,
3765 },
3766 RefreshCodeLens,
3767 DiagnosticsUpdated {
3768 server_id: LanguageServerId,
3769 paths: Vec<ProjectPath>,
3770 },
3771 DiskBasedDiagnosticsStarted {
3772 language_server_id: LanguageServerId,
3773 },
3774 DiskBasedDiagnosticsFinished {
3775 language_server_id: LanguageServerId,
3776 },
3777 SnippetEdit {
3778 buffer_id: BufferId,
3779 edits: Vec<(lsp::Range, Snippet)>,
3780 most_recent_edit: clock::Lamport,
3781 },
3782}
3783
3784#[derive(Clone, Debug, Serialize)]
3785pub struct LanguageServerStatus {
3786 pub name: LanguageServerName,
3787 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3788 pub has_pending_diagnostic_updates: bool,
3789 pub progress_tokens: HashSet<ProgressToken>,
3790 pub worktree: Option<WorktreeId>,
3791 pub binary: Option<LanguageServerBinary>,
3792 pub configuration: Option<Value>,
3793 pub workspace_folders: BTreeSet<Uri>,
3794}
3795
3796#[derive(Clone, Debug)]
3797struct CoreSymbol {
3798 pub language_server_name: LanguageServerName,
3799 pub source_worktree_id: WorktreeId,
3800 pub source_language_server_id: LanguageServerId,
3801 pub path: SymbolLocation,
3802 pub name: String,
3803 pub kind: lsp::SymbolKind,
3804 pub range: Range<Unclipped<PointUtf16>>,
3805}
3806
3807#[derive(Clone, Debug, PartialEq, Eq)]
3808pub enum SymbolLocation {
3809 InProject(ProjectPath),
3810 OutsideProject {
3811 abs_path: Arc<Path>,
3812 signature: [u8; 32],
3813 },
3814}
3815
3816impl SymbolLocation {
3817 fn file_name(&self) -> Option<&str> {
3818 match self {
3819 Self::InProject(path) => path.path.file_name(),
3820 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3821 }
3822 }
3823}
3824
3825impl LspStore {
3826 pub fn init(client: &AnyProtoClient) {
3827 client.add_entity_request_handler(Self::handle_lsp_query);
3828 client.add_entity_message_handler(Self::handle_lsp_query_response);
3829 client.add_entity_request_handler(Self::handle_restart_language_servers);
3830 client.add_entity_request_handler(Self::handle_stop_language_servers);
3831 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3832 client.add_entity_message_handler(Self::handle_start_language_server);
3833 client.add_entity_message_handler(Self::handle_update_language_server);
3834 client.add_entity_message_handler(Self::handle_language_server_log);
3835 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3836 client.add_entity_request_handler(Self::handle_format_buffers);
3837 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3838 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3839 client.add_entity_request_handler(Self::handle_apply_code_action);
3840 client.add_entity_request_handler(Self::handle_get_project_symbols);
3841 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3842 client.add_entity_request_handler(Self::handle_get_color_presentation);
3843 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3844 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3845 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3846 client.add_entity_request_handler(Self::handle_on_type_formatting);
3847 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3848 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3849 client.add_entity_request_handler(Self::handle_rename_project_entry);
3850 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3851 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3852 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3853 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3854 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3855 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3856 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3857
3858 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3859 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3860 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3861 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3862 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3863 client.add_entity_request_handler(
3864 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3865 );
3866 client.add_entity_request_handler(
3867 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3868 );
3869 client.add_entity_request_handler(
3870 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3871 );
3872 }
3873
3874 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3875 match &self.mode {
3876 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3877 _ => None,
3878 }
3879 }
3880
3881 pub fn as_local(&self) -> Option<&LocalLspStore> {
3882 match &self.mode {
3883 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3884 _ => None,
3885 }
3886 }
3887
3888 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3889 match &mut self.mode {
3890 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3891 _ => None,
3892 }
3893 }
3894
3895 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3896 match &self.mode {
3897 LspStoreMode::Remote(RemoteLspStore {
3898 upstream_client: Some(upstream_client),
3899 upstream_project_id,
3900 ..
3901 }) => Some((upstream_client.clone(), *upstream_project_id)),
3902
3903 LspStoreMode::Remote(RemoteLspStore {
3904 upstream_client: None,
3905 ..
3906 }) => None,
3907 LspStoreMode::Local(_) => None,
3908 }
3909 }
3910
3911 pub fn new_local(
3912 buffer_store: Entity<BufferStore>,
3913 worktree_store: Entity<WorktreeStore>,
3914 prettier_store: Entity<PrettierStore>,
3915 toolchain_store: Entity<LocalToolchainStore>,
3916 environment: Entity<ProjectEnvironment>,
3917 manifest_tree: Entity<ManifestTree>,
3918 languages: Arc<LanguageRegistry>,
3919 http_client: Arc<dyn HttpClient>,
3920 fs: Arc<dyn Fs>,
3921 cx: &mut Context<Self>,
3922 ) -> Self {
3923 let yarn = YarnPathStore::new(fs.clone(), cx);
3924 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3925 .detach();
3926 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3927 .detach();
3928 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3929 .detach();
3930 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3931 .detach();
3932 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3933 .detach();
3934 subscribe_to_binary_statuses(&languages, cx).detach();
3935
3936 let _maintain_workspace_config = {
3937 let (sender, receiver) = watch::channel();
3938 (Self::maintain_workspace_config(receiver, cx), sender)
3939 };
3940
3941 Self {
3942 mode: LspStoreMode::Local(LocalLspStore {
3943 weak: cx.weak_entity(),
3944 worktree_store: worktree_store.clone(),
3945
3946 supplementary_language_servers: Default::default(),
3947 languages: languages.clone(),
3948 language_server_ids: Default::default(),
3949 language_servers: Default::default(),
3950 last_workspace_edits_by_language_server: Default::default(),
3951 language_server_watched_paths: Default::default(),
3952 language_server_paths_watched_for_rename: Default::default(),
3953 language_server_dynamic_registrations: Default::default(),
3954 buffers_being_formatted: Default::default(),
3955 buffer_snapshots: Default::default(),
3956 prettier_store,
3957 environment,
3958 http_client,
3959 fs,
3960 yarn,
3961 next_diagnostic_group_id: Default::default(),
3962 diagnostics: Default::default(),
3963 _subscription: cx.on_app_quit(|this, cx| {
3964 this.as_local_mut()
3965 .unwrap()
3966 .shutdown_language_servers_on_quit(cx)
3967 }),
3968 lsp_tree: LanguageServerTree::new(
3969 manifest_tree,
3970 languages.clone(),
3971 toolchain_store.clone(),
3972 ),
3973 toolchain_store,
3974 registered_buffers: HashMap::default(),
3975 buffers_opened_in_servers: HashMap::default(),
3976 buffer_pull_diagnostics_result_ids: HashMap::default(),
3977 workspace_pull_diagnostics_result_ids: HashMap::default(),
3978 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3979 .manifest_file_names(),
3980 }),
3981 last_formatting_failure: None,
3982 downstream_client: None,
3983 buffer_store,
3984 worktree_store,
3985 languages: languages.clone(),
3986 language_server_statuses: Default::default(),
3987 nonce: StdRng::from_os_rng().random(),
3988 diagnostic_summaries: HashMap::default(),
3989 lsp_server_capabilities: HashMap::default(),
3990 lsp_data: HashMap::default(),
3991 next_hint_id: Arc::default(),
3992 active_entry: None,
3993 _maintain_workspace_config,
3994 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3995 }
3996 }
3997
3998 fn send_lsp_proto_request<R: LspCommand>(
3999 &self,
4000 buffer: Entity<Buffer>,
4001 client: AnyProtoClient,
4002 upstream_project_id: u64,
4003 request: R,
4004 cx: &mut Context<LspStore>,
4005 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4006 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4007 return Task::ready(Ok(R::Response::default()));
4008 }
4009 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4010 cx.spawn(async move |this, cx| {
4011 let response = client.request(message).await?;
4012 let this = this.upgrade().context("project dropped")?;
4013 request
4014 .response_from_proto(response, this, buffer, cx.clone())
4015 .await
4016 })
4017 }
4018
4019 pub(super) fn new_remote(
4020 buffer_store: Entity<BufferStore>,
4021 worktree_store: Entity<WorktreeStore>,
4022 languages: Arc<LanguageRegistry>,
4023 upstream_client: AnyProtoClient,
4024 project_id: u64,
4025 cx: &mut Context<Self>,
4026 ) -> Self {
4027 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4028 .detach();
4029 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4030 .detach();
4031 subscribe_to_binary_statuses(&languages, cx).detach();
4032 let _maintain_workspace_config = {
4033 let (sender, receiver) = watch::channel();
4034 (Self::maintain_workspace_config(receiver, cx), sender)
4035 };
4036 Self {
4037 mode: LspStoreMode::Remote(RemoteLspStore {
4038 upstream_client: Some(upstream_client),
4039 upstream_project_id: project_id,
4040 }),
4041 downstream_client: None,
4042 last_formatting_failure: None,
4043 buffer_store,
4044 worktree_store,
4045 languages: languages.clone(),
4046 language_server_statuses: Default::default(),
4047 nonce: StdRng::from_os_rng().random(),
4048 diagnostic_summaries: HashMap::default(),
4049 lsp_server_capabilities: HashMap::default(),
4050 next_hint_id: Arc::default(),
4051 lsp_data: HashMap::default(),
4052 active_entry: None,
4053
4054 _maintain_workspace_config,
4055 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4056 }
4057 }
4058
4059 fn on_buffer_store_event(
4060 &mut self,
4061 _: Entity<BufferStore>,
4062 event: &BufferStoreEvent,
4063 cx: &mut Context<Self>,
4064 ) {
4065 match event {
4066 BufferStoreEvent::BufferAdded(buffer) => {
4067 self.on_buffer_added(buffer, cx).log_err();
4068 }
4069 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4070 let buffer_id = buffer.read(cx).remote_id();
4071 if let Some(local) = self.as_local_mut()
4072 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4073 {
4074 local.reset_buffer(buffer, old_file, cx);
4075
4076 if local.registered_buffers.contains_key(&buffer_id) {
4077 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4078 }
4079 }
4080
4081 self.detect_language_for_buffer(buffer, cx);
4082 if let Some(local) = self.as_local_mut() {
4083 local.initialize_buffer(buffer, cx);
4084 if local.registered_buffers.contains_key(&buffer_id) {
4085 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4086 }
4087 }
4088 }
4089 _ => {}
4090 }
4091 }
4092
4093 fn on_worktree_store_event(
4094 &mut self,
4095 _: Entity<WorktreeStore>,
4096 event: &WorktreeStoreEvent,
4097 cx: &mut Context<Self>,
4098 ) {
4099 match event {
4100 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4101 if !worktree.read(cx).is_local() {
4102 return;
4103 }
4104 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4105 worktree::Event::UpdatedEntries(changes) => {
4106 this.update_local_worktree_language_servers(&worktree, changes, cx);
4107 }
4108 worktree::Event::UpdatedGitRepositories(_)
4109 | worktree::Event::DeletedEntry(_) => {}
4110 })
4111 .detach()
4112 }
4113 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4114 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4115 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4116 }
4117 WorktreeStoreEvent::WorktreeReleased(..)
4118 | WorktreeStoreEvent::WorktreeOrderChanged
4119 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4120 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4121 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4122 }
4123 }
4124
4125 fn on_prettier_store_event(
4126 &mut self,
4127 _: Entity<PrettierStore>,
4128 event: &PrettierStoreEvent,
4129 cx: &mut Context<Self>,
4130 ) {
4131 match event {
4132 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4133 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4134 }
4135 PrettierStoreEvent::LanguageServerAdded {
4136 new_server_id,
4137 name,
4138 prettier_server,
4139 } => {
4140 self.register_supplementary_language_server(
4141 *new_server_id,
4142 name.clone(),
4143 prettier_server.clone(),
4144 cx,
4145 );
4146 }
4147 }
4148 }
4149
4150 fn on_toolchain_store_event(
4151 &mut self,
4152 _: Entity<LocalToolchainStore>,
4153 event: &ToolchainStoreEvent,
4154 _: &mut Context<Self>,
4155 ) {
4156 if let ToolchainStoreEvent::ToolchainActivated = event {
4157 self.request_workspace_config_refresh()
4158 }
4159 }
4160
4161 fn request_workspace_config_refresh(&mut self) {
4162 *self._maintain_workspace_config.1.borrow_mut() = ();
4163 }
4164
4165 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4166 self.as_local().map(|local| local.prettier_store.clone())
4167 }
4168
4169 fn on_buffer_event(
4170 &mut self,
4171 buffer: Entity<Buffer>,
4172 event: &language::BufferEvent,
4173 cx: &mut Context<Self>,
4174 ) {
4175 match event {
4176 language::BufferEvent::Edited => {
4177 self.on_buffer_edited(buffer, cx);
4178 }
4179
4180 language::BufferEvent::Saved => {
4181 self.on_buffer_saved(buffer, cx);
4182 }
4183
4184 _ => {}
4185 }
4186 }
4187
4188 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4189 buffer
4190 .read(cx)
4191 .set_language_registry(self.languages.clone());
4192
4193 cx.subscribe(buffer, |this, buffer, event, cx| {
4194 this.on_buffer_event(buffer, event, cx);
4195 })
4196 .detach();
4197
4198 self.detect_language_for_buffer(buffer, cx);
4199 if let Some(local) = self.as_local_mut() {
4200 local.initialize_buffer(buffer, cx);
4201 }
4202
4203 Ok(())
4204 }
4205
4206 pub(crate) fn register_buffer_with_language_servers(
4207 &mut self,
4208 buffer: &Entity<Buffer>,
4209 only_register_servers: HashSet<LanguageServerSelector>,
4210 ignore_refcounts: bool,
4211 cx: &mut Context<Self>,
4212 ) -> OpenLspBufferHandle {
4213 let buffer_id = buffer.read(cx).remote_id();
4214 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4215 if let Some(local) = self.as_local_mut() {
4216 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4217 if !ignore_refcounts {
4218 *refcount += 1;
4219 }
4220
4221 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4222 // 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
4223 // 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
4224 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4225 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4226 return handle;
4227 };
4228 if !file.is_local() {
4229 return handle;
4230 }
4231
4232 if ignore_refcounts || *refcount == 1 {
4233 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4234 }
4235 if !ignore_refcounts {
4236 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4237 let refcount = {
4238 let local = lsp_store.as_local_mut().unwrap();
4239 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4240 debug_panic!("bad refcounting");
4241 return;
4242 };
4243
4244 *refcount -= 1;
4245 *refcount
4246 };
4247 if refcount == 0 {
4248 lsp_store.lsp_data.remove(&buffer_id);
4249 let local = lsp_store.as_local_mut().unwrap();
4250 local.registered_buffers.remove(&buffer_id);
4251
4252 local.buffers_opened_in_servers.remove(&buffer_id);
4253 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4254 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4255
4256 let buffer_abs_path = file.abs_path(cx);
4257 for (_, buffer_pull_diagnostics_result_ids) in
4258 &mut local.buffer_pull_diagnostics_result_ids
4259 {
4260 buffer_pull_diagnostics_result_ids.retain(
4261 |_, buffer_result_ids| {
4262 buffer_result_ids.remove(&buffer_abs_path);
4263 !buffer_result_ids.is_empty()
4264 },
4265 );
4266 }
4267
4268 let diagnostic_updates = local
4269 .language_servers
4270 .keys()
4271 .cloned()
4272 .map(|server_id| DocumentDiagnosticsUpdate {
4273 diagnostics: DocumentDiagnostics {
4274 document_abs_path: buffer_abs_path.clone(),
4275 version: None,
4276 diagnostics: Vec::new(),
4277 },
4278 result_id: None,
4279 registration_id: None,
4280 server_id: server_id,
4281 disk_based_sources: Cow::Borrowed(&[]),
4282 })
4283 .collect::<Vec<_>>();
4284
4285 lsp_store
4286 .merge_diagnostic_entries(
4287 diagnostic_updates,
4288 |_, diagnostic, _| {
4289 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4290 },
4291 cx,
4292 )
4293 .context("Clearing diagnostics for the closed buffer")
4294 .log_err();
4295 }
4296 }
4297 })
4298 .detach();
4299 }
4300 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4301 let buffer_id = buffer.read(cx).remote_id().to_proto();
4302 cx.background_spawn(async move {
4303 upstream_client
4304 .request(proto::RegisterBufferWithLanguageServers {
4305 project_id: upstream_project_id,
4306 buffer_id,
4307 only_servers: only_register_servers
4308 .into_iter()
4309 .map(|selector| {
4310 let selector = match selector {
4311 LanguageServerSelector::Id(language_server_id) => {
4312 proto::language_server_selector::Selector::ServerId(
4313 language_server_id.to_proto(),
4314 )
4315 }
4316 LanguageServerSelector::Name(language_server_name) => {
4317 proto::language_server_selector::Selector::Name(
4318 language_server_name.to_string(),
4319 )
4320 }
4321 };
4322 proto::LanguageServerSelector {
4323 selector: Some(selector),
4324 }
4325 })
4326 .collect(),
4327 })
4328 .await
4329 })
4330 .detach();
4331 } else {
4332 // Our remote connection got closed
4333 }
4334 handle
4335 }
4336
4337 fn maintain_buffer_languages(
4338 languages: Arc<LanguageRegistry>,
4339 cx: &mut Context<Self>,
4340 ) -> Task<()> {
4341 let mut subscription = languages.subscribe();
4342 let mut prev_reload_count = languages.reload_count();
4343 cx.spawn(async move |this, cx| {
4344 while let Some(()) = subscription.next().await {
4345 if let Some(this) = this.upgrade() {
4346 // If the language registry has been reloaded, then remove and
4347 // re-assign the languages on all open buffers.
4348 let reload_count = languages.reload_count();
4349 if reload_count > prev_reload_count {
4350 prev_reload_count = reload_count;
4351 this.update(cx, |this, cx| {
4352 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4353 for buffer in buffer_store.buffers() {
4354 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4355 {
4356 buffer.update(cx, |buffer, cx| {
4357 buffer.set_language_async(None, cx)
4358 });
4359 if let Some(local) = this.as_local_mut() {
4360 local.reset_buffer(&buffer, &f, cx);
4361
4362 if local
4363 .registered_buffers
4364 .contains_key(&buffer.read(cx).remote_id())
4365 && let Some(file_url) =
4366 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4367 {
4368 local.unregister_buffer_from_language_servers(
4369 &buffer, &file_url, cx,
4370 );
4371 }
4372 }
4373 }
4374 }
4375 });
4376 })
4377 .ok();
4378 }
4379
4380 this.update(cx, |this, cx| {
4381 let mut plain_text_buffers = Vec::new();
4382 let mut buffers_with_unknown_injections = Vec::new();
4383 for handle in this.buffer_store.read(cx).buffers() {
4384 let buffer = handle.read(cx);
4385 if buffer.language().is_none()
4386 || buffer.language() == Some(&*language::PLAIN_TEXT)
4387 {
4388 plain_text_buffers.push(handle);
4389 } else if buffer.contains_unknown_injections() {
4390 buffers_with_unknown_injections.push(handle);
4391 }
4392 }
4393
4394 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4395 // and reused later in the invisible worktrees.
4396 plain_text_buffers.sort_by_key(|buffer| {
4397 Reverse(
4398 File::from_dyn(buffer.read(cx).file())
4399 .map(|file| file.worktree.read(cx).is_visible()),
4400 )
4401 });
4402
4403 for buffer in plain_text_buffers {
4404 this.detect_language_for_buffer(&buffer, cx);
4405 if let Some(local) = this.as_local_mut() {
4406 local.initialize_buffer(&buffer, cx);
4407 if local
4408 .registered_buffers
4409 .contains_key(&buffer.read(cx).remote_id())
4410 {
4411 local.register_buffer_with_language_servers(
4412 &buffer,
4413 HashSet::default(),
4414 cx,
4415 );
4416 }
4417 }
4418 }
4419
4420 for buffer in buffers_with_unknown_injections {
4421 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4422 }
4423 })
4424 .ok();
4425 }
4426 }
4427 })
4428 }
4429
4430 fn detect_language_for_buffer(
4431 &mut self,
4432 buffer_handle: &Entity<Buffer>,
4433 cx: &mut Context<Self>,
4434 ) -> Option<language::AvailableLanguage> {
4435 // If the buffer has a language, set it and start the language server if we haven't already.
4436 let buffer = buffer_handle.read(cx);
4437 let file = buffer.file()?;
4438
4439 let content = buffer.as_rope();
4440 let available_language = self.languages.language_for_file(file, Some(content), cx);
4441 if let Some(available_language) = &available_language {
4442 if let Some(Ok(Ok(new_language))) = self
4443 .languages
4444 .load_language(available_language)
4445 .now_or_never()
4446 {
4447 self.set_language_for_buffer(buffer_handle, new_language, cx);
4448 }
4449 } else {
4450 cx.emit(LspStoreEvent::LanguageDetected {
4451 buffer: buffer_handle.clone(),
4452 new_language: None,
4453 });
4454 }
4455
4456 available_language
4457 }
4458
4459 pub(crate) fn set_language_for_buffer(
4460 &mut self,
4461 buffer_entity: &Entity<Buffer>,
4462 new_language: Arc<Language>,
4463 cx: &mut Context<Self>,
4464 ) {
4465 let buffer = buffer_entity.read(cx);
4466 let buffer_file = buffer.file().cloned();
4467 let buffer_id = buffer.remote_id();
4468 if let Some(local_store) = self.as_local_mut()
4469 && local_store.registered_buffers.contains_key(&buffer_id)
4470 && let Some(abs_path) =
4471 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4472 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4473 {
4474 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4475 }
4476 buffer_entity.update(cx, |buffer, cx| {
4477 if buffer
4478 .language()
4479 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4480 {
4481 buffer.set_language_async(Some(new_language.clone()), cx);
4482 }
4483 });
4484
4485 let settings =
4486 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4487 let buffer_file = File::from_dyn(buffer_file.as_ref());
4488
4489 let worktree_id = if let Some(file) = buffer_file {
4490 let worktree = file.worktree.clone();
4491
4492 if let Some(local) = self.as_local_mut()
4493 && local.registered_buffers.contains_key(&buffer_id)
4494 {
4495 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4496 }
4497 Some(worktree.read(cx).id())
4498 } else {
4499 None
4500 };
4501
4502 if settings.prettier.allowed
4503 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4504 {
4505 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4506 if let Some(prettier_store) = prettier_store {
4507 prettier_store.update(cx, |prettier_store, cx| {
4508 prettier_store.install_default_prettier(
4509 worktree_id,
4510 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4511 cx,
4512 )
4513 })
4514 }
4515 }
4516
4517 cx.emit(LspStoreEvent::LanguageDetected {
4518 buffer: buffer_entity.clone(),
4519 new_language: Some(new_language),
4520 })
4521 }
4522
4523 pub fn buffer_store(&self) -> Entity<BufferStore> {
4524 self.buffer_store.clone()
4525 }
4526
4527 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4528 self.active_entry = active_entry;
4529 }
4530
4531 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4532 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4533 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4534 {
4535 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4536 summaries
4537 .iter()
4538 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4539 });
4540 if let Some(summary) = summaries.next() {
4541 client
4542 .send(proto::UpdateDiagnosticSummary {
4543 project_id: downstream_project_id,
4544 worktree_id: worktree.id().to_proto(),
4545 summary: Some(summary),
4546 more_summaries: summaries.collect(),
4547 })
4548 .log_err();
4549 }
4550 }
4551 }
4552
4553 fn is_capable_for_proto_request<R>(
4554 &self,
4555 buffer: &Entity<Buffer>,
4556 request: &R,
4557 cx: &App,
4558 ) -> bool
4559 where
4560 R: LspCommand,
4561 {
4562 self.check_if_capable_for_proto_request(
4563 buffer,
4564 |capabilities| {
4565 request.check_capabilities(AdapterServerCapabilities {
4566 server_capabilities: capabilities.clone(),
4567 code_action_kinds: None,
4568 })
4569 },
4570 cx,
4571 )
4572 }
4573
4574 fn check_if_capable_for_proto_request<F>(
4575 &self,
4576 buffer: &Entity<Buffer>,
4577 check: F,
4578 cx: &App,
4579 ) -> bool
4580 where
4581 F: FnMut(&lsp::ServerCapabilities) -> bool,
4582 {
4583 let Some(language) = buffer.read(cx).language().cloned() else {
4584 return false;
4585 };
4586 let relevant_language_servers = self
4587 .languages
4588 .lsp_adapters(&language.name())
4589 .into_iter()
4590 .map(|lsp_adapter| lsp_adapter.name())
4591 .collect::<HashSet<_>>();
4592 self.language_server_statuses
4593 .iter()
4594 .filter_map(|(server_id, server_status)| {
4595 relevant_language_servers
4596 .contains(&server_status.name)
4597 .then_some(server_id)
4598 })
4599 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4600 .any(check)
4601 }
4602
4603 fn all_capable_for_proto_request<F>(
4604 &self,
4605 buffer: &Entity<Buffer>,
4606 mut check: F,
4607 cx: &App,
4608 ) -> Vec<lsp::LanguageServerId>
4609 where
4610 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4611 {
4612 let Some(language) = buffer.read(cx).language().cloned() else {
4613 return Vec::default();
4614 };
4615 let relevant_language_servers = self
4616 .languages
4617 .lsp_adapters(&language.name())
4618 .into_iter()
4619 .map(|lsp_adapter| lsp_adapter.name())
4620 .collect::<HashSet<_>>();
4621 self.language_server_statuses
4622 .iter()
4623 .filter_map(|(server_id, server_status)| {
4624 relevant_language_servers
4625 .contains(&server_status.name)
4626 .then_some((server_id, &server_status.name))
4627 })
4628 .filter_map(|(server_id, server_name)| {
4629 self.lsp_server_capabilities
4630 .get(server_id)
4631 .map(|c| (server_id, server_name, c))
4632 })
4633 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4634 .map(|(server_id, _, _)| *server_id)
4635 .collect()
4636 }
4637
4638 pub fn request_lsp<R>(
4639 &mut self,
4640 buffer: Entity<Buffer>,
4641 server: LanguageServerToQuery,
4642 request: R,
4643 cx: &mut Context<Self>,
4644 ) -> Task<Result<R::Response>>
4645 where
4646 R: LspCommand,
4647 <R::LspRequest as lsp::request::Request>::Result: Send,
4648 <R::LspRequest as lsp::request::Request>::Params: Send,
4649 {
4650 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4651 return self.send_lsp_proto_request(
4652 buffer,
4653 upstream_client,
4654 upstream_project_id,
4655 request,
4656 cx,
4657 );
4658 }
4659
4660 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4661 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4662 local
4663 .language_servers_for_buffer(buffer, cx)
4664 .find(|(_, server)| {
4665 request.check_capabilities(server.adapter_server_capabilities())
4666 })
4667 .map(|(_, server)| server.clone())
4668 }),
4669 LanguageServerToQuery::Other(id) => self
4670 .language_server_for_local_buffer(buffer, id, cx)
4671 .and_then(|(_, server)| {
4672 request
4673 .check_capabilities(server.adapter_server_capabilities())
4674 .then(|| Arc::clone(server))
4675 }),
4676 }) else {
4677 return Task::ready(Ok(Default::default()));
4678 };
4679
4680 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4681
4682 let Some(file) = file else {
4683 return Task::ready(Ok(Default::default()));
4684 };
4685
4686 let lsp_params = match request.to_lsp_params_or_response(
4687 &file.abs_path(cx),
4688 buffer.read(cx),
4689 &language_server,
4690 cx,
4691 ) {
4692 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4693 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4694 Err(err) => {
4695 let message = format!(
4696 "{} via {} failed: {}",
4697 request.display_name(),
4698 language_server.name(),
4699 err
4700 );
4701 // rust-analyzer likes to error with this when its still loading up
4702 if !message.ends_with("content modified") {
4703 log::warn!("{message}");
4704 }
4705 return Task::ready(Err(anyhow!(message)));
4706 }
4707 };
4708
4709 let status = request.status();
4710 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4711 return Task::ready(Ok(Default::default()));
4712 }
4713 cx.spawn(async move |this, cx| {
4714 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4715
4716 let id = lsp_request.id();
4717 let _cleanup = if status.is_some() {
4718 cx.update(|cx| {
4719 this.update(cx, |this, cx| {
4720 this.on_lsp_work_start(
4721 language_server.server_id(),
4722 ProgressToken::Number(id),
4723 LanguageServerProgress {
4724 is_disk_based_diagnostics_progress: false,
4725 is_cancellable: false,
4726 title: None,
4727 message: status.clone(),
4728 percentage: None,
4729 last_update_at: cx.background_executor().now(),
4730 },
4731 cx,
4732 );
4733 })
4734 })
4735 .log_err();
4736
4737 Some(defer(|| {
4738 cx.update(|cx| {
4739 this.update(cx, |this, cx| {
4740 this.on_lsp_work_end(
4741 language_server.server_id(),
4742 ProgressToken::Number(id),
4743 cx,
4744 );
4745 })
4746 })
4747 .log_err();
4748 }))
4749 } else {
4750 None
4751 };
4752
4753 let result = lsp_request.await.into_response();
4754
4755 let response = result.map_err(|err| {
4756 let message = format!(
4757 "{} via {} failed: {}",
4758 request.display_name(),
4759 language_server.name(),
4760 err
4761 );
4762 // rust-analyzer likes to error with this when its still loading up
4763 if !message.ends_with("content modified") {
4764 log::warn!("{message}");
4765 }
4766 anyhow::anyhow!(message)
4767 })?;
4768
4769 request
4770 .response_from_lsp(
4771 response,
4772 this.upgrade().context("no app context")?,
4773 buffer,
4774 language_server.server_id(),
4775 cx.clone(),
4776 )
4777 .await
4778 })
4779 }
4780
4781 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4782 let mut language_formatters_to_check = Vec::new();
4783 for buffer in self.buffer_store.read(cx).buffers() {
4784 let buffer = buffer.read(cx);
4785 let buffer_file = File::from_dyn(buffer.file());
4786 let buffer_language = buffer.language();
4787 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4788 if buffer_language.is_some() {
4789 language_formatters_to_check.push((
4790 buffer_file.map(|f| f.worktree_id(cx)),
4791 settings.into_owned(),
4792 ));
4793 }
4794 }
4795
4796 self.request_workspace_config_refresh();
4797
4798 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4799 prettier_store.update(cx, |prettier_store, cx| {
4800 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4801 })
4802 }
4803
4804 cx.notify();
4805 }
4806
4807 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4808 let buffer_store = self.buffer_store.clone();
4809 let Some(local) = self.as_local_mut() else {
4810 return;
4811 };
4812 let mut adapters = BTreeMap::default();
4813 let get_adapter = {
4814 let languages = local.languages.clone();
4815 let environment = local.environment.clone();
4816 let weak = local.weak.clone();
4817 let worktree_store = local.worktree_store.clone();
4818 let http_client = local.http_client.clone();
4819 let fs = local.fs.clone();
4820 move |worktree_id, cx: &mut App| {
4821 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4822 Some(LocalLspAdapterDelegate::new(
4823 languages.clone(),
4824 &environment,
4825 weak.clone(),
4826 &worktree,
4827 http_client.clone(),
4828 fs.clone(),
4829 cx,
4830 ))
4831 }
4832 };
4833
4834 let mut messages_to_report = Vec::new();
4835 let (new_tree, to_stop) = {
4836 let mut rebase = local.lsp_tree.rebase();
4837 let buffers = buffer_store
4838 .read(cx)
4839 .buffers()
4840 .filter_map(|buffer| {
4841 let raw_buffer = buffer.read(cx);
4842 if !local
4843 .registered_buffers
4844 .contains_key(&raw_buffer.remote_id())
4845 {
4846 return None;
4847 }
4848 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4849 let language = raw_buffer.language().cloned()?;
4850 Some((file, language, raw_buffer.remote_id()))
4851 })
4852 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4853 for (file, language, buffer_id) in buffers {
4854 let worktree_id = file.worktree_id(cx);
4855 let Some(worktree) = local
4856 .worktree_store
4857 .read(cx)
4858 .worktree_for_id(worktree_id, cx)
4859 else {
4860 continue;
4861 };
4862
4863 if let Some((_, apply)) = local.reuse_existing_language_server(
4864 rebase.server_tree(),
4865 &worktree,
4866 &language.name(),
4867 cx,
4868 ) {
4869 (apply)(rebase.server_tree());
4870 } else if let Some(lsp_delegate) = adapters
4871 .entry(worktree_id)
4872 .or_insert_with(|| get_adapter(worktree_id, cx))
4873 .clone()
4874 {
4875 let delegate =
4876 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4877 let path = file
4878 .path()
4879 .parent()
4880 .map(Arc::from)
4881 .unwrap_or_else(|| file.path().clone());
4882 let worktree_path = ProjectPath { worktree_id, path };
4883 let abs_path = file.abs_path(cx);
4884 let nodes = rebase
4885 .walk(
4886 worktree_path,
4887 language.name(),
4888 language.manifest(),
4889 delegate.clone(),
4890 cx,
4891 )
4892 .collect::<Vec<_>>();
4893 for node in nodes {
4894 let server_id = node.server_id_or_init(|disposition| {
4895 let path = &disposition.path;
4896 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4897 let key = LanguageServerSeed {
4898 worktree_id,
4899 name: disposition.server_name.clone(),
4900 settings: disposition.settings.clone(),
4901 toolchain: local.toolchain_store.read(cx).active_toolchain(
4902 path.worktree_id,
4903 &path.path,
4904 language.name(),
4905 ),
4906 };
4907 local.language_server_ids.remove(&key);
4908
4909 let server_id = local.get_or_insert_language_server(
4910 &worktree,
4911 lsp_delegate.clone(),
4912 disposition,
4913 &language.name(),
4914 cx,
4915 );
4916 if let Some(state) = local.language_servers.get(&server_id)
4917 && let Ok(uri) = uri
4918 {
4919 state.add_workspace_folder(uri);
4920 };
4921 server_id
4922 });
4923
4924 if let Some(language_server_id) = server_id {
4925 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4926 language_server_id,
4927 name: node.name(),
4928 message:
4929 proto::update_language_server::Variant::RegisteredForBuffer(
4930 proto::RegisteredForBuffer {
4931 buffer_abs_path: abs_path
4932 .to_string_lossy()
4933 .into_owned(),
4934 buffer_id: buffer_id.to_proto(),
4935 },
4936 ),
4937 });
4938 }
4939 }
4940 } else {
4941 continue;
4942 }
4943 }
4944 rebase.finish()
4945 };
4946 for message in messages_to_report {
4947 cx.emit(message);
4948 }
4949 local.lsp_tree = new_tree;
4950 for (id, _) in to_stop {
4951 self.stop_local_language_server(id, cx).detach();
4952 }
4953 }
4954
4955 pub fn apply_code_action(
4956 &self,
4957 buffer_handle: Entity<Buffer>,
4958 mut action: CodeAction,
4959 push_to_history: bool,
4960 cx: &mut Context<Self>,
4961 ) -> Task<Result<ProjectTransaction>> {
4962 if let Some((upstream_client, project_id)) = self.upstream_client() {
4963 let request = proto::ApplyCodeAction {
4964 project_id,
4965 buffer_id: buffer_handle.read(cx).remote_id().into(),
4966 action: Some(Self::serialize_code_action(&action)),
4967 };
4968 let buffer_store = self.buffer_store();
4969 cx.spawn(async move |_, cx| {
4970 let response = upstream_client
4971 .request(request)
4972 .await?
4973 .transaction
4974 .context("missing transaction")?;
4975
4976 buffer_store
4977 .update(cx, |buffer_store, cx| {
4978 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4979 })?
4980 .await
4981 })
4982 } else if self.mode.is_local() {
4983 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4984 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4985 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4986 }) else {
4987 return Task::ready(Ok(ProjectTransaction::default()));
4988 };
4989 cx.spawn(async move |this, cx| {
4990 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4991 .await
4992 .context("resolving a code action")?;
4993 if let Some(edit) = action.lsp_action.edit()
4994 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4995 return LocalLspStore::deserialize_workspace_edit(
4996 this.upgrade().context("no app present")?,
4997 edit.clone(),
4998 push_to_history,
4999
5000 lang_server.clone(),
5001 cx,
5002 )
5003 .await;
5004 }
5005
5006 if let Some(command) = action.lsp_action.command() {
5007 let server_capabilities = lang_server.capabilities();
5008 let available_commands = server_capabilities
5009 .execute_command_provider
5010 .as_ref()
5011 .map(|options| options.commands.as_slice())
5012 .unwrap_or_default();
5013 if available_commands.contains(&command.command) {
5014 this.update(cx, |this, _| {
5015 this.as_local_mut()
5016 .unwrap()
5017 .last_workspace_edits_by_language_server
5018 .remove(&lang_server.server_id());
5019 })?;
5020
5021 let _result = lang_server
5022 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5023 command: command.command.clone(),
5024 arguments: command.arguments.clone().unwrap_or_default(),
5025 ..lsp::ExecuteCommandParams::default()
5026 })
5027 .await.into_response()
5028 .context("execute command")?;
5029
5030 return this.update(cx, |this, _| {
5031 this.as_local_mut()
5032 .unwrap()
5033 .last_workspace_edits_by_language_server
5034 .remove(&lang_server.server_id())
5035 .unwrap_or_default()
5036 });
5037 } else {
5038 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5039 }
5040 }
5041
5042 Ok(ProjectTransaction::default())
5043 })
5044 } else {
5045 Task::ready(Err(anyhow!("no upstream client and not local")))
5046 }
5047 }
5048
5049 pub fn apply_code_action_kind(
5050 &mut self,
5051 buffers: HashSet<Entity<Buffer>>,
5052 kind: CodeActionKind,
5053 push_to_history: bool,
5054 cx: &mut Context<Self>,
5055 ) -> Task<anyhow::Result<ProjectTransaction>> {
5056 if self.as_local().is_some() {
5057 cx.spawn(async move |lsp_store, cx| {
5058 let buffers = buffers.into_iter().collect::<Vec<_>>();
5059 let result = LocalLspStore::execute_code_action_kind_locally(
5060 lsp_store.clone(),
5061 buffers,
5062 kind,
5063 push_to_history,
5064 cx,
5065 )
5066 .await;
5067 lsp_store.update(cx, |lsp_store, _| {
5068 lsp_store.update_last_formatting_failure(&result);
5069 })?;
5070 result
5071 })
5072 } else if let Some((client, project_id)) = self.upstream_client() {
5073 let buffer_store = self.buffer_store();
5074 cx.spawn(async move |lsp_store, cx| {
5075 let result = client
5076 .request(proto::ApplyCodeActionKind {
5077 project_id,
5078 kind: kind.as_str().to_owned(),
5079 buffer_ids: buffers
5080 .iter()
5081 .map(|buffer| {
5082 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5083 })
5084 .collect::<Result<_>>()?,
5085 })
5086 .await
5087 .and_then(|result| result.transaction.context("missing transaction"));
5088 lsp_store.update(cx, |lsp_store, _| {
5089 lsp_store.update_last_formatting_failure(&result);
5090 })?;
5091
5092 let transaction_response = result?;
5093 buffer_store
5094 .update(cx, |buffer_store, cx| {
5095 buffer_store.deserialize_project_transaction(
5096 transaction_response,
5097 push_to_history,
5098 cx,
5099 )
5100 })?
5101 .await
5102 })
5103 } else {
5104 Task::ready(Ok(ProjectTransaction::default()))
5105 }
5106 }
5107
5108 pub fn resolved_hint(
5109 &mut self,
5110 buffer_id: BufferId,
5111 id: InlayId,
5112 cx: &mut Context<Self>,
5113 ) -> Option<ResolvedHint> {
5114 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5115
5116 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5117 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5118 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5119 let (server_id, resolve_data) = match &hint.resolve_state {
5120 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5121 ResolveState::Resolving => {
5122 return Some(ResolvedHint::Resolving(
5123 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5124 ));
5125 }
5126 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5127 };
5128
5129 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5130 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5131 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5132 id,
5133 cx.spawn(async move |lsp_store, cx| {
5134 let resolved_hint = resolve_task.await;
5135 lsp_store
5136 .update(cx, |lsp_store, _| {
5137 if let Some(old_inlay_hint) = lsp_store
5138 .lsp_data
5139 .get_mut(&buffer_id)
5140 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5141 {
5142 match resolved_hint {
5143 Ok(resolved_hint) => {
5144 *old_inlay_hint = resolved_hint;
5145 }
5146 Err(e) => {
5147 old_inlay_hint.resolve_state =
5148 ResolveState::CanResolve(server_id, resolve_data);
5149 log::error!("Inlay hint resolve failed: {e:#}");
5150 }
5151 }
5152 }
5153 })
5154 .ok();
5155 })
5156 .shared(),
5157 );
5158 debug_assert!(
5159 previous_task.is_none(),
5160 "Did not change hint's resolve state after spawning its resolve"
5161 );
5162 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5163 None
5164 }
5165
5166 fn resolve_inlay_hint(
5167 &self,
5168 mut hint: InlayHint,
5169 buffer: Entity<Buffer>,
5170 server_id: LanguageServerId,
5171 cx: &mut Context<Self>,
5172 ) -> Task<anyhow::Result<InlayHint>> {
5173 if let Some((upstream_client, project_id)) = self.upstream_client() {
5174 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5175 {
5176 hint.resolve_state = ResolveState::Resolved;
5177 return Task::ready(Ok(hint));
5178 }
5179 let request = proto::ResolveInlayHint {
5180 project_id,
5181 buffer_id: buffer.read(cx).remote_id().into(),
5182 language_server_id: server_id.0 as u64,
5183 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5184 };
5185 cx.background_spawn(async move {
5186 let response = upstream_client
5187 .request(request)
5188 .await
5189 .context("inlay hints proto request")?;
5190 match response.hint {
5191 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5192 .context("inlay hints proto resolve response conversion"),
5193 None => Ok(hint),
5194 }
5195 })
5196 } else {
5197 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5198 self.language_server_for_local_buffer(buffer, server_id, cx)
5199 .map(|(_, server)| server.clone())
5200 }) else {
5201 return Task::ready(Ok(hint));
5202 };
5203 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5204 return Task::ready(Ok(hint));
5205 }
5206 let buffer_snapshot = buffer.read(cx).snapshot();
5207 cx.spawn(async move |_, cx| {
5208 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5209 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5210 );
5211 let resolved_hint = resolve_task
5212 .await
5213 .into_response()
5214 .context("inlay hint resolve LSP request")?;
5215 let resolved_hint = InlayHints::lsp_to_project_hint(
5216 resolved_hint,
5217 &buffer,
5218 server_id,
5219 ResolveState::Resolved,
5220 false,
5221 cx,
5222 )
5223 .await?;
5224 Ok(resolved_hint)
5225 })
5226 }
5227 }
5228
5229 pub fn resolve_color_presentation(
5230 &mut self,
5231 mut color: DocumentColor,
5232 buffer: Entity<Buffer>,
5233 server_id: LanguageServerId,
5234 cx: &mut Context<Self>,
5235 ) -> Task<Result<DocumentColor>> {
5236 if color.resolved {
5237 return Task::ready(Ok(color));
5238 }
5239
5240 if let Some((upstream_client, project_id)) = self.upstream_client() {
5241 let start = color.lsp_range.start;
5242 let end = color.lsp_range.end;
5243 let request = proto::GetColorPresentation {
5244 project_id,
5245 server_id: server_id.to_proto(),
5246 buffer_id: buffer.read(cx).remote_id().into(),
5247 color: Some(proto::ColorInformation {
5248 red: color.color.red,
5249 green: color.color.green,
5250 blue: color.color.blue,
5251 alpha: color.color.alpha,
5252 lsp_range_start: Some(proto::PointUtf16 {
5253 row: start.line,
5254 column: start.character,
5255 }),
5256 lsp_range_end: Some(proto::PointUtf16 {
5257 row: end.line,
5258 column: end.character,
5259 }),
5260 }),
5261 };
5262 cx.background_spawn(async move {
5263 let response = upstream_client
5264 .request(request)
5265 .await
5266 .context("color presentation proto request")?;
5267 color.resolved = true;
5268 color.color_presentations = response
5269 .presentations
5270 .into_iter()
5271 .map(|presentation| ColorPresentation {
5272 label: SharedString::from(presentation.label),
5273 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5274 additional_text_edits: presentation
5275 .additional_text_edits
5276 .into_iter()
5277 .filter_map(deserialize_lsp_edit)
5278 .collect(),
5279 })
5280 .collect();
5281 Ok(color)
5282 })
5283 } else {
5284 let path = match buffer
5285 .update(cx, |buffer, cx| {
5286 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5287 })
5288 .context("buffer with the missing path")
5289 {
5290 Ok(path) => path,
5291 Err(e) => return Task::ready(Err(e)),
5292 };
5293 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5294 self.language_server_for_local_buffer(buffer, server_id, cx)
5295 .map(|(_, server)| server.clone())
5296 }) else {
5297 return Task::ready(Ok(color));
5298 };
5299 cx.background_spawn(async move {
5300 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5301 lsp::ColorPresentationParams {
5302 text_document: make_text_document_identifier(&path)?,
5303 color: color.color,
5304 range: color.lsp_range,
5305 work_done_progress_params: Default::default(),
5306 partial_result_params: Default::default(),
5307 },
5308 );
5309 color.color_presentations = resolve_task
5310 .await
5311 .into_response()
5312 .context("color presentation resolve LSP request")?
5313 .into_iter()
5314 .map(|presentation| ColorPresentation {
5315 label: SharedString::from(presentation.label),
5316 text_edit: presentation.text_edit,
5317 additional_text_edits: presentation
5318 .additional_text_edits
5319 .unwrap_or_default(),
5320 })
5321 .collect();
5322 color.resolved = true;
5323 Ok(color)
5324 })
5325 }
5326 }
5327
5328 pub(crate) fn linked_edits(
5329 &mut self,
5330 buffer: &Entity<Buffer>,
5331 position: Anchor,
5332 cx: &mut Context<Self>,
5333 ) -> Task<Result<Vec<Range<Anchor>>>> {
5334 let snapshot = buffer.read(cx).snapshot();
5335 let scope = snapshot.language_scope_at(position);
5336 let Some(server_id) = self
5337 .as_local()
5338 .and_then(|local| {
5339 buffer.update(cx, |buffer, cx| {
5340 local
5341 .language_servers_for_buffer(buffer, cx)
5342 .filter(|(_, server)| {
5343 LinkedEditingRange::check_server_capabilities(server.capabilities())
5344 })
5345 .filter(|(adapter, _)| {
5346 scope
5347 .as_ref()
5348 .map(|scope| scope.language_allowed(&adapter.name))
5349 .unwrap_or(true)
5350 })
5351 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5352 .next()
5353 })
5354 })
5355 .or_else(|| {
5356 self.upstream_client()
5357 .is_some()
5358 .then_some(LanguageServerToQuery::FirstCapable)
5359 })
5360 .filter(|_| {
5361 maybe!({
5362 let language = buffer.read(cx).language_at(position)?;
5363 Some(
5364 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5365 .linked_edits,
5366 )
5367 }) == Some(true)
5368 })
5369 else {
5370 return Task::ready(Ok(Vec::new()));
5371 };
5372
5373 self.request_lsp(
5374 buffer.clone(),
5375 server_id,
5376 LinkedEditingRange { position },
5377 cx,
5378 )
5379 }
5380
5381 fn apply_on_type_formatting(
5382 &mut self,
5383 buffer: Entity<Buffer>,
5384 position: Anchor,
5385 trigger: String,
5386 cx: &mut Context<Self>,
5387 ) -> Task<Result<Option<Transaction>>> {
5388 if let Some((client, project_id)) = self.upstream_client() {
5389 if !self.check_if_capable_for_proto_request(
5390 &buffer,
5391 |capabilities| {
5392 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5393 },
5394 cx,
5395 ) {
5396 return Task::ready(Ok(None));
5397 }
5398 let request = proto::OnTypeFormatting {
5399 project_id,
5400 buffer_id: buffer.read(cx).remote_id().into(),
5401 position: Some(serialize_anchor(&position)),
5402 trigger,
5403 version: serialize_version(&buffer.read(cx).version()),
5404 };
5405 cx.background_spawn(async move {
5406 client
5407 .request(request)
5408 .await?
5409 .transaction
5410 .map(language::proto::deserialize_transaction)
5411 .transpose()
5412 })
5413 } else if let Some(local) = self.as_local_mut() {
5414 let buffer_id = buffer.read(cx).remote_id();
5415 local.buffers_being_formatted.insert(buffer_id);
5416 cx.spawn(async move |this, cx| {
5417 let _cleanup = defer({
5418 let this = this.clone();
5419 let mut cx = cx.clone();
5420 move || {
5421 this.update(&mut cx, |this, _| {
5422 if let Some(local) = this.as_local_mut() {
5423 local.buffers_being_formatted.remove(&buffer_id);
5424 }
5425 })
5426 .ok();
5427 }
5428 });
5429
5430 buffer
5431 .update(cx, |buffer, _| {
5432 buffer.wait_for_edits(Some(position.timestamp))
5433 })?
5434 .await?;
5435 this.update(cx, |this, cx| {
5436 let position = position.to_point_utf16(buffer.read(cx));
5437 this.on_type_format(buffer, position, trigger, false, cx)
5438 })?
5439 .await
5440 })
5441 } else {
5442 Task::ready(Err(anyhow!("No upstream client or local language server")))
5443 }
5444 }
5445
5446 pub fn on_type_format<T: ToPointUtf16>(
5447 &mut self,
5448 buffer: Entity<Buffer>,
5449 position: T,
5450 trigger: String,
5451 push_to_history: bool,
5452 cx: &mut Context<Self>,
5453 ) -> Task<Result<Option<Transaction>>> {
5454 let position = position.to_point_utf16(buffer.read(cx));
5455 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5456 }
5457
5458 fn on_type_format_impl(
5459 &mut self,
5460 buffer: Entity<Buffer>,
5461 position: PointUtf16,
5462 trigger: String,
5463 push_to_history: bool,
5464 cx: &mut Context<Self>,
5465 ) -> Task<Result<Option<Transaction>>> {
5466 let options = buffer.update(cx, |buffer, cx| {
5467 lsp_command::lsp_formatting_options(
5468 language_settings(
5469 buffer.language_at(position).map(|l| l.name()),
5470 buffer.file(),
5471 cx,
5472 )
5473 .as_ref(),
5474 )
5475 });
5476
5477 cx.spawn(async move |this, cx| {
5478 if let Some(waiter) =
5479 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5480 {
5481 waiter.await?;
5482 }
5483 cx.update(|cx| {
5484 this.update(cx, |this, cx| {
5485 this.request_lsp(
5486 buffer.clone(),
5487 LanguageServerToQuery::FirstCapable,
5488 OnTypeFormatting {
5489 position,
5490 trigger,
5491 options,
5492 push_to_history,
5493 },
5494 cx,
5495 )
5496 })
5497 })??
5498 .await
5499 })
5500 }
5501
5502 pub fn definitions(
5503 &mut self,
5504 buffer: &Entity<Buffer>,
5505 position: PointUtf16,
5506 cx: &mut Context<Self>,
5507 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5508 if let Some((upstream_client, project_id)) = self.upstream_client() {
5509 let request = GetDefinitions { position };
5510 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5511 return Task::ready(Ok(None));
5512 }
5513 let request_task = upstream_client.request_lsp(
5514 project_id,
5515 None,
5516 LSP_REQUEST_TIMEOUT,
5517 cx.background_executor().clone(),
5518 request.to_proto(project_id, buffer.read(cx)),
5519 );
5520 let buffer = buffer.clone();
5521 cx.spawn(async move |weak_lsp_store, cx| {
5522 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5523 return Ok(None);
5524 };
5525 let Some(responses) = request_task.await? else {
5526 return Ok(None);
5527 };
5528 let actions = join_all(responses.payload.into_iter().map(|response| {
5529 GetDefinitions { position }.response_from_proto(
5530 response.response,
5531 lsp_store.clone(),
5532 buffer.clone(),
5533 cx.clone(),
5534 )
5535 }))
5536 .await;
5537
5538 Ok(Some(
5539 actions
5540 .into_iter()
5541 .collect::<Result<Vec<Vec<_>>>>()?
5542 .into_iter()
5543 .flatten()
5544 .dedup()
5545 .collect(),
5546 ))
5547 })
5548 } else {
5549 let definitions_task = self.request_multiple_lsp_locally(
5550 buffer,
5551 Some(position),
5552 GetDefinitions { position },
5553 cx,
5554 );
5555 cx.background_spawn(async move {
5556 Ok(Some(
5557 definitions_task
5558 .await
5559 .into_iter()
5560 .flat_map(|(_, definitions)| definitions)
5561 .dedup()
5562 .collect(),
5563 ))
5564 })
5565 }
5566 }
5567
5568 pub fn declarations(
5569 &mut self,
5570 buffer: &Entity<Buffer>,
5571 position: PointUtf16,
5572 cx: &mut Context<Self>,
5573 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5574 if let Some((upstream_client, project_id)) = self.upstream_client() {
5575 let request = GetDeclarations { position };
5576 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5577 return Task::ready(Ok(None));
5578 }
5579 let request_task = upstream_client.request_lsp(
5580 project_id,
5581 None,
5582 LSP_REQUEST_TIMEOUT,
5583 cx.background_executor().clone(),
5584 request.to_proto(project_id, buffer.read(cx)),
5585 );
5586 let buffer = buffer.clone();
5587 cx.spawn(async move |weak_lsp_store, cx| {
5588 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5589 return Ok(None);
5590 };
5591 let Some(responses) = request_task.await? else {
5592 return Ok(None);
5593 };
5594 let actions = join_all(responses.payload.into_iter().map(|response| {
5595 GetDeclarations { position }.response_from_proto(
5596 response.response,
5597 lsp_store.clone(),
5598 buffer.clone(),
5599 cx.clone(),
5600 )
5601 }))
5602 .await;
5603
5604 Ok(Some(
5605 actions
5606 .into_iter()
5607 .collect::<Result<Vec<Vec<_>>>>()?
5608 .into_iter()
5609 .flatten()
5610 .dedup()
5611 .collect(),
5612 ))
5613 })
5614 } else {
5615 let declarations_task = self.request_multiple_lsp_locally(
5616 buffer,
5617 Some(position),
5618 GetDeclarations { position },
5619 cx,
5620 );
5621 cx.background_spawn(async move {
5622 Ok(Some(
5623 declarations_task
5624 .await
5625 .into_iter()
5626 .flat_map(|(_, declarations)| declarations)
5627 .dedup()
5628 .collect(),
5629 ))
5630 })
5631 }
5632 }
5633
5634 pub fn type_definitions(
5635 &mut self,
5636 buffer: &Entity<Buffer>,
5637 position: PointUtf16,
5638 cx: &mut Context<Self>,
5639 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5640 if let Some((upstream_client, project_id)) = self.upstream_client() {
5641 let request = GetTypeDefinitions { position };
5642 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5643 return Task::ready(Ok(None));
5644 }
5645 let request_task = upstream_client.request_lsp(
5646 project_id,
5647 None,
5648 LSP_REQUEST_TIMEOUT,
5649 cx.background_executor().clone(),
5650 request.to_proto(project_id, buffer.read(cx)),
5651 );
5652 let buffer = buffer.clone();
5653 cx.spawn(async move |weak_lsp_store, cx| {
5654 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5655 return Ok(None);
5656 };
5657 let Some(responses) = request_task.await? else {
5658 return Ok(None);
5659 };
5660 let actions = join_all(responses.payload.into_iter().map(|response| {
5661 GetTypeDefinitions { position }.response_from_proto(
5662 response.response,
5663 lsp_store.clone(),
5664 buffer.clone(),
5665 cx.clone(),
5666 )
5667 }))
5668 .await;
5669
5670 Ok(Some(
5671 actions
5672 .into_iter()
5673 .collect::<Result<Vec<Vec<_>>>>()?
5674 .into_iter()
5675 .flatten()
5676 .dedup()
5677 .collect(),
5678 ))
5679 })
5680 } else {
5681 let type_definitions_task = self.request_multiple_lsp_locally(
5682 buffer,
5683 Some(position),
5684 GetTypeDefinitions { position },
5685 cx,
5686 );
5687 cx.background_spawn(async move {
5688 Ok(Some(
5689 type_definitions_task
5690 .await
5691 .into_iter()
5692 .flat_map(|(_, type_definitions)| type_definitions)
5693 .dedup()
5694 .collect(),
5695 ))
5696 })
5697 }
5698 }
5699
5700 pub fn implementations(
5701 &mut self,
5702 buffer: &Entity<Buffer>,
5703 position: PointUtf16,
5704 cx: &mut Context<Self>,
5705 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5706 if let Some((upstream_client, project_id)) = self.upstream_client() {
5707 let request = GetImplementations { position };
5708 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5709 return Task::ready(Ok(None));
5710 }
5711 let request_task = upstream_client.request_lsp(
5712 project_id,
5713 None,
5714 LSP_REQUEST_TIMEOUT,
5715 cx.background_executor().clone(),
5716 request.to_proto(project_id, buffer.read(cx)),
5717 );
5718 let buffer = buffer.clone();
5719 cx.spawn(async move |weak_lsp_store, cx| {
5720 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5721 return Ok(None);
5722 };
5723 let Some(responses) = request_task.await? else {
5724 return Ok(None);
5725 };
5726 let actions = join_all(responses.payload.into_iter().map(|response| {
5727 GetImplementations { position }.response_from_proto(
5728 response.response,
5729 lsp_store.clone(),
5730 buffer.clone(),
5731 cx.clone(),
5732 )
5733 }))
5734 .await;
5735
5736 Ok(Some(
5737 actions
5738 .into_iter()
5739 .collect::<Result<Vec<Vec<_>>>>()?
5740 .into_iter()
5741 .flatten()
5742 .dedup()
5743 .collect(),
5744 ))
5745 })
5746 } else {
5747 let implementations_task = self.request_multiple_lsp_locally(
5748 buffer,
5749 Some(position),
5750 GetImplementations { position },
5751 cx,
5752 );
5753 cx.background_spawn(async move {
5754 Ok(Some(
5755 implementations_task
5756 .await
5757 .into_iter()
5758 .flat_map(|(_, implementations)| implementations)
5759 .dedup()
5760 .collect(),
5761 ))
5762 })
5763 }
5764 }
5765
5766 pub fn references(
5767 &mut self,
5768 buffer: &Entity<Buffer>,
5769 position: PointUtf16,
5770 cx: &mut Context<Self>,
5771 ) -> Task<Result<Option<Vec<Location>>>> {
5772 if let Some((upstream_client, project_id)) = self.upstream_client() {
5773 let request = GetReferences { position };
5774 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5775 return Task::ready(Ok(None));
5776 }
5777
5778 let request_task = upstream_client.request_lsp(
5779 project_id,
5780 None,
5781 LSP_REQUEST_TIMEOUT,
5782 cx.background_executor().clone(),
5783 request.to_proto(project_id, buffer.read(cx)),
5784 );
5785 let buffer = buffer.clone();
5786 cx.spawn(async move |weak_lsp_store, cx| {
5787 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5788 return Ok(None);
5789 };
5790 let Some(responses) = request_task.await? else {
5791 return Ok(None);
5792 };
5793
5794 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5795 GetReferences { position }.response_from_proto(
5796 lsp_response.response,
5797 lsp_store.clone(),
5798 buffer.clone(),
5799 cx.clone(),
5800 )
5801 }))
5802 .await
5803 .into_iter()
5804 .collect::<Result<Vec<Vec<_>>>>()?
5805 .into_iter()
5806 .flatten()
5807 .dedup()
5808 .collect();
5809 Ok(Some(locations))
5810 })
5811 } else {
5812 let references_task = self.request_multiple_lsp_locally(
5813 buffer,
5814 Some(position),
5815 GetReferences { position },
5816 cx,
5817 );
5818 cx.background_spawn(async move {
5819 Ok(Some(
5820 references_task
5821 .await
5822 .into_iter()
5823 .flat_map(|(_, references)| references)
5824 .dedup()
5825 .collect(),
5826 ))
5827 })
5828 }
5829 }
5830
5831 pub fn code_actions(
5832 &mut self,
5833 buffer: &Entity<Buffer>,
5834 range: Range<Anchor>,
5835 kinds: Option<Vec<CodeActionKind>>,
5836 cx: &mut Context<Self>,
5837 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5838 if let Some((upstream_client, project_id)) = self.upstream_client() {
5839 let request = GetCodeActions {
5840 range: range.clone(),
5841 kinds: kinds.clone(),
5842 };
5843 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5844 return Task::ready(Ok(None));
5845 }
5846 let request_task = upstream_client.request_lsp(
5847 project_id,
5848 None,
5849 LSP_REQUEST_TIMEOUT,
5850 cx.background_executor().clone(),
5851 request.to_proto(project_id, buffer.read(cx)),
5852 );
5853 let buffer = buffer.clone();
5854 cx.spawn(async move |weak_lsp_store, cx| {
5855 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5856 return Ok(None);
5857 };
5858 let Some(responses) = request_task.await? else {
5859 return Ok(None);
5860 };
5861 let actions = join_all(responses.payload.into_iter().map(|response| {
5862 GetCodeActions {
5863 range: range.clone(),
5864 kinds: kinds.clone(),
5865 }
5866 .response_from_proto(
5867 response.response,
5868 lsp_store.clone(),
5869 buffer.clone(),
5870 cx.clone(),
5871 )
5872 }))
5873 .await;
5874
5875 Ok(Some(
5876 actions
5877 .into_iter()
5878 .collect::<Result<Vec<Vec<_>>>>()?
5879 .into_iter()
5880 .flatten()
5881 .collect(),
5882 ))
5883 })
5884 } else {
5885 let all_actions_task = self.request_multiple_lsp_locally(
5886 buffer,
5887 Some(range.start),
5888 GetCodeActions { range, kinds },
5889 cx,
5890 );
5891 cx.background_spawn(async move {
5892 Ok(Some(
5893 all_actions_task
5894 .await
5895 .into_iter()
5896 .flat_map(|(_, actions)| actions)
5897 .collect(),
5898 ))
5899 })
5900 }
5901 }
5902
5903 pub fn code_lens_actions(
5904 &mut self,
5905 buffer: &Entity<Buffer>,
5906 cx: &mut Context<Self>,
5907 ) -> CodeLensTask {
5908 let version_queried_for = buffer.read(cx).version();
5909 let buffer_id = buffer.read(cx).remote_id();
5910 let existing_servers = self.as_local().map(|local| {
5911 local
5912 .buffers_opened_in_servers
5913 .get(&buffer_id)
5914 .cloned()
5915 .unwrap_or_default()
5916 });
5917
5918 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5919 if let Some(cached_lens) = &lsp_data.code_lens {
5920 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5921 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5922 existing_servers != cached_lens.lens.keys().copied().collect()
5923 });
5924 if !has_different_servers {
5925 return Task::ready(Ok(Some(
5926 cached_lens.lens.values().flatten().cloned().collect(),
5927 )))
5928 .shared();
5929 }
5930 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5931 if !version_queried_for.changed_since(updating_for) {
5932 return running_update.clone();
5933 }
5934 }
5935 }
5936 }
5937
5938 let lens_lsp_data = self
5939 .latest_lsp_data(buffer, cx)
5940 .code_lens
5941 .get_or_insert_default();
5942 let buffer = buffer.clone();
5943 let query_version_queried_for = version_queried_for.clone();
5944 let new_task = cx
5945 .spawn(async move |lsp_store, cx| {
5946 cx.background_executor()
5947 .timer(Duration::from_millis(30))
5948 .await;
5949 let fetched_lens = lsp_store
5950 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5951 .map_err(Arc::new)?
5952 .await
5953 .context("fetching code lens")
5954 .map_err(Arc::new);
5955 let fetched_lens = match fetched_lens {
5956 Ok(fetched_lens) => fetched_lens,
5957 Err(e) => {
5958 lsp_store
5959 .update(cx, |lsp_store, _| {
5960 if let Some(lens_lsp_data) = lsp_store
5961 .lsp_data
5962 .get_mut(&buffer_id)
5963 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5964 {
5965 lens_lsp_data.update = None;
5966 }
5967 })
5968 .ok();
5969 return Err(e);
5970 }
5971 };
5972
5973 lsp_store
5974 .update(cx, |lsp_store, _| {
5975 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5976 let code_lens = lsp_data.code_lens.as_mut()?;
5977 if let Some(fetched_lens) = fetched_lens {
5978 if lsp_data.buffer_version == query_version_queried_for {
5979 code_lens.lens.extend(fetched_lens);
5980 } else if !lsp_data
5981 .buffer_version
5982 .changed_since(&query_version_queried_for)
5983 {
5984 lsp_data.buffer_version = query_version_queried_for;
5985 code_lens.lens = fetched_lens;
5986 }
5987 }
5988 code_lens.update = None;
5989 Some(code_lens.lens.values().flatten().cloned().collect())
5990 })
5991 .map_err(Arc::new)
5992 })
5993 .shared();
5994 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5995 new_task
5996 }
5997
5998 fn fetch_code_lens(
5999 &mut self,
6000 buffer: &Entity<Buffer>,
6001 cx: &mut Context<Self>,
6002 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6003 if let Some((upstream_client, project_id)) = self.upstream_client() {
6004 let request = GetCodeLens;
6005 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6006 return Task::ready(Ok(None));
6007 }
6008 let request_task = upstream_client.request_lsp(
6009 project_id,
6010 None,
6011 LSP_REQUEST_TIMEOUT,
6012 cx.background_executor().clone(),
6013 request.to_proto(project_id, buffer.read(cx)),
6014 );
6015 let buffer = buffer.clone();
6016 cx.spawn(async move |weak_lsp_store, cx| {
6017 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6018 return Ok(None);
6019 };
6020 let Some(responses) = request_task.await? else {
6021 return Ok(None);
6022 };
6023
6024 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6025 let lsp_store = lsp_store.clone();
6026 let buffer = buffer.clone();
6027 let cx = cx.clone();
6028 async move {
6029 (
6030 LanguageServerId::from_proto(response.server_id),
6031 GetCodeLens
6032 .response_from_proto(response.response, lsp_store, buffer, cx)
6033 .await,
6034 )
6035 }
6036 }))
6037 .await;
6038
6039 let mut has_errors = false;
6040 let code_lens_actions = code_lens_actions
6041 .into_iter()
6042 .filter_map(|(server_id, code_lens)| match code_lens {
6043 Ok(code_lens) => Some((server_id, code_lens)),
6044 Err(e) => {
6045 has_errors = true;
6046 log::error!("{e:#}");
6047 None
6048 }
6049 })
6050 .collect::<HashMap<_, _>>();
6051 anyhow::ensure!(
6052 !has_errors || !code_lens_actions.is_empty(),
6053 "Failed to fetch code lens"
6054 );
6055 Ok(Some(code_lens_actions))
6056 })
6057 } else {
6058 let code_lens_actions_task =
6059 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6060 cx.background_spawn(async move {
6061 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6062 })
6063 }
6064 }
6065
6066 #[inline(never)]
6067 pub fn completions(
6068 &self,
6069 buffer: &Entity<Buffer>,
6070 position: PointUtf16,
6071 context: CompletionContext,
6072 cx: &mut Context<Self>,
6073 ) -> Task<Result<Vec<CompletionResponse>>> {
6074 let language_registry = self.languages.clone();
6075
6076 if let Some((upstream_client, project_id)) = self.upstream_client() {
6077 let snapshot = buffer.read(cx).snapshot();
6078 let offset = position.to_offset(&snapshot);
6079 let scope = snapshot.language_scope_at(offset);
6080 let capable_lsps = self.all_capable_for_proto_request(
6081 buffer,
6082 |server_name, capabilities| {
6083 capabilities.completion_provider.is_some()
6084 && scope
6085 .as_ref()
6086 .map(|scope| scope.language_allowed(server_name))
6087 .unwrap_or(true)
6088 },
6089 cx,
6090 );
6091 if capable_lsps.is_empty() {
6092 return Task::ready(Ok(Vec::new()));
6093 }
6094
6095 let language = buffer.read(cx).language().cloned();
6096
6097 // In the future, we should provide project guests with the names of LSP adapters,
6098 // so that they can use the correct LSP adapter when computing labels. For now,
6099 // guests just use the first LSP adapter associated with the buffer's language.
6100 let lsp_adapter = language.as_ref().and_then(|language| {
6101 language_registry
6102 .lsp_adapters(&language.name())
6103 .first()
6104 .cloned()
6105 });
6106
6107 let buffer = buffer.clone();
6108
6109 cx.spawn(async move |this, cx| {
6110 let requests = join_all(
6111 capable_lsps
6112 .into_iter()
6113 .map(|id| {
6114 let request = GetCompletions {
6115 position,
6116 context: context.clone(),
6117 server_id: Some(id),
6118 };
6119 let buffer = buffer.clone();
6120 let language = language.clone();
6121 let lsp_adapter = lsp_adapter.clone();
6122 let upstream_client = upstream_client.clone();
6123 let response = this
6124 .update(cx, |this, cx| {
6125 this.send_lsp_proto_request(
6126 buffer,
6127 upstream_client,
6128 project_id,
6129 request,
6130 cx,
6131 )
6132 })
6133 .log_err();
6134 async move {
6135 let response = response?.await.log_err()?;
6136
6137 let completions = populate_labels_for_completions(
6138 response.completions,
6139 language,
6140 lsp_adapter,
6141 )
6142 .await;
6143
6144 Some(CompletionResponse {
6145 completions,
6146 display_options: CompletionDisplayOptions::default(),
6147 is_incomplete: response.is_incomplete,
6148 })
6149 }
6150 })
6151 .collect::<Vec<_>>(),
6152 );
6153 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6154 })
6155 } else if let Some(local) = self.as_local() {
6156 let snapshot = buffer.read(cx).snapshot();
6157 let offset = position.to_offset(&snapshot);
6158 let scope = snapshot.language_scope_at(offset);
6159 let language = snapshot.language().cloned();
6160 let completion_settings = language_settings(
6161 language.as_ref().map(|language| language.name()),
6162 buffer.read(cx).file(),
6163 cx,
6164 )
6165 .completions
6166 .clone();
6167 if !completion_settings.lsp {
6168 return Task::ready(Ok(Vec::new()));
6169 }
6170
6171 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6172 local
6173 .language_servers_for_buffer(buffer, cx)
6174 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6175 .filter(|(adapter, _)| {
6176 scope
6177 .as_ref()
6178 .map(|scope| scope.language_allowed(&adapter.name))
6179 .unwrap_or(true)
6180 })
6181 .map(|(_, server)| server.server_id())
6182 .collect()
6183 });
6184
6185 let buffer = buffer.clone();
6186 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6187 let lsp_timeout = if lsp_timeout > 0 {
6188 Some(Duration::from_millis(lsp_timeout))
6189 } else {
6190 None
6191 };
6192 cx.spawn(async move |this, cx| {
6193 let mut tasks = Vec::with_capacity(server_ids.len());
6194 this.update(cx, |lsp_store, cx| {
6195 for server_id in server_ids {
6196 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6197 let lsp_timeout = lsp_timeout
6198 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6199 let mut timeout = cx.background_spawn(async move {
6200 match lsp_timeout {
6201 Some(lsp_timeout) => {
6202 lsp_timeout.await;
6203 true
6204 },
6205 None => false,
6206 }
6207 }).fuse();
6208 let mut lsp_request = lsp_store.request_lsp(
6209 buffer.clone(),
6210 LanguageServerToQuery::Other(server_id),
6211 GetCompletions {
6212 position,
6213 context: context.clone(),
6214 server_id: Some(server_id),
6215 },
6216 cx,
6217 ).fuse();
6218 let new_task = cx.background_spawn(async move {
6219 select_biased! {
6220 response = lsp_request => anyhow::Ok(Some(response?)),
6221 timeout_happened = timeout => {
6222 if timeout_happened {
6223 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6224 Ok(None)
6225 } else {
6226 let completions = lsp_request.await?;
6227 Ok(Some(completions))
6228 }
6229 },
6230 }
6231 });
6232 tasks.push((lsp_adapter, new_task));
6233 }
6234 })?;
6235
6236 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6237 let completion_response = task.await.ok()??;
6238 let completions = populate_labels_for_completions(
6239 completion_response.completions,
6240 language.clone(),
6241 lsp_adapter,
6242 )
6243 .await;
6244 Some(CompletionResponse {
6245 completions,
6246 display_options: CompletionDisplayOptions::default(),
6247 is_incomplete: completion_response.is_incomplete,
6248 })
6249 });
6250
6251 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6252
6253 Ok(responses.into_iter().flatten().collect())
6254 })
6255 } else {
6256 Task::ready(Err(anyhow!("No upstream client or local language server")))
6257 }
6258 }
6259
6260 pub fn resolve_completions(
6261 &self,
6262 buffer: Entity<Buffer>,
6263 completion_indices: Vec<usize>,
6264 completions: Rc<RefCell<Box<[Completion]>>>,
6265 cx: &mut Context<Self>,
6266 ) -> Task<Result<bool>> {
6267 let client = self.upstream_client();
6268 let buffer_id = buffer.read(cx).remote_id();
6269 let buffer_snapshot = buffer.read(cx).snapshot();
6270
6271 if !self.check_if_capable_for_proto_request(
6272 &buffer,
6273 GetCompletions::can_resolve_completions,
6274 cx,
6275 ) {
6276 return Task::ready(Ok(false));
6277 }
6278 cx.spawn(async move |lsp_store, cx| {
6279 let mut did_resolve = false;
6280 if let Some((client, project_id)) = client {
6281 for completion_index in completion_indices {
6282 let server_id = {
6283 let completion = &completions.borrow()[completion_index];
6284 completion.source.server_id()
6285 };
6286 if let Some(server_id) = server_id {
6287 if Self::resolve_completion_remote(
6288 project_id,
6289 server_id,
6290 buffer_id,
6291 completions.clone(),
6292 completion_index,
6293 client.clone(),
6294 )
6295 .await
6296 .log_err()
6297 .is_some()
6298 {
6299 did_resolve = true;
6300 }
6301 } else {
6302 resolve_word_completion(
6303 &buffer_snapshot,
6304 &mut completions.borrow_mut()[completion_index],
6305 );
6306 }
6307 }
6308 } else {
6309 for completion_index in completion_indices {
6310 let server_id = {
6311 let completion = &completions.borrow()[completion_index];
6312 completion.source.server_id()
6313 };
6314 if let Some(server_id) = server_id {
6315 let server_and_adapter = lsp_store
6316 .read_with(cx, |lsp_store, _| {
6317 let server = lsp_store.language_server_for_id(server_id)?;
6318 let adapter =
6319 lsp_store.language_server_adapter_for_id(server.server_id())?;
6320 Some((server, adapter))
6321 })
6322 .ok()
6323 .flatten();
6324 let Some((server, adapter)) = server_and_adapter else {
6325 continue;
6326 };
6327
6328 let resolved = Self::resolve_completion_local(
6329 server,
6330 completions.clone(),
6331 completion_index,
6332 )
6333 .await
6334 .log_err()
6335 .is_some();
6336 if resolved {
6337 Self::regenerate_completion_labels(
6338 adapter,
6339 &buffer_snapshot,
6340 completions.clone(),
6341 completion_index,
6342 )
6343 .await
6344 .log_err();
6345 did_resolve = true;
6346 }
6347 } else {
6348 resolve_word_completion(
6349 &buffer_snapshot,
6350 &mut completions.borrow_mut()[completion_index],
6351 );
6352 }
6353 }
6354 }
6355
6356 Ok(did_resolve)
6357 })
6358 }
6359
6360 async fn resolve_completion_local(
6361 server: Arc<lsp::LanguageServer>,
6362 completions: Rc<RefCell<Box<[Completion]>>>,
6363 completion_index: usize,
6364 ) -> Result<()> {
6365 let server_id = server.server_id();
6366 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6367 return Ok(());
6368 }
6369
6370 let request = {
6371 let completion = &completions.borrow()[completion_index];
6372 match &completion.source {
6373 CompletionSource::Lsp {
6374 lsp_completion,
6375 resolved,
6376 server_id: completion_server_id,
6377 ..
6378 } => {
6379 if *resolved {
6380 return Ok(());
6381 }
6382 anyhow::ensure!(
6383 server_id == *completion_server_id,
6384 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6385 );
6386 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6387 }
6388 CompletionSource::BufferWord { .. }
6389 | CompletionSource::Dap { .. }
6390 | CompletionSource::Custom => {
6391 return Ok(());
6392 }
6393 }
6394 };
6395 let resolved_completion = request
6396 .await
6397 .into_response()
6398 .context("resolve completion")?;
6399
6400 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6401 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6402
6403 let mut completions = completions.borrow_mut();
6404 let completion = &mut completions[completion_index];
6405 if let CompletionSource::Lsp {
6406 lsp_completion,
6407 resolved,
6408 server_id: completion_server_id,
6409 ..
6410 } = &mut completion.source
6411 {
6412 if *resolved {
6413 return Ok(());
6414 }
6415 anyhow::ensure!(
6416 server_id == *completion_server_id,
6417 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6418 );
6419 *lsp_completion = Box::new(resolved_completion);
6420 *resolved = true;
6421 }
6422 Ok(())
6423 }
6424
6425 async fn regenerate_completion_labels(
6426 adapter: Arc<CachedLspAdapter>,
6427 snapshot: &BufferSnapshot,
6428 completions: Rc<RefCell<Box<[Completion]>>>,
6429 completion_index: usize,
6430 ) -> Result<()> {
6431 let completion_item = completions.borrow()[completion_index]
6432 .source
6433 .lsp_completion(true)
6434 .map(Cow::into_owned);
6435 if let Some(lsp_documentation) = completion_item
6436 .as_ref()
6437 .and_then(|completion_item| completion_item.documentation.clone())
6438 {
6439 let mut completions = completions.borrow_mut();
6440 let completion = &mut completions[completion_index];
6441 completion.documentation = Some(lsp_documentation.into());
6442 } else {
6443 let mut completions = completions.borrow_mut();
6444 let completion = &mut completions[completion_index];
6445 completion.documentation = Some(CompletionDocumentation::Undocumented);
6446 }
6447
6448 let mut new_label = match completion_item {
6449 Some(completion_item) => {
6450 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6451 // So we have to update the label here anyway...
6452 let language = snapshot.language();
6453 match language {
6454 Some(language) => {
6455 adapter
6456 .labels_for_completions(
6457 std::slice::from_ref(&completion_item),
6458 language,
6459 )
6460 .await?
6461 }
6462 None => Vec::new(),
6463 }
6464 .pop()
6465 .flatten()
6466 .unwrap_or_else(|| {
6467 CodeLabel::fallback_for_completion(
6468 &completion_item,
6469 language.map(|language| language.as_ref()),
6470 )
6471 })
6472 }
6473 None => CodeLabel::plain(
6474 completions.borrow()[completion_index].new_text.clone(),
6475 None,
6476 ),
6477 };
6478 ensure_uniform_list_compatible_label(&mut new_label);
6479
6480 let mut completions = completions.borrow_mut();
6481 let completion = &mut completions[completion_index];
6482 if completion.label.filter_text() == new_label.filter_text() {
6483 completion.label = new_label;
6484 } else {
6485 log::error!(
6486 "Resolved completion changed display label from {} to {}. \
6487 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6488 completion.label.text(),
6489 new_label.text(),
6490 completion.label.filter_text(),
6491 new_label.filter_text()
6492 );
6493 }
6494
6495 Ok(())
6496 }
6497
6498 async fn resolve_completion_remote(
6499 project_id: u64,
6500 server_id: LanguageServerId,
6501 buffer_id: BufferId,
6502 completions: Rc<RefCell<Box<[Completion]>>>,
6503 completion_index: usize,
6504 client: AnyProtoClient,
6505 ) -> Result<()> {
6506 let lsp_completion = {
6507 let completion = &completions.borrow()[completion_index];
6508 match &completion.source {
6509 CompletionSource::Lsp {
6510 lsp_completion,
6511 resolved,
6512 server_id: completion_server_id,
6513 ..
6514 } => {
6515 anyhow::ensure!(
6516 server_id == *completion_server_id,
6517 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6518 );
6519 if *resolved {
6520 return Ok(());
6521 }
6522 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6523 }
6524 CompletionSource::Custom
6525 | CompletionSource::Dap { .. }
6526 | CompletionSource::BufferWord { .. } => {
6527 return Ok(());
6528 }
6529 }
6530 };
6531 let request = proto::ResolveCompletionDocumentation {
6532 project_id,
6533 language_server_id: server_id.0 as u64,
6534 lsp_completion,
6535 buffer_id: buffer_id.into(),
6536 };
6537
6538 let response = client
6539 .request(request)
6540 .await
6541 .context("completion documentation resolve proto request")?;
6542 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6543
6544 let documentation = if response.documentation.is_empty() {
6545 CompletionDocumentation::Undocumented
6546 } else if response.documentation_is_markdown {
6547 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6548 } else if response.documentation.lines().count() <= 1 {
6549 CompletionDocumentation::SingleLine(response.documentation.into())
6550 } else {
6551 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6552 };
6553
6554 let mut completions = completions.borrow_mut();
6555 let completion = &mut completions[completion_index];
6556 completion.documentation = Some(documentation);
6557 if let CompletionSource::Lsp {
6558 insert_range,
6559 lsp_completion,
6560 resolved,
6561 server_id: completion_server_id,
6562 lsp_defaults: _,
6563 } = &mut completion.source
6564 {
6565 let completion_insert_range = response
6566 .old_insert_start
6567 .and_then(deserialize_anchor)
6568 .zip(response.old_insert_end.and_then(deserialize_anchor));
6569 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6570
6571 if *resolved {
6572 return Ok(());
6573 }
6574 anyhow::ensure!(
6575 server_id == *completion_server_id,
6576 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6577 );
6578 *lsp_completion = Box::new(resolved_lsp_completion);
6579 *resolved = true;
6580 }
6581
6582 let replace_range = response
6583 .old_replace_start
6584 .and_then(deserialize_anchor)
6585 .zip(response.old_replace_end.and_then(deserialize_anchor));
6586 if let Some((old_replace_start, old_replace_end)) = replace_range
6587 && !response.new_text.is_empty()
6588 {
6589 completion.new_text = response.new_text;
6590 completion.replace_range = old_replace_start..old_replace_end;
6591 }
6592
6593 Ok(())
6594 }
6595
6596 pub fn apply_additional_edits_for_completion(
6597 &self,
6598 buffer_handle: Entity<Buffer>,
6599 completions: Rc<RefCell<Box<[Completion]>>>,
6600 completion_index: usize,
6601 push_to_history: bool,
6602 cx: &mut Context<Self>,
6603 ) -> Task<Result<Option<Transaction>>> {
6604 if let Some((client, project_id)) = self.upstream_client() {
6605 let buffer = buffer_handle.read(cx);
6606 let buffer_id = buffer.remote_id();
6607 cx.spawn(async move |_, cx| {
6608 let request = {
6609 let completion = completions.borrow()[completion_index].clone();
6610 proto::ApplyCompletionAdditionalEdits {
6611 project_id,
6612 buffer_id: buffer_id.into(),
6613 completion: Some(Self::serialize_completion(&CoreCompletion {
6614 replace_range: completion.replace_range,
6615 new_text: completion.new_text,
6616 source: completion.source,
6617 })),
6618 }
6619 };
6620
6621 if let Some(transaction) = client.request(request).await?.transaction {
6622 let transaction = language::proto::deserialize_transaction(transaction)?;
6623 buffer_handle
6624 .update(cx, |buffer, _| {
6625 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6626 })?
6627 .await?;
6628 if push_to_history {
6629 buffer_handle.update(cx, |buffer, _| {
6630 buffer.push_transaction(transaction.clone(), Instant::now());
6631 buffer.finalize_last_transaction();
6632 })?;
6633 }
6634 Ok(Some(transaction))
6635 } else {
6636 Ok(None)
6637 }
6638 })
6639 } else {
6640 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6641 let completion = &completions.borrow()[completion_index];
6642 let server_id = completion.source.server_id()?;
6643 Some(
6644 self.language_server_for_local_buffer(buffer, server_id, cx)?
6645 .1
6646 .clone(),
6647 )
6648 }) else {
6649 return Task::ready(Ok(None));
6650 };
6651
6652 cx.spawn(async move |this, cx| {
6653 Self::resolve_completion_local(
6654 server.clone(),
6655 completions.clone(),
6656 completion_index,
6657 )
6658 .await
6659 .context("resolving completion")?;
6660 let completion = completions.borrow()[completion_index].clone();
6661 let additional_text_edits = completion
6662 .source
6663 .lsp_completion(true)
6664 .as_ref()
6665 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6666 if let Some(edits) = additional_text_edits {
6667 let edits = this
6668 .update(cx, |this, cx| {
6669 this.as_local_mut().unwrap().edits_from_lsp(
6670 &buffer_handle,
6671 edits,
6672 server.server_id(),
6673 None,
6674 cx,
6675 )
6676 })?
6677 .await?;
6678
6679 buffer_handle.update(cx, |buffer, cx| {
6680 buffer.finalize_last_transaction();
6681 buffer.start_transaction();
6682
6683 for (range, text) in edits {
6684 let primary = &completion.replace_range;
6685
6686 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6687 // and the primary completion is just an insertion (empty range), then this is likely
6688 // an auto-import scenario and should not be considered overlapping
6689 // https://github.com/zed-industries/zed/issues/26136
6690 let is_file_start_auto_import = {
6691 let snapshot = buffer.snapshot();
6692 let primary_start_point = primary.start.to_point(&snapshot);
6693 let range_start_point = range.start.to_point(&snapshot);
6694
6695 let result = primary_start_point.row == 0
6696 && primary_start_point.column == 0
6697 && range_start_point.row == 0
6698 && range_start_point.column == 0;
6699
6700 result
6701 };
6702
6703 let has_overlap = if is_file_start_auto_import {
6704 false
6705 } else {
6706 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6707 && primary.end.cmp(&range.start, buffer).is_ge();
6708 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6709 && range.end.cmp(&primary.end, buffer).is_ge();
6710 let result = start_within || end_within;
6711 result
6712 };
6713
6714 //Skip additional edits which overlap with the primary completion edit
6715 //https://github.com/zed-industries/zed/pull/1871
6716 if !has_overlap {
6717 buffer.edit([(range, text)], None, cx);
6718 }
6719 }
6720
6721 let transaction = if buffer.end_transaction(cx).is_some() {
6722 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6723 if !push_to_history {
6724 buffer.forget_transaction(transaction.id);
6725 }
6726 Some(transaction)
6727 } else {
6728 None
6729 };
6730 Ok(transaction)
6731 })?
6732 } else {
6733 Ok(None)
6734 }
6735 })
6736 }
6737 }
6738
6739 pub fn pull_diagnostics(
6740 &mut self,
6741 buffer: Entity<Buffer>,
6742 cx: &mut Context<Self>,
6743 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6744 let buffer_id = buffer.read(cx).remote_id();
6745
6746 if let Some((client, upstream_project_id)) = self.upstream_client() {
6747 let mut suitable_capabilities = None;
6748 // Are we capable for proto request?
6749 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6750 &buffer,
6751 |capabilities| {
6752 if let Some(caps) = &capabilities.diagnostic_provider {
6753 suitable_capabilities = Some(caps.clone());
6754 true
6755 } else {
6756 false
6757 }
6758 },
6759 cx,
6760 );
6761 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6762 let Some(dynamic_caps) = suitable_capabilities else {
6763 return Task::ready(Ok(None));
6764 };
6765 assert!(any_server_has_diagnostics_provider);
6766
6767 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6768 let request = GetDocumentDiagnostics {
6769 previous_result_id: None,
6770 identifier,
6771 registration_id: None,
6772 };
6773 let request_task = client.request_lsp(
6774 upstream_project_id,
6775 None,
6776 LSP_REQUEST_TIMEOUT,
6777 cx.background_executor().clone(),
6778 request.to_proto(upstream_project_id, buffer.read(cx)),
6779 );
6780 cx.background_spawn(async move {
6781 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6782 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6783 // Do not attempt to further process the dummy responses here.
6784 let _response = request_task.await?;
6785 Ok(None)
6786 })
6787 } else {
6788 let servers = buffer.update(cx, |buffer, cx| {
6789 self.running_language_servers_for_local_buffer(buffer, cx)
6790 .map(|(_, server)| server.clone())
6791 .collect::<Vec<_>>()
6792 });
6793
6794 let pull_diagnostics = servers
6795 .into_iter()
6796 .flat_map(|server| {
6797 let result = maybe!({
6798 let local = self.as_local()?;
6799 let server_id = server.server_id();
6800 let providers_with_identifiers = local
6801 .language_server_dynamic_registrations
6802 .get(&server_id)
6803 .into_iter()
6804 .flat_map(|registrations| registrations.diagnostics.clone())
6805 .collect::<Vec<_>>();
6806 Some(
6807 providers_with_identifiers
6808 .into_iter()
6809 .map(|(registration_id, dynamic_caps)| {
6810 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6811 let registration_id = registration_id.map(SharedString::from);
6812 let result_id = self.result_id_for_buffer_pull(
6813 server_id,
6814 buffer_id,
6815 ®istration_id,
6816 cx,
6817 );
6818 self.request_lsp(
6819 buffer.clone(),
6820 LanguageServerToQuery::Other(server_id),
6821 GetDocumentDiagnostics {
6822 previous_result_id: result_id,
6823 registration_id,
6824 identifier,
6825 },
6826 cx,
6827 )
6828 })
6829 .collect::<Vec<_>>(),
6830 )
6831 });
6832
6833 result.unwrap_or_default()
6834 })
6835 .collect::<Vec<_>>();
6836
6837 cx.background_spawn(async move {
6838 let mut responses = Vec::new();
6839 for diagnostics in join_all(pull_diagnostics).await {
6840 responses.extend(diagnostics?);
6841 }
6842 Ok(Some(responses))
6843 })
6844 }
6845 }
6846
6847 pub fn applicable_inlay_chunks(
6848 &mut self,
6849 buffer: &Entity<Buffer>,
6850 ranges: &[Range<text::Anchor>],
6851 cx: &mut Context<Self>,
6852 ) -> Vec<Range<BufferRow>> {
6853 self.latest_lsp_data(buffer, cx)
6854 .inlay_hints
6855 .applicable_chunks(ranges)
6856 .map(|chunk| chunk.row_range())
6857 .collect()
6858 }
6859
6860 pub fn invalidate_inlay_hints<'a>(
6861 &'a mut self,
6862 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6863 ) {
6864 for buffer_id in for_buffers {
6865 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6866 lsp_data.inlay_hints.clear();
6867 }
6868 }
6869 }
6870
6871 pub fn inlay_hints(
6872 &mut self,
6873 invalidate: InvalidationStrategy,
6874 buffer: Entity<Buffer>,
6875 ranges: Vec<Range<text::Anchor>>,
6876 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6877 cx: &mut Context<Self>,
6878 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6879 let next_hint_id = self.next_hint_id.clone();
6880 let lsp_data = self.latest_lsp_data(&buffer, cx);
6881 let query_version = lsp_data.buffer_version.clone();
6882 let mut lsp_refresh_requested = false;
6883 let for_server = if let InvalidationStrategy::RefreshRequested {
6884 server_id,
6885 request_id,
6886 } = invalidate
6887 {
6888 let invalidated = lsp_data
6889 .inlay_hints
6890 .invalidate_for_server_refresh(server_id, request_id);
6891 lsp_refresh_requested = invalidated;
6892 Some(server_id)
6893 } else {
6894 None
6895 };
6896 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6897 let known_chunks = known_chunks
6898 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6899 .map(|(_, known_chunks)| known_chunks)
6900 .unwrap_or_default();
6901
6902 let mut hint_fetch_tasks = Vec::new();
6903 let mut cached_inlay_hints = None;
6904 let mut ranges_to_query = None;
6905 let applicable_chunks = existing_inlay_hints
6906 .applicable_chunks(ranges.as_slice())
6907 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6908 .collect::<Vec<_>>();
6909 if applicable_chunks.is_empty() {
6910 return HashMap::default();
6911 }
6912
6913 for row_chunk in applicable_chunks {
6914 match (
6915 existing_inlay_hints
6916 .cached_hints(&row_chunk)
6917 .filter(|_| !lsp_refresh_requested)
6918 .cloned(),
6919 existing_inlay_hints
6920 .fetched_hints(&row_chunk)
6921 .as_ref()
6922 .filter(|_| !lsp_refresh_requested)
6923 .cloned(),
6924 ) {
6925 (None, None) => {
6926 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6927 continue;
6928 };
6929 ranges_to_query
6930 .get_or_insert_with(Vec::new)
6931 .push((row_chunk, chunk_range));
6932 }
6933 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6934 (Some(cached_hints), None) => {
6935 for (server_id, cached_hints) in cached_hints {
6936 if for_server.is_none_or(|for_server| for_server == server_id) {
6937 cached_inlay_hints
6938 .get_or_insert_with(HashMap::default)
6939 .entry(row_chunk.row_range())
6940 .or_insert_with(HashMap::default)
6941 .entry(server_id)
6942 .or_insert_with(Vec::new)
6943 .extend(cached_hints);
6944 }
6945 }
6946 }
6947 (Some(cached_hints), Some(fetched_hints)) => {
6948 hint_fetch_tasks.push((row_chunk, fetched_hints));
6949 for (server_id, cached_hints) in cached_hints {
6950 if for_server.is_none_or(|for_server| for_server == server_id) {
6951 cached_inlay_hints
6952 .get_or_insert_with(HashMap::default)
6953 .entry(row_chunk.row_range())
6954 .or_insert_with(HashMap::default)
6955 .entry(server_id)
6956 .or_insert_with(Vec::new)
6957 .extend(cached_hints);
6958 }
6959 }
6960 }
6961 }
6962 }
6963
6964 if hint_fetch_tasks.is_empty()
6965 && ranges_to_query
6966 .as_ref()
6967 .is_none_or(|ranges| ranges.is_empty())
6968 && let Some(cached_inlay_hints) = cached_inlay_hints
6969 {
6970 cached_inlay_hints
6971 .into_iter()
6972 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6973 .collect()
6974 } else {
6975 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6976 let next_hint_id = next_hint_id.clone();
6977 let buffer = buffer.clone();
6978 let query_version = query_version.clone();
6979 let new_inlay_hints = cx
6980 .spawn(async move |lsp_store, cx| {
6981 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6982 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6983 })?;
6984 new_fetch_task
6985 .await
6986 .and_then(|new_hints_by_server| {
6987 lsp_store.update(cx, |lsp_store, cx| {
6988 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6989 let update_cache = lsp_data.buffer_version == query_version;
6990 if new_hints_by_server.is_empty() {
6991 if update_cache {
6992 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6993 }
6994 HashMap::default()
6995 } else {
6996 new_hints_by_server
6997 .into_iter()
6998 .map(|(server_id, new_hints)| {
6999 let new_hints = new_hints
7000 .into_iter()
7001 .map(|new_hint| {
7002 (
7003 InlayId::Hint(next_hint_id.fetch_add(
7004 1,
7005 atomic::Ordering::AcqRel,
7006 )),
7007 new_hint,
7008 )
7009 })
7010 .collect::<Vec<_>>();
7011 if update_cache {
7012 lsp_data.inlay_hints.insert_new_hints(
7013 chunk,
7014 server_id,
7015 new_hints.clone(),
7016 );
7017 }
7018 (server_id, new_hints)
7019 })
7020 .collect()
7021 }
7022 })
7023 })
7024 .map_err(Arc::new)
7025 })
7026 .shared();
7027
7028 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7029 *fetch_task = Some(new_inlay_hints.clone());
7030 hint_fetch_tasks.push((chunk, new_inlay_hints));
7031 }
7032
7033 cached_inlay_hints
7034 .unwrap_or_default()
7035 .into_iter()
7036 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7037 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7038 (
7039 chunk.row_range(),
7040 cx.spawn(async move |_, _| {
7041 hints_fetch.await.map_err(|e| {
7042 if e.error_code() != ErrorCode::Internal {
7043 anyhow!(e.error_code())
7044 } else {
7045 anyhow!("{e:#}")
7046 }
7047 })
7048 }),
7049 )
7050 }))
7051 .collect()
7052 }
7053 }
7054
7055 fn fetch_inlay_hints(
7056 &mut self,
7057 for_server: Option<LanguageServerId>,
7058 buffer: &Entity<Buffer>,
7059 range: Range<Anchor>,
7060 cx: &mut Context<Self>,
7061 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7062 let request = InlayHints {
7063 range: range.clone(),
7064 };
7065 if let Some((upstream_client, project_id)) = self.upstream_client() {
7066 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7067 return Task::ready(Ok(HashMap::default()));
7068 }
7069 let request_task = upstream_client.request_lsp(
7070 project_id,
7071 for_server.map(|id| id.to_proto()),
7072 LSP_REQUEST_TIMEOUT,
7073 cx.background_executor().clone(),
7074 request.to_proto(project_id, buffer.read(cx)),
7075 );
7076 let buffer = buffer.clone();
7077 cx.spawn(async move |weak_lsp_store, cx| {
7078 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7079 return Ok(HashMap::default());
7080 };
7081 let Some(responses) = request_task.await? else {
7082 return Ok(HashMap::default());
7083 };
7084
7085 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7086 let lsp_store = lsp_store.clone();
7087 let buffer = buffer.clone();
7088 let cx = cx.clone();
7089 let request = request.clone();
7090 async move {
7091 (
7092 LanguageServerId::from_proto(response.server_id),
7093 request
7094 .response_from_proto(response.response, lsp_store, buffer, cx)
7095 .await,
7096 )
7097 }
7098 }))
7099 .await;
7100
7101 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7102 let mut has_errors = false;
7103 let inlay_hints = inlay_hints
7104 .into_iter()
7105 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7106 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7107 Err(e) => {
7108 has_errors = true;
7109 log::error!("{e:#}");
7110 None
7111 }
7112 })
7113 .map(|(server_id, mut new_hints)| {
7114 new_hints.retain(|hint| {
7115 hint.position.is_valid(&buffer_snapshot)
7116 && range.start.is_valid(&buffer_snapshot)
7117 && range.end.is_valid(&buffer_snapshot)
7118 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7119 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7120 });
7121 (server_id, new_hints)
7122 })
7123 .collect::<HashMap<_, _>>();
7124 anyhow::ensure!(
7125 !has_errors || !inlay_hints.is_empty(),
7126 "Failed to fetch inlay hints"
7127 );
7128 Ok(inlay_hints)
7129 })
7130 } else {
7131 let inlay_hints_task = match for_server {
7132 Some(server_id) => {
7133 let server_task = self.request_lsp(
7134 buffer.clone(),
7135 LanguageServerToQuery::Other(server_id),
7136 request,
7137 cx,
7138 );
7139 cx.background_spawn(async move {
7140 let mut responses = Vec::new();
7141 match server_task.await {
7142 Ok(response) => responses.push((server_id, response)),
7143 // rust-analyzer likes to error with this when its still loading up
7144 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7145 Err(e) => log::error!(
7146 "Error handling response for inlay hints request: {e:#}"
7147 ),
7148 }
7149 responses
7150 })
7151 }
7152 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7153 };
7154 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7155 cx.background_spawn(async move {
7156 Ok(inlay_hints_task
7157 .await
7158 .into_iter()
7159 .map(|(server_id, mut new_hints)| {
7160 new_hints.retain(|hint| {
7161 hint.position.is_valid(&buffer_snapshot)
7162 && range.start.is_valid(&buffer_snapshot)
7163 && range.end.is_valid(&buffer_snapshot)
7164 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7165 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7166 });
7167 (server_id, new_hints)
7168 })
7169 .collect())
7170 })
7171 }
7172 }
7173
7174 pub fn pull_diagnostics_for_buffer(
7175 &mut self,
7176 buffer: Entity<Buffer>,
7177 cx: &mut Context<Self>,
7178 ) -> Task<anyhow::Result<()>> {
7179 let diagnostics = self.pull_diagnostics(buffer, cx);
7180 cx.spawn(async move |lsp_store, cx| {
7181 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7182 return Ok(());
7183 };
7184 lsp_store.update(cx, |lsp_store, cx| {
7185 if lsp_store.as_local().is_none() {
7186 return;
7187 }
7188
7189 let mut unchanged_buffers = HashMap::default();
7190 let server_diagnostics_updates = diagnostics
7191 .into_iter()
7192 .filter_map(|diagnostics_set| match diagnostics_set {
7193 LspPullDiagnostics::Response {
7194 server_id,
7195 uri,
7196 diagnostics,
7197 registration_id,
7198 } => Some((server_id, uri, diagnostics, registration_id)),
7199 LspPullDiagnostics::Default => None,
7200 })
7201 .fold(
7202 HashMap::default(),
7203 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7204 let (result_id, diagnostics) = match diagnostics {
7205 PulledDiagnostics::Unchanged { result_id } => {
7206 unchanged_buffers
7207 .entry(new_registration_id.clone())
7208 .or_insert_with(HashSet::default)
7209 .insert(uri.clone());
7210 (Some(result_id), Vec::new())
7211 }
7212 PulledDiagnostics::Changed {
7213 result_id,
7214 diagnostics,
7215 } => (result_id, diagnostics),
7216 };
7217 let disk_based_sources = Cow::Owned(
7218 lsp_store
7219 .language_server_adapter_for_id(server_id)
7220 .as_ref()
7221 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7222 .unwrap_or(&[])
7223 .to_vec(),
7224 );
7225 acc.entry(server_id)
7226 .or_insert_with(HashMap::default)
7227 .entry(new_registration_id.clone())
7228 .or_insert_with(Vec::new)
7229 .push(DocumentDiagnosticsUpdate {
7230 server_id,
7231 diagnostics: lsp::PublishDiagnosticsParams {
7232 uri,
7233 diagnostics,
7234 version: None,
7235 },
7236 result_id,
7237 disk_based_sources,
7238 registration_id: new_registration_id,
7239 });
7240 acc
7241 },
7242 );
7243
7244 for diagnostic_updates in server_diagnostics_updates.into_values() {
7245 for (registration_id, diagnostic_updates) in diagnostic_updates {
7246 lsp_store
7247 .merge_lsp_diagnostics(
7248 DiagnosticSourceKind::Pulled,
7249 diagnostic_updates,
7250 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7251 DiagnosticSourceKind::Pulled => {
7252 old_diagnostic.registration_id != registration_id
7253 || unchanged_buffers
7254 .get(&old_diagnostic.registration_id)
7255 .is_some_and(|unchanged_buffers| {
7256 unchanged_buffers.contains(&document_uri)
7257 })
7258 }
7259 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7260 true
7261 }
7262 },
7263 cx,
7264 )
7265 .log_err();
7266 }
7267 }
7268 })
7269 })
7270 }
7271
7272 pub fn document_colors(
7273 &mut self,
7274 known_cache_version: Option<usize>,
7275 buffer: Entity<Buffer>,
7276 cx: &mut Context<Self>,
7277 ) -> Option<DocumentColorTask> {
7278 let version_queried_for = buffer.read(cx).version();
7279 let buffer_id = buffer.read(cx).remote_id();
7280
7281 let current_language_servers = self.as_local().map(|local| {
7282 local
7283 .buffers_opened_in_servers
7284 .get(&buffer_id)
7285 .cloned()
7286 .unwrap_or_default()
7287 });
7288
7289 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7290 if let Some(cached_colors) = &lsp_data.document_colors {
7291 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7292 let has_different_servers =
7293 current_language_servers.is_some_and(|current_language_servers| {
7294 current_language_servers
7295 != cached_colors.colors.keys().copied().collect()
7296 });
7297 if !has_different_servers {
7298 let cache_version = cached_colors.cache_version;
7299 if Some(cache_version) == known_cache_version {
7300 return None;
7301 } else {
7302 return Some(
7303 Task::ready(Ok(DocumentColors {
7304 colors: cached_colors
7305 .colors
7306 .values()
7307 .flatten()
7308 .cloned()
7309 .collect(),
7310 cache_version: Some(cache_version),
7311 }))
7312 .shared(),
7313 );
7314 }
7315 }
7316 }
7317 }
7318 }
7319
7320 let color_lsp_data = self
7321 .latest_lsp_data(&buffer, cx)
7322 .document_colors
7323 .get_or_insert_default();
7324 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7325 && !version_queried_for.changed_since(updating_for)
7326 {
7327 return Some(running_update.clone());
7328 }
7329 let buffer_version_queried_for = version_queried_for.clone();
7330 let new_task = cx
7331 .spawn(async move |lsp_store, cx| {
7332 cx.background_executor()
7333 .timer(Duration::from_millis(30))
7334 .await;
7335 let fetched_colors = lsp_store
7336 .update(cx, |lsp_store, cx| {
7337 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7338 })?
7339 .await
7340 .context("fetching document colors")
7341 .map_err(Arc::new);
7342 let fetched_colors = match fetched_colors {
7343 Ok(fetched_colors) => {
7344 if Some(true)
7345 == buffer
7346 .update(cx, |buffer, _| {
7347 buffer.version() != buffer_version_queried_for
7348 })
7349 .ok()
7350 {
7351 return Ok(DocumentColors::default());
7352 }
7353 fetched_colors
7354 }
7355 Err(e) => {
7356 lsp_store
7357 .update(cx, |lsp_store, _| {
7358 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7359 if let Some(document_colors) = &mut lsp_data.document_colors {
7360 document_colors.colors_update = None;
7361 }
7362 }
7363 })
7364 .ok();
7365 return Err(e);
7366 }
7367 };
7368
7369 lsp_store
7370 .update(cx, |lsp_store, cx| {
7371 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7372 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7373
7374 if let Some(fetched_colors) = fetched_colors {
7375 if lsp_data.buffer_version == buffer_version_queried_for {
7376 lsp_colors.colors.extend(fetched_colors);
7377 lsp_colors.cache_version += 1;
7378 } else if !lsp_data
7379 .buffer_version
7380 .changed_since(&buffer_version_queried_for)
7381 {
7382 lsp_data.buffer_version = buffer_version_queried_for;
7383 lsp_colors.colors = fetched_colors;
7384 lsp_colors.cache_version += 1;
7385 }
7386 }
7387 lsp_colors.colors_update = None;
7388 let colors = lsp_colors
7389 .colors
7390 .values()
7391 .flatten()
7392 .cloned()
7393 .collect::<HashSet<_>>();
7394 DocumentColors {
7395 colors,
7396 cache_version: Some(lsp_colors.cache_version),
7397 }
7398 })
7399 .map_err(Arc::new)
7400 })
7401 .shared();
7402 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7403 Some(new_task)
7404 }
7405
7406 fn fetch_document_colors_for_buffer(
7407 &mut self,
7408 buffer: &Entity<Buffer>,
7409 cx: &mut Context<Self>,
7410 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7411 if let Some((client, project_id)) = self.upstream_client() {
7412 let request = GetDocumentColor {};
7413 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7414 return Task::ready(Ok(None));
7415 }
7416
7417 let request_task = client.request_lsp(
7418 project_id,
7419 None,
7420 LSP_REQUEST_TIMEOUT,
7421 cx.background_executor().clone(),
7422 request.to_proto(project_id, buffer.read(cx)),
7423 );
7424 let buffer = buffer.clone();
7425 cx.spawn(async move |lsp_store, cx| {
7426 let Some(lsp_store) = lsp_store.upgrade() else {
7427 return Ok(None);
7428 };
7429 let colors = join_all(
7430 request_task
7431 .await
7432 .log_err()
7433 .flatten()
7434 .map(|response| response.payload)
7435 .unwrap_or_default()
7436 .into_iter()
7437 .map(|color_response| {
7438 let response = request.response_from_proto(
7439 color_response.response,
7440 lsp_store.clone(),
7441 buffer.clone(),
7442 cx.clone(),
7443 );
7444 async move {
7445 (
7446 LanguageServerId::from_proto(color_response.server_id),
7447 response.await.log_err().unwrap_or_default(),
7448 )
7449 }
7450 }),
7451 )
7452 .await
7453 .into_iter()
7454 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7455 acc.entry(server_id)
7456 .or_insert_with(HashSet::default)
7457 .extend(colors);
7458 acc
7459 });
7460 Ok(Some(colors))
7461 })
7462 } else {
7463 let document_colors_task =
7464 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7465 cx.background_spawn(async move {
7466 Ok(Some(
7467 document_colors_task
7468 .await
7469 .into_iter()
7470 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7471 acc.entry(server_id)
7472 .or_insert_with(HashSet::default)
7473 .extend(colors);
7474 acc
7475 })
7476 .into_iter()
7477 .collect(),
7478 ))
7479 })
7480 }
7481 }
7482
7483 pub fn signature_help<T: ToPointUtf16>(
7484 &mut self,
7485 buffer: &Entity<Buffer>,
7486 position: T,
7487 cx: &mut Context<Self>,
7488 ) -> Task<Option<Vec<SignatureHelp>>> {
7489 let position = position.to_point_utf16(buffer.read(cx));
7490
7491 if let Some((client, upstream_project_id)) = self.upstream_client() {
7492 let request = GetSignatureHelp { position };
7493 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7494 return Task::ready(None);
7495 }
7496 let request_task = client.request_lsp(
7497 upstream_project_id,
7498 None,
7499 LSP_REQUEST_TIMEOUT,
7500 cx.background_executor().clone(),
7501 request.to_proto(upstream_project_id, buffer.read(cx)),
7502 );
7503 let buffer = buffer.clone();
7504 cx.spawn(async move |weak_lsp_store, cx| {
7505 let lsp_store = weak_lsp_store.upgrade()?;
7506 let signatures = join_all(
7507 request_task
7508 .await
7509 .log_err()
7510 .flatten()
7511 .map(|response| response.payload)
7512 .unwrap_or_default()
7513 .into_iter()
7514 .map(|response| {
7515 let response = GetSignatureHelp { position }.response_from_proto(
7516 response.response,
7517 lsp_store.clone(),
7518 buffer.clone(),
7519 cx.clone(),
7520 );
7521 async move { response.await.log_err().flatten() }
7522 }),
7523 )
7524 .await
7525 .into_iter()
7526 .flatten()
7527 .collect();
7528 Some(signatures)
7529 })
7530 } else {
7531 let all_actions_task = self.request_multiple_lsp_locally(
7532 buffer,
7533 Some(position),
7534 GetSignatureHelp { position },
7535 cx,
7536 );
7537 cx.background_spawn(async move {
7538 Some(
7539 all_actions_task
7540 .await
7541 .into_iter()
7542 .flat_map(|(_, actions)| actions)
7543 .collect::<Vec<_>>(),
7544 )
7545 })
7546 }
7547 }
7548
7549 pub fn hover(
7550 &mut self,
7551 buffer: &Entity<Buffer>,
7552 position: PointUtf16,
7553 cx: &mut Context<Self>,
7554 ) -> Task<Option<Vec<Hover>>> {
7555 if let Some((client, upstream_project_id)) = self.upstream_client() {
7556 let request = GetHover { position };
7557 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7558 return Task::ready(None);
7559 }
7560 let request_task = client.request_lsp(
7561 upstream_project_id,
7562 None,
7563 LSP_REQUEST_TIMEOUT,
7564 cx.background_executor().clone(),
7565 request.to_proto(upstream_project_id, buffer.read(cx)),
7566 );
7567 let buffer = buffer.clone();
7568 cx.spawn(async move |weak_lsp_store, cx| {
7569 let lsp_store = weak_lsp_store.upgrade()?;
7570 let hovers = join_all(
7571 request_task
7572 .await
7573 .log_err()
7574 .flatten()
7575 .map(|response| response.payload)
7576 .unwrap_or_default()
7577 .into_iter()
7578 .map(|response| {
7579 let response = GetHover { position }.response_from_proto(
7580 response.response,
7581 lsp_store.clone(),
7582 buffer.clone(),
7583 cx.clone(),
7584 );
7585 async move {
7586 response
7587 .await
7588 .log_err()
7589 .flatten()
7590 .and_then(remove_empty_hover_blocks)
7591 }
7592 }),
7593 )
7594 .await
7595 .into_iter()
7596 .flatten()
7597 .collect();
7598 Some(hovers)
7599 })
7600 } else {
7601 let all_actions_task = self.request_multiple_lsp_locally(
7602 buffer,
7603 Some(position),
7604 GetHover { position },
7605 cx,
7606 );
7607 cx.background_spawn(async move {
7608 Some(
7609 all_actions_task
7610 .await
7611 .into_iter()
7612 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7613 .collect::<Vec<Hover>>(),
7614 )
7615 })
7616 }
7617 }
7618
7619 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7620 let language_registry = self.languages.clone();
7621
7622 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7623 let request = upstream_client.request(proto::GetProjectSymbols {
7624 project_id: *project_id,
7625 query: query.to_string(),
7626 });
7627 cx.foreground_executor().spawn(async move {
7628 let response = request.await?;
7629 let mut symbols = Vec::new();
7630 let core_symbols = response
7631 .symbols
7632 .into_iter()
7633 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7634 .collect::<Vec<_>>();
7635 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7636 .await;
7637 Ok(symbols)
7638 })
7639 } else if let Some(local) = self.as_local() {
7640 struct WorkspaceSymbolsResult {
7641 server_id: LanguageServerId,
7642 lsp_adapter: Arc<CachedLspAdapter>,
7643 worktree: WeakEntity<Worktree>,
7644 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7645 }
7646
7647 let mut requests = Vec::new();
7648 let mut requested_servers = BTreeSet::new();
7649 for (seed, state) in local.language_server_ids.iter() {
7650 let Some(worktree_handle) = self
7651 .worktree_store
7652 .read(cx)
7653 .worktree_for_id(seed.worktree_id, cx)
7654 else {
7655 continue;
7656 };
7657 let worktree = worktree_handle.read(cx);
7658 if !worktree.is_visible() {
7659 continue;
7660 }
7661
7662 if !requested_servers.insert(state.id) {
7663 continue;
7664 }
7665
7666 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7667 Some(LanguageServerState::Running {
7668 adapter, server, ..
7669 }) => (adapter.clone(), server),
7670
7671 _ => continue,
7672 };
7673 let supports_workspace_symbol_request =
7674 match server.capabilities().workspace_symbol_provider {
7675 Some(OneOf::Left(supported)) => supported,
7676 Some(OneOf::Right(_)) => true,
7677 None => false,
7678 };
7679 if !supports_workspace_symbol_request {
7680 continue;
7681 }
7682 let worktree_handle = worktree_handle.clone();
7683 let server_id = server.server_id();
7684 requests.push(
7685 server
7686 .request::<lsp::request::WorkspaceSymbolRequest>(
7687 lsp::WorkspaceSymbolParams {
7688 query: query.to_string(),
7689 ..Default::default()
7690 },
7691 )
7692 .map(move |response| {
7693 let lsp_symbols = response.into_response()
7694 .context("workspace symbols request")
7695 .log_err()
7696 .flatten()
7697 .map(|symbol_response| match symbol_response {
7698 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7699 flat_responses.into_iter().map(|lsp_symbol| {
7700 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7701 }).collect::<Vec<_>>()
7702 }
7703 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7704 nested_responses.into_iter().filter_map(|lsp_symbol| {
7705 let location = match lsp_symbol.location {
7706 OneOf::Left(location) => location,
7707 OneOf::Right(_) => {
7708 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7709 return None
7710 }
7711 };
7712 Some((lsp_symbol.name, lsp_symbol.kind, location))
7713 }).collect::<Vec<_>>()
7714 }
7715 }).unwrap_or_default();
7716
7717 WorkspaceSymbolsResult {
7718 server_id,
7719 lsp_adapter,
7720 worktree: worktree_handle.downgrade(),
7721 lsp_symbols,
7722 }
7723 }),
7724 );
7725 }
7726
7727 cx.spawn(async move |this, cx| {
7728 let responses = futures::future::join_all(requests).await;
7729 let this = match this.upgrade() {
7730 Some(this) => this,
7731 None => return Ok(Vec::new()),
7732 };
7733
7734 let mut symbols = Vec::new();
7735 for result in responses {
7736 let core_symbols = this.update(cx, |this, cx| {
7737 result
7738 .lsp_symbols
7739 .into_iter()
7740 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7741 let abs_path = symbol_location.uri.to_file_path().ok()?;
7742 let source_worktree = result.worktree.upgrade()?;
7743 let source_worktree_id = source_worktree.read(cx).id();
7744
7745 let path = if let Some((tree, rel_path)) =
7746 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7747 {
7748 let worktree_id = tree.read(cx).id();
7749 SymbolLocation::InProject(ProjectPath {
7750 worktree_id,
7751 path: rel_path,
7752 })
7753 } else {
7754 SymbolLocation::OutsideProject {
7755 signature: this.symbol_signature(&abs_path),
7756 abs_path: abs_path.into(),
7757 }
7758 };
7759
7760 Some(CoreSymbol {
7761 source_language_server_id: result.server_id,
7762 language_server_name: result.lsp_adapter.name.clone(),
7763 source_worktree_id,
7764 path,
7765 kind: symbol_kind,
7766 name: symbol_name,
7767 range: range_from_lsp(symbol_location.range),
7768 })
7769 })
7770 .collect()
7771 })?;
7772
7773 populate_labels_for_symbols(
7774 core_symbols,
7775 &language_registry,
7776 Some(result.lsp_adapter),
7777 &mut symbols,
7778 )
7779 .await;
7780 }
7781
7782 Ok(symbols)
7783 })
7784 } else {
7785 Task::ready(Err(anyhow!("No upstream client or local language server")))
7786 }
7787 }
7788
7789 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7790 let mut summary = DiagnosticSummary::default();
7791 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7792 summary.error_count += path_summary.error_count;
7793 summary.warning_count += path_summary.warning_count;
7794 }
7795 summary
7796 }
7797
7798 /// Returns the diagnostic summary for a specific project path.
7799 pub fn diagnostic_summary_for_path(
7800 &self,
7801 project_path: &ProjectPath,
7802 _: &App,
7803 ) -> DiagnosticSummary {
7804 if let Some(summaries) = self
7805 .diagnostic_summaries
7806 .get(&project_path.worktree_id)
7807 .and_then(|map| map.get(&project_path.path))
7808 {
7809 let (error_count, warning_count) = summaries.iter().fold(
7810 (0, 0),
7811 |(error_count, warning_count), (_language_server_id, summary)| {
7812 (
7813 error_count + summary.error_count,
7814 warning_count + summary.warning_count,
7815 )
7816 },
7817 );
7818
7819 DiagnosticSummary {
7820 error_count,
7821 warning_count,
7822 }
7823 } else {
7824 DiagnosticSummary::default()
7825 }
7826 }
7827
7828 pub fn diagnostic_summaries<'a>(
7829 &'a self,
7830 include_ignored: bool,
7831 cx: &'a App,
7832 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7833 self.worktree_store
7834 .read(cx)
7835 .visible_worktrees(cx)
7836 .filter_map(|worktree| {
7837 let worktree = worktree.read(cx);
7838 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7839 })
7840 .flat_map(move |(worktree, summaries)| {
7841 let worktree_id = worktree.id();
7842 summaries
7843 .iter()
7844 .filter(move |(path, _)| {
7845 include_ignored
7846 || worktree
7847 .entry_for_path(path.as_ref())
7848 .is_some_and(|entry| !entry.is_ignored)
7849 })
7850 .flat_map(move |(path, summaries)| {
7851 summaries.iter().map(move |(server_id, summary)| {
7852 (
7853 ProjectPath {
7854 worktree_id,
7855 path: path.clone(),
7856 },
7857 *server_id,
7858 *summary,
7859 )
7860 })
7861 })
7862 })
7863 }
7864
7865 pub fn on_buffer_edited(
7866 &mut self,
7867 buffer: Entity<Buffer>,
7868 cx: &mut Context<Self>,
7869 ) -> Option<()> {
7870 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7871 Some(
7872 self.as_local()?
7873 .language_servers_for_buffer(buffer, cx)
7874 .map(|i| i.1.clone())
7875 .collect(),
7876 )
7877 })?;
7878
7879 let buffer = buffer.read(cx);
7880 let file = File::from_dyn(buffer.file())?;
7881 let abs_path = file.as_local()?.abs_path(cx);
7882 let uri = lsp::Uri::from_file_path(&abs_path)
7883 .ok()
7884 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7885 .log_err()?;
7886 let next_snapshot = buffer.text_snapshot();
7887 for language_server in language_servers {
7888 let language_server = language_server.clone();
7889
7890 let buffer_snapshots = self
7891 .as_local_mut()?
7892 .buffer_snapshots
7893 .get_mut(&buffer.remote_id())
7894 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7895 let previous_snapshot = buffer_snapshots.last()?;
7896
7897 let build_incremental_change = || {
7898 buffer
7899 .edits_since::<Dimensions<PointUtf16, usize>>(
7900 previous_snapshot.snapshot.version(),
7901 )
7902 .map(|edit| {
7903 let edit_start = edit.new.start.0;
7904 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7905 let new_text = next_snapshot
7906 .text_for_range(edit.new.start.1..edit.new.end.1)
7907 .collect();
7908 lsp::TextDocumentContentChangeEvent {
7909 range: Some(lsp::Range::new(
7910 point_to_lsp(edit_start),
7911 point_to_lsp(edit_end),
7912 )),
7913 range_length: None,
7914 text: new_text,
7915 }
7916 })
7917 .collect()
7918 };
7919
7920 let document_sync_kind = language_server
7921 .capabilities()
7922 .text_document_sync
7923 .as_ref()
7924 .and_then(|sync| match sync {
7925 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7926 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7927 });
7928
7929 let content_changes: Vec<_> = match document_sync_kind {
7930 Some(lsp::TextDocumentSyncKind::FULL) => {
7931 vec![lsp::TextDocumentContentChangeEvent {
7932 range: None,
7933 range_length: None,
7934 text: next_snapshot.text(),
7935 }]
7936 }
7937 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7938 _ => {
7939 #[cfg(any(test, feature = "test-support"))]
7940 {
7941 build_incremental_change()
7942 }
7943
7944 #[cfg(not(any(test, feature = "test-support")))]
7945 {
7946 continue;
7947 }
7948 }
7949 };
7950
7951 let next_version = previous_snapshot.version + 1;
7952 buffer_snapshots.push(LspBufferSnapshot {
7953 version: next_version,
7954 snapshot: next_snapshot.clone(),
7955 });
7956
7957 language_server
7958 .notify::<lsp::notification::DidChangeTextDocument>(
7959 lsp::DidChangeTextDocumentParams {
7960 text_document: lsp::VersionedTextDocumentIdentifier::new(
7961 uri.clone(),
7962 next_version,
7963 ),
7964 content_changes,
7965 },
7966 )
7967 .ok();
7968 self.pull_workspace_diagnostics(language_server.server_id());
7969 }
7970
7971 None
7972 }
7973
7974 pub fn on_buffer_saved(
7975 &mut self,
7976 buffer: Entity<Buffer>,
7977 cx: &mut Context<Self>,
7978 ) -> Option<()> {
7979 let file = File::from_dyn(buffer.read(cx).file())?;
7980 let worktree_id = file.worktree_id(cx);
7981 let abs_path = file.as_local()?.abs_path(cx);
7982 let text_document = lsp::TextDocumentIdentifier {
7983 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7984 };
7985 let local = self.as_local()?;
7986
7987 for server in local.language_servers_for_worktree(worktree_id) {
7988 if let Some(include_text) = include_text(server.as_ref()) {
7989 let text = if include_text {
7990 Some(buffer.read(cx).text())
7991 } else {
7992 None
7993 };
7994 server
7995 .notify::<lsp::notification::DidSaveTextDocument>(
7996 lsp::DidSaveTextDocumentParams {
7997 text_document: text_document.clone(),
7998 text,
7999 },
8000 )
8001 .ok();
8002 }
8003 }
8004
8005 let language_servers = buffer.update(cx, |buffer, cx| {
8006 local.language_server_ids_for_buffer(buffer, cx)
8007 });
8008 for language_server_id in language_servers {
8009 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8010 }
8011
8012 None
8013 }
8014
8015 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8016 maybe!(async move {
8017 let mut refreshed_servers = HashSet::default();
8018 let servers = lsp_store
8019 .update(cx, |lsp_store, cx| {
8020 let local = lsp_store.as_local()?;
8021
8022 let servers = local
8023 .language_server_ids
8024 .iter()
8025 .filter_map(|(seed, state)| {
8026 let worktree = lsp_store
8027 .worktree_store
8028 .read(cx)
8029 .worktree_for_id(seed.worktree_id, cx);
8030 let delegate: Arc<dyn LspAdapterDelegate> =
8031 worktree.map(|worktree| {
8032 LocalLspAdapterDelegate::new(
8033 local.languages.clone(),
8034 &local.environment,
8035 cx.weak_entity(),
8036 &worktree,
8037 local.http_client.clone(),
8038 local.fs.clone(),
8039 cx,
8040 )
8041 })?;
8042 let server_id = state.id;
8043
8044 let states = local.language_servers.get(&server_id)?;
8045
8046 match states {
8047 LanguageServerState::Starting { .. } => None,
8048 LanguageServerState::Running {
8049 adapter, server, ..
8050 } => {
8051 let adapter = adapter.clone();
8052 let server = server.clone();
8053 refreshed_servers.insert(server.name());
8054 let toolchain = seed.toolchain.clone();
8055 Some(cx.spawn(async move |_, cx| {
8056 let settings =
8057 LocalLspStore::workspace_configuration_for_adapter(
8058 adapter.adapter.clone(),
8059 &delegate,
8060 toolchain,
8061 None,
8062 cx,
8063 )
8064 .await
8065 .ok()?;
8066 server
8067 .notify::<lsp::notification::DidChangeConfiguration>(
8068 lsp::DidChangeConfigurationParams { settings },
8069 )
8070 .ok()?;
8071 Some(())
8072 }))
8073 }
8074 }
8075 })
8076 .collect::<Vec<_>>();
8077
8078 Some(servers)
8079 })
8080 .ok()
8081 .flatten()?;
8082
8083 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8084 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8085 // to stop and unregister its language server wrapper.
8086 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8087 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8088 let _: Vec<Option<()>> = join_all(servers).await;
8089
8090 Some(())
8091 })
8092 .await;
8093 }
8094
8095 fn maintain_workspace_config(
8096 external_refresh_requests: watch::Receiver<()>,
8097 cx: &mut Context<Self>,
8098 ) -> Task<Result<()>> {
8099 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8100 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8101
8102 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8103 *settings_changed_tx.borrow_mut() = ();
8104 });
8105
8106 let mut joint_future =
8107 futures::stream::select(settings_changed_rx, external_refresh_requests);
8108 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8109 // - 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).
8110 // - 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.
8111 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8112 // - 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,
8113 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8114 cx.spawn(async move |this, cx| {
8115 while let Some(()) = joint_future.next().await {
8116 this.update(cx, |this, cx| {
8117 this.refresh_server_tree(cx);
8118 })
8119 .ok();
8120
8121 Self::refresh_workspace_configurations(&this, cx).await;
8122 }
8123
8124 drop(settings_observation);
8125 anyhow::Ok(())
8126 })
8127 }
8128
8129 pub fn running_language_servers_for_local_buffer<'a>(
8130 &'a self,
8131 buffer: &Buffer,
8132 cx: &mut App,
8133 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8134 let local = self.as_local();
8135 let language_server_ids = local
8136 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8137 .unwrap_or_default();
8138
8139 language_server_ids
8140 .into_iter()
8141 .filter_map(
8142 move |server_id| match local?.language_servers.get(&server_id)? {
8143 LanguageServerState::Running {
8144 adapter, server, ..
8145 } => Some((adapter, server)),
8146 _ => None,
8147 },
8148 )
8149 }
8150
8151 pub fn language_servers_for_local_buffer(
8152 &self,
8153 buffer: &Buffer,
8154 cx: &mut App,
8155 ) -> Vec<LanguageServerId> {
8156 let local = self.as_local();
8157 local
8158 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8159 .unwrap_or_default()
8160 }
8161
8162 pub fn language_server_for_local_buffer<'a>(
8163 &'a self,
8164 buffer: &'a Buffer,
8165 server_id: LanguageServerId,
8166 cx: &'a mut App,
8167 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8168 self.as_local()?
8169 .language_servers_for_buffer(buffer, cx)
8170 .find(|(_, s)| s.server_id() == server_id)
8171 }
8172
8173 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8174 self.diagnostic_summaries.remove(&id_to_remove);
8175 if let Some(local) = self.as_local_mut() {
8176 let to_remove = local.remove_worktree(id_to_remove, cx);
8177 for server in to_remove {
8178 self.language_server_statuses.remove(&server);
8179 }
8180 }
8181 }
8182
8183 pub fn shared(
8184 &mut self,
8185 project_id: u64,
8186 downstream_client: AnyProtoClient,
8187 _: &mut Context<Self>,
8188 ) {
8189 self.downstream_client = Some((downstream_client.clone(), project_id));
8190
8191 for (server_id, status) in &self.language_server_statuses {
8192 if let Some(server) = self.language_server_for_id(*server_id) {
8193 downstream_client
8194 .send(proto::StartLanguageServer {
8195 project_id,
8196 server: Some(proto::LanguageServer {
8197 id: server_id.to_proto(),
8198 name: status.name.to_string(),
8199 worktree_id: status.worktree.map(|id| id.to_proto()),
8200 }),
8201 capabilities: serde_json::to_string(&server.capabilities())
8202 .expect("serializing server LSP capabilities"),
8203 })
8204 .log_err();
8205 }
8206 }
8207 }
8208
8209 pub fn disconnected_from_host(&mut self) {
8210 self.downstream_client.take();
8211 }
8212
8213 pub fn disconnected_from_ssh_remote(&mut self) {
8214 if let LspStoreMode::Remote(RemoteLspStore {
8215 upstream_client, ..
8216 }) = &mut self.mode
8217 {
8218 upstream_client.take();
8219 }
8220 }
8221
8222 pub(crate) fn set_language_server_statuses_from_proto(
8223 &mut self,
8224 project: WeakEntity<Project>,
8225 language_servers: Vec<proto::LanguageServer>,
8226 server_capabilities: Vec<String>,
8227 cx: &mut Context<Self>,
8228 ) {
8229 let lsp_logs = cx
8230 .try_global::<GlobalLogStore>()
8231 .map(|lsp_store| lsp_store.0.clone());
8232
8233 self.language_server_statuses = language_servers
8234 .into_iter()
8235 .zip(server_capabilities)
8236 .map(|(server, server_capabilities)| {
8237 let server_id = LanguageServerId(server.id as usize);
8238 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8239 self.lsp_server_capabilities
8240 .insert(server_id, server_capabilities);
8241 }
8242
8243 let name = LanguageServerName::from_proto(server.name);
8244 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8245
8246 if let Some(lsp_logs) = &lsp_logs {
8247 lsp_logs.update(cx, |lsp_logs, cx| {
8248 lsp_logs.add_language_server(
8249 // Only remote clients get their language servers set from proto
8250 LanguageServerKind::Remote {
8251 project: project.clone(),
8252 },
8253 server_id,
8254 Some(name.clone()),
8255 worktree,
8256 None,
8257 cx,
8258 );
8259 });
8260 }
8261
8262 (
8263 server_id,
8264 LanguageServerStatus {
8265 name,
8266 pending_work: Default::default(),
8267 has_pending_diagnostic_updates: false,
8268 progress_tokens: Default::default(),
8269 worktree,
8270 binary: None,
8271 configuration: None,
8272 workspace_folders: BTreeSet::new(),
8273 },
8274 )
8275 })
8276 .collect();
8277 }
8278
8279 #[cfg(test)]
8280 pub fn update_diagnostic_entries(
8281 &mut self,
8282 server_id: LanguageServerId,
8283 abs_path: PathBuf,
8284 result_id: Option<SharedString>,
8285 version: Option<i32>,
8286 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8287 cx: &mut Context<Self>,
8288 ) -> anyhow::Result<()> {
8289 self.merge_diagnostic_entries(
8290 vec![DocumentDiagnosticsUpdate {
8291 diagnostics: DocumentDiagnostics {
8292 diagnostics,
8293 document_abs_path: abs_path,
8294 version,
8295 },
8296 result_id,
8297 server_id,
8298 disk_based_sources: Cow::Borrowed(&[]),
8299 registration_id: None,
8300 }],
8301 |_, _, _| false,
8302 cx,
8303 )?;
8304 Ok(())
8305 }
8306
8307 pub fn merge_diagnostic_entries<'a>(
8308 &mut self,
8309 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8310 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8311 cx: &mut Context<Self>,
8312 ) -> anyhow::Result<()> {
8313 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8314 let mut updated_diagnostics_paths = HashMap::default();
8315 for mut update in diagnostic_updates {
8316 let abs_path = &update.diagnostics.document_abs_path;
8317 let server_id = update.server_id;
8318 let Some((worktree, relative_path)) =
8319 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8320 else {
8321 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8322 return Ok(());
8323 };
8324
8325 let worktree_id = worktree.read(cx).id();
8326 let project_path = ProjectPath {
8327 worktree_id,
8328 path: relative_path,
8329 };
8330
8331 let document_uri = lsp::Uri::from_file_path(abs_path)
8332 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8333 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8334 let snapshot = buffer_handle.read(cx).snapshot();
8335 let buffer = buffer_handle.read(cx);
8336 let reused_diagnostics = buffer
8337 .buffer_diagnostics(Some(server_id))
8338 .iter()
8339 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8340 .map(|v| {
8341 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8342 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8343 DiagnosticEntry {
8344 range: start..end,
8345 diagnostic: v.diagnostic.clone(),
8346 }
8347 })
8348 .collect::<Vec<_>>();
8349
8350 self.as_local_mut()
8351 .context("cannot merge diagnostics on a remote LspStore")?
8352 .update_buffer_diagnostics(
8353 &buffer_handle,
8354 server_id,
8355 Some(update.registration_id),
8356 update.result_id,
8357 update.diagnostics.version,
8358 update.diagnostics.diagnostics.clone(),
8359 reused_diagnostics.clone(),
8360 cx,
8361 )?;
8362
8363 update.diagnostics.diagnostics.extend(reused_diagnostics);
8364 } else if let Some(local) = self.as_local() {
8365 let reused_diagnostics = local
8366 .diagnostics
8367 .get(&worktree_id)
8368 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8369 .and_then(|diagnostics_by_server_id| {
8370 diagnostics_by_server_id
8371 .binary_search_by_key(&server_id, |e| e.0)
8372 .ok()
8373 .map(|ix| &diagnostics_by_server_id[ix].1)
8374 })
8375 .into_iter()
8376 .flatten()
8377 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8378
8379 update
8380 .diagnostics
8381 .diagnostics
8382 .extend(reused_diagnostics.cloned());
8383 }
8384
8385 let updated = worktree.update(cx, |worktree, cx| {
8386 self.update_worktree_diagnostics(
8387 worktree.id(),
8388 server_id,
8389 project_path.path.clone(),
8390 update.diagnostics.diagnostics,
8391 cx,
8392 )
8393 })?;
8394 match updated {
8395 ControlFlow::Continue(new_summary) => {
8396 if let Some((project_id, new_summary)) = new_summary {
8397 match &mut diagnostics_summary {
8398 Some(diagnostics_summary) => {
8399 diagnostics_summary
8400 .more_summaries
8401 .push(proto::DiagnosticSummary {
8402 path: project_path.path.as_ref().to_proto(),
8403 language_server_id: server_id.0 as u64,
8404 error_count: new_summary.error_count,
8405 warning_count: new_summary.warning_count,
8406 })
8407 }
8408 None => {
8409 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8410 project_id,
8411 worktree_id: worktree_id.to_proto(),
8412 summary: Some(proto::DiagnosticSummary {
8413 path: project_path.path.as_ref().to_proto(),
8414 language_server_id: server_id.0 as u64,
8415 error_count: new_summary.error_count,
8416 warning_count: new_summary.warning_count,
8417 }),
8418 more_summaries: Vec::new(),
8419 })
8420 }
8421 }
8422 }
8423 updated_diagnostics_paths
8424 .entry(server_id)
8425 .or_insert_with(Vec::new)
8426 .push(project_path);
8427 }
8428 ControlFlow::Break(()) => {}
8429 }
8430 }
8431
8432 if let Some((diagnostics_summary, (downstream_client, _))) =
8433 diagnostics_summary.zip(self.downstream_client.as_ref())
8434 {
8435 downstream_client.send(diagnostics_summary).log_err();
8436 }
8437 for (server_id, paths) in updated_diagnostics_paths {
8438 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8439 }
8440 Ok(())
8441 }
8442
8443 fn update_worktree_diagnostics(
8444 &mut self,
8445 worktree_id: WorktreeId,
8446 server_id: LanguageServerId,
8447 path_in_worktree: Arc<RelPath>,
8448 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8449 _: &mut Context<Worktree>,
8450 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8451 let local = match &mut self.mode {
8452 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8453 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8454 };
8455
8456 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8457 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8458 let summaries_by_server_id = summaries_for_tree
8459 .entry(path_in_worktree.clone())
8460 .or_default();
8461
8462 let old_summary = summaries_by_server_id
8463 .remove(&server_id)
8464 .unwrap_or_default();
8465
8466 let new_summary = DiagnosticSummary::new(&diagnostics);
8467 if diagnostics.is_empty() {
8468 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8469 {
8470 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8471 diagnostics_by_server_id.remove(ix);
8472 }
8473 if diagnostics_by_server_id.is_empty() {
8474 diagnostics_for_tree.remove(&path_in_worktree);
8475 }
8476 }
8477 } else {
8478 summaries_by_server_id.insert(server_id, new_summary);
8479 let diagnostics_by_server_id = diagnostics_for_tree
8480 .entry(path_in_worktree.clone())
8481 .or_default();
8482 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8483 Ok(ix) => {
8484 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8485 }
8486 Err(ix) => {
8487 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8488 }
8489 }
8490 }
8491
8492 if !old_summary.is_empty() || !new_summary.is_empty() {
8493 if let Some((_, project_id)) = &self.downstream_client {
8494 Ok(ControlFlow::Continue(Some((
8495 *project_id,
8496 proto::DiagnosticSummary {
8497 path: path_in_worktree.to_proto(),
8498 language_server_id: server_id.0 as u64,
8499 error_count: new_summary.error_count as u32,
8500 warning_count: new_summary.warning_count as u32,
8501 },
8502 ))))
8503 } else {
8504 Ok(ControlFlow::Continue(None))
8505 }
8506 } else {
8507 Ok(ControlFlow::Break(()))
8508 }
8509 }
8510
8511 pub fn open_buffer_for_symbol(
8512 &mut self,
8513 symbol: &Symbol,
8514 cx: &mut Context<Self>,
8515 ) -> Task<Result<Entity<Buffer>>> {
8516 if let Some((client, project_id)) = self.upstream_client() {
8517 let request = client.request(proto::OpenBufferForSymbol {
8518 project_id,
8519 symbol: Some(Self::serialize_symbol(symbol)),
8520 });
8521 cx.spawn(async move |this, cx| {
8522 let response = request.await?;
8523 let buffer_id = BufferId::new(response.buffer_id)?;
8524 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8525 .await
8526 })
8527 } else if let Some(local) = self.as_local() {
8528 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8529 seed.worktree_id == symbol.source_worktree_id
8530 && state.id == symbol.source_language_server_id
8531 && symbol.language_server_name == seed.name
8532 });
8533 if !is_valid {
8534 return Task::ready(Err(anyhow!(
8535 "language server for worktree and language not found"
8536 )));
8537 };
8538
8539 let symbol_abs_path = match &symbol.path {
8540 SymbolLocation::InProject(project_path) => self
8541 .worktree_store
8542 .read(cx)
8543 .absolutize(&project_path, cx)
8544 .context("no such worktree"),
8545 SymbolLocation::OutsideProject {
8546 abs_path,
8547 signature: _,
8548 } => Ok(abs_path.to_path_buf()),
8549 };
8550 let symbol_abs_path = match symbol_abs_path {
8551 Ok(abs_path) => abs_path,
8552 Err(err) => return Task::ready(Err(err)),
8553 };
8554 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8555 uri
8556 } else {
8557 return Task::ready(Err(anyhow!("invalid symbol path")));
8558 };
8559
8560 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8561 } else {
8562 Task::ready(Err(anyhow!("no upstream client or local store")))
8563 }
8564 }
8565
8566 pub(crate) fn open_local_buffer_via_lsp(
8567 &mut self,
8568 abs_path: lsp::Uri,
8569 language_server_id: LanguageServerId,
8570 cx: &mut Context<Self>,
8571 ) -> Task<Result<Entity<Buffer>>> {
8572 cx.spawn(async move |lsp_store, cx| {
8573 // Escape percent-encoded string.
8574 let current_scheme = abs_path.scheme().to_owned();
8575 // Uri is immutable, so we can't modify the scheme
8576
8577 let abs_path = abs_path
8578 .to_file_path()
8579 .map_err(|()| anyhow!("can't convert URI to path"))?;
8580 let p = abs_path.clone();
8581 let yarn_worktree = lsp_store
8582 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8583 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8584 cx.spawn(async move |this, cx| {
8585 let t = this
8586 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8587 .ok()?;
8588 t.await
8589 })
8590 }),
8591 None => Task::ready(None),
8592 })?
8593 .await;
8594 let (worktree_root_target, known_relative_path) =
8595 if let Some((zip_root, relative_path)) = yarn_worktree {
8596 (zip_root, Some(relative_path))
8597 } else {
8598 (Arc::<Path>::from(abs_path.as_path()), None)
8599 };
8600 let (worktree, relative_path) = if let Some(result) =
8601 lsp_store.update(cx, |lsp_store, cx| {
8602 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8603 worktree_store.find_worktree(&worktree_root_target, cx)
8604 })
8605 })? {
8606 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8607 (result.0, relative_path)
8608 } else {
8609 let worktree = lsp_store
8610 .update(cx, |lsp_store, cx| {
8611 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8612 worktree_store.create_worktree(&worktree_root_target, false, cx)
8613 })
8614 })?
8615 .await?;
8616 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8617 lsp_store
8618 .update(cx, |lsp_store, cx| {
8619 if let Some(local) = lsp_store.as_local_mut() {
8620 local.register_language_server_for_invisible_worktree(
8621 &worktree,
8622 language_server_id,
8623 cx,
8624 )
8625 }
8626 })
8627 .ok();
8628 }
8629 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8630 let relative_path = if let Some(known_path) = known_relative_path {
8631 known_path
8632 } else {
8633 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8634 .into_arc()
8635 };
8636 (worktree, relative_path)
8637 };
8638 let project_path = ProjectPath {
8639 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8640 path: relative_path,
8641 };
8642 lsp_store
8643 .update(cx, |lsp_store, cx| {
8644 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8645 buffer_store.open_buffer(project_path, cx)
8646 })
8647 })?
8648 .await
8649 })
8650 }
8651
8652 fn request_multiple_lsp_locally<P, R>(
8653 &mut self,
8654 buffer: &Entity<Buffer>,
8655 position: Option<P>,
8656 request: R,
8657 cx: &mut Context<Self>,
8658 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8659 where
8660 P: ToOffset,
8661 R: LspCommand + Clone,
8662 <R::LspRequest as lsp::request::Request>::Result: Send,
8663 <R::LspRequest as lsp::request::Request>::Params: Send,
8664 {
8665 let Some(local) = self.as_local() else {
8666 return Task::ready(Vec::new());
8667 };
8668
8669 let snapshot = buffer.read(cx).snapshot();
8670 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8671
8672 let server_ids = buffer.update(cx, |buffer, cx| {
8673 local
8674 .language_servers_for_buffer(buffer, cx)
8675 .filter(|(adapter, _)| {
8676 scope
8677 .as_ref()
8678 .map(|scope| scope.language_allowed(&adapter.name))
8679 .unwrap_or(true)
8680 })
8681 .map(|(_, server)| server.server_id())
8682 .filter(|server_id| {
8683 self.as_local().is_none_or(|local| {
8684 local
8685 .buffers_opened_in_servers
8686 .get(&snapshot.remote_id())
8687 .is_some_and(|servers| servers.contains(server_id))
8688 })
8689 })
8690 .collect::<Vec<_>>()
8691 });
8692
8693 let mut response_results = server_ids
8694 .into_iter()
8695 .map(|server_id| {
8696 let task = self.request_lsp(
8697 buffer.clone(),
8698 LanguageServerToQuery::Other(server_id),
8699 request.clone(),
8700 cx,
8701 );
8702 async move { (server_id, task.await) }
8703 })
8704 .collect::<FuturesUnordered<_>>();
8705
8706 cx.background_spawn(async move {
8707 let mut responses = Vec::with_capacity(response_results.len());
8708 while let Some((server_id, response_result)) = response_results.next().await {
8709 match response_result {
8710 Ok(response) => responses.push((server_id, response)),
8711 // rust-analyzer likes to error with this when its still loading up
8712 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8713 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8714 }
8715 }
8716 responses
8717 })
8718 }
8719
8720 async fn handle_lsp_get_completions(
8721 this: Entity<Self>,
8722 envelope: TypedEnvelope<proto::GetCompletions>,
8723 mut cx: AsyncApp,
8724 ) -> Result<proto::GetCompletionsResponse> {
8725 let sender_id = envelope.original_sender_id().unwrap_or_default();
8726
8727 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8728 let buffer_handle = this.update(&mut cx, |this, cx| {
8729 this.buffer_store.read(cx).get_existing(buffer_id)
8730 })??;
8731 let request = GetCompletions::from_proto(
8732 envelope.payload,
8733 this.clone(),
8734 buffer_handle.clone(),
8735 cx.clone(),
8736 )
8737 .await?;
8738
8739 let server_to_query = match request.server_id {
8740 Some(server_id) => LanguageServerToQuery::Other(server_id),
8741 None => LanguageServerToQuery::FirstCapable,
8742 };
8743
8744 let response = this
8745 .update(&mut cx, |this, cx| {
8746 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8747 })?
8748 .await?;
8749 this.update(&mut cx, |this, cx| {
8750 Ok(GetCompletions::response_to_proto(
8751 response,
8752 this,
8753 sender_id,
8754 &buffer_handle.read(cx).version(),
8755 cx,
8756 ))
8757 })?
8758 }
8759
8760 async fn handle_lsp_command<T: LspCommand>(
8761 this: Entity<Self>,
8762 envelope: TypedEnvelope<T::ProtoRequest>,
8763 mut cx: AsyncApp,
8764 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8765 where
8766 <T::LspRequest as lsp::request::Request>::Params: Send,
8767 <T::LspRequest as lsp::request::Request>::Result: Send,
8768 {
8769 let sender_id = envelope.original_sender_id().unwrap_or_default();
8770 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8771 let buffer_handle = this.update(&mut cx, |this, cx| {
8772 this.buffer_store.read(cx).get_existing(buffer_id)
8773 })??;
8774 let request = T::from_proto(
8775 envelope.payload,
8776 this.clone(),
8777 buffer_handle.clone(),
8778 cx.clone(),
8779 )
8780 .await?;
8781 let response = this
8782 .update(&mut cx, |this, cx| {
8783 this.request_lsp(
8784 buffer_handle.clone(),
8785 LanguageServerToQuery::FirstCapable,
8786 request,
8787 cx,
8788 )
8789 })?
8790 .await?;
8791 this.update(&mut cx, |this, cx| {
8792 Ok(T::response_to_proto(
8793 response,
8794 this,
8795 sender_id,
8796 &buffer_handle.read(cx).version(),
8797 cx,
8798 ))
8799 })?
8800 }
8801
8802 async fn handle_lsp_query(
8803 lsp_store: Entity<Self>,
8804 envelope: TypedEnvelope<proto::LspQuery>,
8805 mut cx: AsyncApp,
8806 ) -> Result<proto::Ack> {
8807 use proto::lsp_query::Request;
8808 let sender_id = envelope.original_sender_id().unwrap_or_default();
8809 let lsp_query = envelope.payload;
8810 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8811 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8812 match lsp_query.request.context("invalid LSP query request")? {
8813 Request::GetReferences(get_references) => {
8814 let position = get_references.position.clone().and_then(deserialize_anchor);
8815 Self::query_lsp_locally::<GetReferences>(
8816 lsp_store,
8817 server_id,
8818 sender_id,
8819 lsp_request_id,
8820 get_references,
8821 position,
8822 &mut cx,
8823 )
8824 .await?;
8825 }
8826 Request::GetDocumentColor(get_document_color) => {
8827 Self::query_lsp_locally::<GetDocumentColor>(
8828 lsp_store,
8829 server_id,
8830 sender_id,
8831 lsp_request_id,
8832 get_document_color,
8833 None,
8834 &mut cx,
8835 )
8836 .await?;
8837 }
8838 Request::GetHover(get_hover) => {
8839 let position = get_hover.position.clone().and_then(deserialize_anchor);
8840 Self::query_lsp_locally::<GetHover>(
8841 lsp_store,
8842 server_id,
8843 sender_id,
8844 lsp_request_id,
8845 get_hover,
8846 position,
8847 &mut cx,
8848 )
8849 .await?;
8850 }
8851 Request::GetCodeActions(get_code_actions) => {
8852 Self::query_lsp_locally::<GetCodeActions>(
8853 lsp_store,
8854 server_id,
8855 sender_id,
8856 lsp_request_id,
8857 get_code_actions,
8858 None,
8859 &mut cx,
8860 )
8861 .await?;
8862 }
8863 Request::GetSignatureHelp(get_signature_help) => {
8864 let position = get_signature_help
8865 .position
8866 .clone()
8867 .and_then(deserialize_anchor);
8868 Self::query_lsp_locally::<GetSignatureHelp>(
8869 lsp_store,
8870 server_id,
8871 sender_id,
8872 lsp_request_id,
8873 get_signature_help,
8874 position,
8875 &mut cx,
8876 )
8877 .await?;
8878 }
8879 Request::GetCodeLens(get_code_lens) => {
8880 Self::query_lsp_locally::<GetCodeLens>(
8881 lsp_store,
8882 server_id,
8883 sender_id,
8884 lsp_request_id,
8885 get_code_lens,
8886 None,
8887 &mut cx,
8888 )
8889 .await?;
8890 }
8891 Request::GetDefinition(get_definition) => {
8892 let position = get_definition.position.clone().and_then(deserialize_anchor);
8893 Self::query_lsp_locally::<GetDefinitions>(
8894 lsp_store,
8895 server_id,
8896 sender_id,
8897 lsp_request_id,
8898 get_definition,
8899 position,
8900 &mut cx,
8901 )
8902 .await?;
8903 }
8904 Request::GetDeclaration(get_declaration) => {
8905 let position = get_declaration
8906 .position
8907 .clone()
8908 .and_then(deserialize_anchor);
8909 Self::query_lsp_locally::<GetDeclarations>(
8910 lsp_store,
8911 server_id,
8912 sender_id,
8913 lsp_request_id,
8914 get_declaration,
8915 position,
8916 &mut cx,
8917 )
8918 .await?;
8919 }
8920 Request::GetTypeDefinition(get_type_definition) => {
8921 let position = get_type_definition
8922 .position
8923 .clone()
8924 .and_then(deserialize_anchor);
8925 Self::query_lsp_locally::<GetTypeDefinitions>(
8926 lsp_store,
8927 server_id,
8928 sender_id,
8929 lsp_request_id,
8930 get_type_definition,
8931 position,
8932 &mut cx,
8933 )
8934 .await?;
8935 }
8936 Request::GetImplementation(get_implementation) => {
8937 let position = get_implementation
8938 .position
8939 .clone()
8940 .and_then(deserialize_anchor);
8941 Self::query_lsp_locally::<GetImplementations>(
8942 lsp_store,
8943 server_id,
8944 sender_id,
8945 lsp_request_id,
8946 get_implementation,
8947 position,
8948 &mut cx,
8949 )
8950 .await?;
8951 }
8952 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8953 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8954 let version = deserialize_version(get_document_diagnostics.buffer_version());
8955 let buffer = lsp_store.update(&mut cx, |this, cx| {
8956 this.buffer_store.read(cx).get_existing(buffer_id)
8957 })??;
8958 buffer
8959 .update(&mut cx, |buffer, _| {
8960 buffer.wait_for_version(version.clone())
8961 })?
8962 .await?;
8963 lsp_store.update(&mut cx, |lsp_store, cx| {
8964 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8965 let key = LspKey {
8966 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8967 server_queried: server_id,
8968 };
8969 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8970 ) {
8971 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8972 lsp_requests.clear();
8973 };
8974 }
8975
8976 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8977 existing_queries.insert(
8978 lsp_request_id,
8979 cx.spawn(async move |lsp_store, cx| {
8980 let diagnostics_pull = lsp_store
8981 .update(cx, |lsp_store, cx| {
8982 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8983 })
8984 .ok();
8985 if let Some(diagnostics_pull) = diagnostics_pull {
8986 match diagnostics_pull.await {
8987 Ok(()) => {}
8988 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8989 };
8990 }
8991 }),
8992 );
8993 })?;
8994 }
8995 Request::InlayHints(inlay_hints) => {
8996 let query_start = inlay_hints
8997 .start
8998 .clone()
8999 .and_then(deserialize_anchor)
9000 .context("invalid inlay hints range start")?;
9001 let query_end = inlay_hints
9002 .end
9003 .clone()
9004 .and_then(deserialize_anchor)
9005 .context("invalid inlay hints range end")?;
9006 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9007 &lsp_store,
9008 server_id,
9009 lsp_request_id,
9010 &inlay_hints,
9011 query_start..query_end,
9012 &mut cx,
9013 )
9014 .await
9015 .context("preparing inlay hints request")?;
9016 Self::query_lsp_locally::<InlayHints>(
9017 lsp_store,
9018 server_id,
9019 sender_id,
9020 lsp_request_id,
9021 inlay_hints,
9022 None,
9023 &mut cx,
9024 )
9025 .await
9026 .context("querying for inlay hints")?
9027 }
9028 }
9029 Ok(proto::Ack {})
9030 }
9031
9032 async fn handle_lsp_query_response(
9033 lsp_store: Entity<Self>,
9034 envelope: TypedEnvelope<proto::LspQueryResponse>,
9035 cx: AsyncApp,
9036 ) -> Result<()> {
9037 lsp_store.read_with(&cx, |lsp_store, _| {
9038 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9039 upstream_client.handle_lsp_response(envelope.clone());
9040 }
9041 })?;
9042 Ok(())
9043 }
9044
9045 async fn handle_apply_code_action(
9046 this: Entity<Self>,
9047 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9048 mut cx: AsyncApp,
9049 ) -> Result<proto::ApplyCodeActionResponse> {
9050 let sender_id = envelope.original_sender_id().unwrap_or_default();
9051 let action =
9052 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9053 let apply_code_action = this.update(&mut cx, |this, cx| {
9054 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9055 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9056 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9057 })??;
9058
9059 let project_transaction = apply_code_action.await?;
9060 let project_transaction = this.update(&mut cx, |this, cx| {
9061 this.buffer_store.update(cx, |buffer_store, cx| {
9062 buffer_store.serialize_project_transaction_for_peer(
9063 project_transaction,
9064 sender_id,
9065 cx,
9066 )
9067 })
9068 })?;
9069 Ok(proto::ApplyCodeActionResponse {
9070 transaction: Some(project_transaction),
9071 })
9072 }
9073
9074 async fn handle_register_buffer_with_language_servers(
9075 this: Entity<Self>,
9076 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9077 mut cx: AsyncApp,
9078 ) -> Result<proto::Ack> {
9079 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9080 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9081 this.update(&mut cx, |this, cx| {
9082 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9083 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9084 project_id: upstream_project_id,
9085 buffer_id: buffer_id.to_proto(),
9086 only_servers: envelope.payload.only_servers,
9087 });
9088 }
9089
9090 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9091 anyhow::bail!("buffer is not open");
9092 };
9093
9094 let handle = this.register_buffer_with_language_servers(
9095 &buffer,
9096 envelope
9097 .payload
9098 .only_servers
9099 .into_iter()
9100 .filter_map(|selector| {
9101 Some(match selector.selector? {
9102 proto::language_server_selector::Selector::ServerId(server_id) => {
9103 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9104 }
9105 proto::language_server_selector::Selector::Name(name) => {
9106 LanguageServerSelector::Name(LanguageServerName(
9107 SharedString::from(name),
9108 ))
9109 }
9110 })
9111 })
9112 .collect(),
9113 false,
9114 cx,
9115 );
9116 this.buffer_store().update(cx, |buffer_store, _| {
9117 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9118 });
9119
9120 Ok(())
9121 })??;
9122 Ok(proto::Ack {})
9123 }
9124
9125 async fn handle_rename_project_entry(
9126 this: Entity<Self>,
9127 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9128 mut cx: AsyncApp,
9129 ) -> Result<proto::ProjectEntryResponse> {
9130 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9131 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9132 let new_path =
9133 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9134
9135 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9136 .update(&mut cx, |this, cx| {
9137 let (worktree, entry) = this
9138 .worktree_store
9139 .read(cx)
9140 .worktree_and_entry_for_id(entry_id, cx)?;
9141 let new_worktree = this
9142 .worktree_store
9143 .read(cx)
9144 .worktree_for_id(new_worktree_id, cx)?;
9145 Some((
9146 this.worktree_store.clone(),
9147 worktree,
9148 new_worktree,
9149 entry.clone(),
9150 ))
9151 })?
9152 .context("worktree not found")?;
9153 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9154 (worktree.absolutize(&old_entry.path), worktree.id())
9155 })?;
9156 let new_abs_path =
9157 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9158
9159 let _transaction = Self::will_rename_entry(
9160 this.downgrade(),
9161 old_worktree_id,
9162 &old_abs_path,
9163 &new_abs_path,
9164 old_entry.is_dir(),
9165 cx.clone(),
9166 )
9167 .await;
9168 let response = WorktreeStore::handle_rename_project_entry(
9169 worktree_store,
9170 envelope.payload,
9171 cx.clone(),
9172 )
9173 .await;
9174 this.read_with(&cx, |this, _| {
9175 this.did_rename_entry(
9176 old_worktree_id,
9177 &old_abs_path,
9178 &new_abs_path,
9179 old_entry.is_dir(),
9180 );
9181 })
9182 .ok();
9183 response
9184 }
9185
9186 async fn handle_update_diagnostic_summary(
9187 this: Entity<Self>,
9188 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9189 mut cx: AsyncApp,
9190 ) -> Result<()> {
9191 this.update(&mut cx, |lsp_store, cx| {
9192 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9193 let mut updated_diagnostics_paths = HashMap::default();
9194 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9195 for message_summary in envelope
9196 .payload
9197 .summary
9198 .into_iter()
9199 .chain(envelope.payload.more_summaries)
9200 {
9201 let project_path = ProjectPath {
9202 worktree_id,
9203 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9204 };
9205 let path = project_path.path.clone();
9206 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9207 let summary = DiagnosticSummary {
9208 error_count: message_summary.error_count as usize,
9209 warning_count: message_summary.warning_count as usize,
9210 };
9211
9212 if summary.is_empty() {
9213 if let Some(worktree_summaries) =
9214 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9215 && let Some(summaries) = worktree_summaries.get_mut(&path)
9216 {
9217 summaries.remove(&server_id);
9218 if summaries.is_empty() {
9219 worktree_summaries.remove(&path);
9220 }
9221 }
9222 } else {
9223 lsp_store
9224 .diagnostic_summaries
9225 .entry(worktree_id)
9226 .or_default()
9227 .entry(path)
9228 .or_default()
9229 .insert(server_id, summary);
9230 }
9231
9232 if let Some((_, project_id)) = &lsp_store.downstream_client {
9233 match &mut diagnostics_summary {
9234 Some(diagnostics_summary) => {
9235 diagnostics_summary
9236 .more_summaries
9237 .push(proto::DiagnosticSummary {
9238 path: project_path.path.as_ref().to_proto(),
9239 language_server_id: server_id.0 as u64,
9240 error_count: summary.error_count as u32,
9241 warning_count: summary.warning_count as u32,
9242 })
9243 }
9244 None => {
9245 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9246 project_id: *project_id,
9247 worktree_id: worktree_id.to_proto(),
9248 summary: Some(proto::DiagnosticSummary {
9249 path: project_path.path.as_ref().to_proto(),
9250 language_server_id: server_id.0 as u64,
9251 error_count: summary.error_count as u32,
9252 warning_count: summary.warning_count as u32,
9253 }),
9254 more_summaries: Vec::new(),
9255 })
9256 }
9257 }
9258 }
9259 updated_diagnostics_paths
9260 .entry(server_id)
9261 .or_insert_with(Vec::new)
9262 .push(project_path);
9263 }
9264
9265 if let Some((diagnostics_summary, (downstream_client, _))) =
9266 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9267 {
9268 downstream_client.send(diagnostics_summary).log_err();
9269 }
9270 for (server_id, paths) in updated_diagnostics_paths {
9271 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9272 }
9273 Ok(())
9274 })?
9275 }
9276
9277 async fn handle_start_language_server(
9278 lsp_store: Entity<Self>,
9279 envelope: TypedEnvelope<proto::StartLanguageServer>,
9280 mut cx: AsyncApp,
9281 ) -> Result<()> {
9282 let server = envelope.payload.server.context("invalid server")?;
9283 let server_capabilities =
9284 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9285 .with_context(|| {
9286 format!(
9287 "incorrect server capabilities {}",
9288 envelope.payload.capabilities
9289 )
9290 })?;
9291 lsp_store.update(&mut cx, |lsp_store, cx| {
9292 let server_id = LanguageServerId(server.id as usize);
9293 let server_name = LanguageServerName::from_proto(server.name.clone());
9294 lsp_store
9295 .lsp_server_capabilities
9296 .insert(server_id, server_capabilities);
9297 lsp_store.language_server_statuses.insert(
9298 server_id,
9299 LanguageServerStatus {
9300 name: server_name.clone(),
9301 pending_work: Default::default(),
9302 has_pending_diagnostic_updates: false,
9303 progress_tokens: Default::default(),
9304 worktree: server.worktree_id.map(WorktreeId::from_proto),
9305 binary: None,
9306 configuration: None,
9307 workspace_folders: BTreeSet::new(),
9308 },
9309 );
9310 cx.emit(LspStoreEvent::LanguageServerAdded(
9311 server_id,
9312 server_name,
9313 server.worktree_id.map(WorktreeId::from_proto),
9314 ));
9315 cx.notify();
9316 })?;
9317 Ok(())
9318 }
9319
9320 async fn handle_update_language_server(
9321 lsp_store: Entity<Self>,
9322 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9323 mut cx: AsyncApp,
9324 ) -> Result<()> {
9325 lsp_store.update(&mut cx, |lsp_store, cx| {
9326 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9327
9328 match envelope.payload.variant.context("invalid variant")? {
9329 proto::update_language_server::Variant::WorkStart(payload) => {
9330 lsp_store.on_lsp_work_start(
9331 language_server_id,
9332 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9333 .context("invalid progress token value")?,
9334 LanguageServerProgress {
9335 title: payload.title,
9336 is_disk_based_diagnostics_progress: false,
9337 is_cancellable: payload.is_cancellable.unwrap_or(false),
9338 message: payload.message,
9339 percentage: payload.percentage.map(|p| p as usize),
9340 last_update_at: cx.background_executor().now(),
9341 },
9342 cx,
9343 );
9344 }
9345 proto::update_language_server::Variant::WorkProgress(payload) => {
9346 lsp_store.on_lsp_work_progress(
9347 language_server_id,
9348 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9349 .context("invalid progress token value")?,
9350 LanguageServerProgress {
9351 title: None,
9352 is_disk_based_diagnostics_progress: false,
9353 is_cancellable: payload.is_cancellable.unwrap_or(false),
9354 message: payload.message,
9355 percentage: payload.percentage.map(|p| p as usize),
9356 last_update_at: cx.background_executor().now(),
9357 },
9358 cx,
9359 );
9360 }
9361
9362 proto::update_language_server::Variant::WorkEnd(payload) => {
9363 lsp_store.on_lsp_work_end(
9364 language_server_id,
9365 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9366 .context("invalid progress token value")?,
9367 cx,
9368 );
9369 }
9370
9371 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9372 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9373 }
9374
9375 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9376 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9377 }
9378
9379 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9380 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9381 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9382 cx.emit(LspStoreEvent::LanguageServerUpdate {
9383 language_server_id,
9384 name: envelope
9385 .payload
9386 .server_name
9387 .map(SharedString::new)
9388 .map(LanguageServerName),
9389 message: non_lsp,
9390 });
9391 }
9392 }
9393
9394 Ok(())
9395 })?
9396 }
9397
9398 async fn handle_language_server_log(
9399 this: Entity<Self>,
9400 envelope: TypedEnvelope<proto::LanguageServerLog>,
9401 mut cx: AsyncApp,
9402 ) -> Result<()> {
9403 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9404 let log_type = envelope
9405 .payload
9406 .log_type
9407 .map(LanguageServerLogType::from_proto)
9408 .context("invalid language server log type")?;
9409
9410 let message = envelope.payload.message;
9411
9412 this.update(&mut cx, |_, cx| {
9413 cx.emit(LspStoreEvent::LanguageServerLog(
9414 language_server_id,
9415 log_type,
9416 message,
9417 ));
9418 })
9419 }
9420
9421 async fn handle_lsp_ext_cancel_flycheck(
9422 lsp_store: Entity<Self>,
9423 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9424 cx: AsyncApp,
9425 ) -> Result<proto::Ack> {
9426 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9427 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9428 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9429 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9430 } else {
9431 None
9432 }
9433 })?;
9434 if let Some(task) = task {
9435 task.context("handling lsp ext cancel flycheck")?;
9436 }
9437
9438 Ok(proto::Ack {})
9439 }
9440
9441 async fn handle_lsp_ext_run_flycheck(
9442 lsp_store: Entity<Self>,
9443 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9444 mut cx: AsyncApp,
9445 ) -> Result<proto::Ack> {
9446 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9447 lsp_store.update(&mut cx, |lsp_store, cx| {
9448 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9449 let text_document = if envelope.payload.current_file_only {
9450 let buffer_id = envelope
9451 .payload
9452 .buffer_id
9453 .map(|id| BufferId::new(id))
9454 .transpose()?;
9455 buffer_id
9456 .and_then(|buffer_id| {
9457 lsp_store
9458 .buffer_store()
9459 .read(cx)
9460 .get(buffer_id)
9461 .and_then(|buffer| {
9462 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9463 })
9464 .map(|path| make_text_document_identifier(&path))
9465 })
9466 .transpose()?
9467 } else {
9468 None
9469 };
9470 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9471 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9472 )?;
9473 }
9474 anyhow::Ok(())
9475 })??;
9476
9477 Ok(proto::Ack {})
9478 }
9479
9480 async fn handle_lsp_ext_clear_flycheck(
9481 lsp_store: Entity<Self>,
9482 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9483 cx: AsyncApp,
9484 ) -> Result<proto::Ack> {
9485 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9486 lsp_store
9487 .read_with(&cx, |lsp_store, _| {
9488 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9489 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9490 } else {
9491 None
9492 }
9493 })
9494 .context("handling lsp ext clear flycheck")?;
9495
9496 Ok(proto::Ack {})
9497 }
9498
9499 pub fn disk_based_diagnostics_started(
9500 &mut self,
9501 language_server_id: LanguageServerId,
9502 cx: &mut Context<Self>,
9503 ) {
9504 if let Some(language_server_status) =
9505 self.language_server_statuses.get_mut(&language_server_id)
9506 {
9507 language_server_status.has_pending_diagnostic_updates = true;
9508 }
9509
9510 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9511 cx.emit(LspStoreEvent::LanguageServerUpdate {
9512 language_server_id,
9513 name: self
9514 .language_server_adapter_for_id(language_server_id)
9515 .map(|adapter| adapter.name()),
9516 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9517 Default::default(),
9518 ),
9519 })
9520 }
9521
9522 pub fn disk_based_diagnostics_finished(
9523 &mut self,
9524 language_server_id: LanguageServerId,
9525 cx: &mut Context<Self>,
9526 ) {
9527 if let Some(language_server_status) =
9528 self.language_server_statuses.get_mut(&language_server_id)
9529 {
9530 language_server_status.has_pending_diagnostic_updates = false;
9531 }
9532
9533 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9534 cx.emit(LspStoreEvent::LanguageServerUpdate {
9535 language_server_id,
9536 name: self
9537 .language_server_adapter_for_id(language_server_id)
9538 .map(|adapter| adapter.name()),
9539 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9540 Default::default(),
9541 ),
9542 })
9543 }
9544
9545 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9546 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9547 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9548 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9549 // the language server might take some time to publish diagnostics.
9550 fn simulate_disk_based_diagnostics_events_if_needed(
9551 &mut self,
9552 language_server_id: LanguageServerId,
9553 cx: &mut Context<Self>,
9554 ) {
9555 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9556
9557 let Some(LanguageServerState::Running {
9558 simulate_disk_based_diagnostics_completion,
9559 adapter,
9560 ..
9561 }) = self
9562 .as_local_mut()
9563 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9564 else {
9565 return;
9566 };
9567
9568 if adapter.disk_based_diagnostics_progress_token.is_some() {
9569 return;
9570 }
9571
9572 let prev_task =
9573 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9574 cx.background_executor()
9575 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9576 .await;
9577
9578 this.update(cx, |this, cx| {
9579 this.disk_based_diagnostics_finished(language_server_id, cx);
9580
9581 if let Some(LanguageServerState::Running {
9582 simulate_disk_based_diagnostics_completion,
9583 ..
9584 }) = this.as_local_mut().and_then(|local_store| {
9585 local_store.language_servers.get_mut(&language_server_id)
9586 }) {
9587 *simulate_disk_based_diagnostics_completion = None;
9588 }
9589 })
9590 .ok();
9591 }));
9592
9593 if prev_task.is_none() {
9594 self.disk_based_diagnostics_started(language_server_id, cx);
9595 }
9596 }
9597
9598 pub fn language_server_statuses(
9599 &self,
9600 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9601 self.language_server_statuses
9602 .iter()
9603 .map(|(key, value)| (*key, value))
9604 }
9605
9606 pub(super) fn did_rename_entry(
9607 &self,
9608 worktree_id: WorktreeId,
9609 old_path: &Path,
9610 new_path: &Path,
9611 is_dir: bool,
9612 ) {
9613 maybe!({
9614 let local_store = self.as_local()?;
9615
9616 let old_uri = lsp::Uri::from_file_path(old_path)
9617 .ok()
9618 .map(|uri| uri.to_string())?;
9619 let new_uri = lsp::Uri::from_file_path(new_path)
9620 .ok()
9621 .map(|uri| uri.to_string())?;
9622
9623 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9624 let Some(filter) = local_store
9625 .language_server_paths_watched_for_rename
9626 .get(&language_server.server_id())
9627 else {
9628 continue;
9629 };
9630
9631 if filter.should_send_did_rename(&old_uri, is_dir) {
9632 language_server
9633 .notify::<DidRenameFiles>(RenameFilesParams {
9634 files: vec![FileRename {
9635 old_uri: old_uri.clone(),
9636 new_uri: new_uri.clone(),
9637 }],
9638 })
9639 .ok();
9640 }
9641 }
9642 Some(())
9643 });
9644 }
9645
9646 pub(super) fn will_rename_entry(
9647 this: WeakEntity<Self>,
9648 worktree_id: WorktreeId,
9649 old_path: &Path,
9650 new_path: &Path,
9651 is_dir: bool,
9652 cx: AsyncApp,
9653 ) -> Task<ProjectTransaction> {
9654 let old_uri = lsp::Uri::from_file_path(old_path)
9655 .ok()
9656 .map(|uri| uri.to_string());
9657 let new_uri = lsp::Uri::from_file_path(new_path)
9658 .ok()
9659 .map(|uri| uri.to_string());
9660 cx.spawn(async move |cx| {
9661 let mut tasks = vec![];
9662 this.update(cx, |this, cx| {
9663 let local_store = this.as_local()?;
9664 let old_uri = old_uri?;
9665 let new_uri = new_uri?;
9666 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9667 let Some(filter) = local_store
9668 .language_server_paths_watched_for_rename
9669 .get(&language_server.server_id())
9670 else {
9671 continue;
9672 };
9673
9674 if filter.should_send_will_rename(&old_uri, is_dir) {
9675 let apply_edit = cx.spawn({
9676 let old_uri = old_uri.clone();
9677 let new_uri = new_uri.clone();
9678 let language_server = language_server.clone();
9679 async move |this, cx| {
9680 let edit = language_server
9681 .request::<WillRenameFiles>(RenameFilesParams {
9682 files: vec![FileRename { old_uri, new_uri }],
9683 })
9684 .await
9685 .into_response()
9686 .context("will rename files")
9687 .log_err()
9688 .flatten()?;
9689
9690 let transaction = LocalLspStore::deserialize_workspace_edit(
9691 this.upgrade()?,
9692 edit,
9693 false,
9694 language_server.clone(),
9695 cx,
9696 )
9697 .await
9698 .ok()?;
9699 Some(transaction)
9700 }
9701 });
9702 tasks.push(apply_edit);
9703 }
9704 }
9705 Some(())
9706 })
9707 .ok()
9708 .flatten();
9709 let mut merged_transaction = ProjectTransaction::default();
9710 for task in tasks {
9711 // Await on tasks sequentially so that the order of application of edits is deterministic
9712 // (at least with regards to the order of registration of language servers)
9713 if let Some(transaction) = task.await {
9714 for (buffer, buffer_transaction) in transaction.0 {
9715 merged_transaction.0.insert(buffer, buffer_transaction);
9716 }
9717 }
9718 }
9719 merged_transaction
9720 })
9721 }
9722
9723 fn lsp_notify_abs_paths_changed(
9724 &mut self,
9725 server_id: LanguageServerId,
9726 changes: Vec<PathEvent>,
9727 ) {
9728 maybe!({
9729 let server = self.language_server_for_id(server_id)?;
9730 let changes = changes
9731 .into_iter()
9732 .filter_map(|event| {
9733 let typ = match event.kind? {
9734 PathEventKind::Created => lsp::FileChangeType::CREATED,
9735 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9736 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9737 };
9738 Some(lsp::FileEvent {
9739 uri: file_path_to_lsp_url(&event.path).log_err()?,
9740 typ,
9741 })
9742 })
9743 .collect::<Vec<_>>();
9744 if !changes.is_empty() {
9745 server
9746 .notify::<lsp::notification::DidChangeWatchedFiles>(
9747 lsp::DidChangeWatchedFilesParams { changes },
9748 )
9749 .ok();
9750 }
9751 Some(())
9752 });
9753 }
9754
9755 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9756 self.as_local()?.language_server_for_id(id)
9757 }
9758
9759 fn on_lsp_progress(
9760 &mut self,
9761 progress_params: lsp::ProgressParams,
9762 language_server_id: LanguageServerId,
9763 disk_based_diagnostics_progress_token: Option<String>,
9764 cx: &mut Context<Self>,
9765 ) {
9766 match progress_params.value {
9767 lsp::ProgressParamsValue::WorkDone(progress) => {
9768 self.handle_work_done_progress(
9769 progress,
9770 language_server_id,
9771 disk_based_diagnostics_progress_token,
9772 ProgressToken::from_lsp(progress_params.token),
9773 cx,
9774 );
9775 }
9776 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9777 let registration_id = match progress_params.token {
9778 lsp::NumberOrString::Number(_) => None,
9779 lsp::NumberOrString::String(token) => token
9780 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9781 .map(|(_, id)| id.to_owned()),
9782 };
9783 if let Some(LanguageServerState::Running {
9784 workspace_diagnostics_refresh_tasks,
9785 ..
9786 }) = self
9787 .as_local_mut()
9788 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9789 && let Some(workspace_diagnostics) =
9790 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9791 {
9792 workspace_diagnostics.progress_tx.try_send(()).ok();
9793 self.apply_workspace_diagnostic_report(
9794 language_server_id,
9795 report,
9796 registration_id.map(SharedString::from),
9797 cx,
9798 )
9799 }
9800 }
9801 }
9802 }
9803
9804 fn handle_work_done_progress(
9805 &mut self,
9806 progress: lsp::WorkDoneProgress,
9807 language_server_id: LanguageServerId,
9808 disk_based_diagnostics_progress_token: Option<String>,
9809 token: ProgressToken,
9810 cx: &mut Context<Self>,
9811 ) {
9812 let language_server_status =
9813 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9814 status
9815 } else {
9816 return;
9817 };
9818
9819 if !language_server_status.progress_tokens.contains(&token) {
9820 return;
9821 }
9822
9823 let is_disk_based_diagnostics_progress =
9824 if let (Some(disk_based_token), ProgressToken::String(token)) =
9825 (&disk_based_diagnostics_progress_token, &token)
9826 {
9827 token.starts_with(disk_based_token)
9828 } else {
9829 false
9830 };
9831
9832 match progress {
9833 lsp::WorkDoneProgress::Begin(report) => {
9834 if is_disk_based_diagnostics_progress {
9835 self.disk_based_diagnostics_started(language_server_id, cx);
9836 }
9837 self.on_lsp_work_start(
9838 language_server_id,
9839 token.clone(),
9840 LanguageServerProgress {
9841 title: Some(report.title),
9842 is_disk_based_diagnostics_progress,
9843 is_cancellable: report.cancellable.unwrap_or(false),
9844 message: report.message.clone(),
9845 percentage: report.percentage.map(|p| p as usize),
9846 last_update_at: cx.background_executor().now(),
9847 },
9848 cx,
9849 );
9850 }
9851 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9852 language_server_id,
9853 token,
9854 LanguageServerProgress {
9855 title: None,
9856 is_disk_based_diagnostics_progress,
9857 is_cancellable: report.cancellable.unwrap_or(false),
9858 message: report.message,
9859 percentage: report.percentage.map(|p| p as usize),
9860 last_update_at: cx.background_executor().now(),
9861 },
9862 cx,
9863 ),
9864 lsp::WorkDoneProgress::End(_) => {
9865 language_server_status.progress_tokens.remove(&token);
9866 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9867 if is_disk_based_diagnostics_progress {
9868 self.disk_based_diagnostics_finished(language_server_id, cx);
9869 }
9870 }
9871 }
9872 }
9873
9874 fn on_lsp_work_start(
9875 &mut self,
9876 language_server_id: LanguageServerId,
9877 token: ProgressToken,
9878 progress: LanguageServerProgress,
9879 cx: &mut Context<Self>,
9880 ) {
9881 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9882 status.pending_work.insert(token.clone(), progress.clone());
9883 cx.notify();
9884 }
9885 cx.emit(LspStoreEvent::LanguageServerUpdate {
9886 language_server_id,
9887 name: self
9888 .language_server_adapter_for_id(language_server_id)
9889 .map(|adapter| adapter.name()),
9890 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9891 token: Some(token.to_proto()),
9892 title: progress.title,
9893 message: progress.message,
9894 percentage: progress.percentage.map(|p| p as u32),
9895 is_cancellable: Some(progress.is_cancellable),
9896 }),
9897 })
9898 }
9899
9900 fn on_lsp_work_progress(
9901 &mut self,
9902 language_server_id: LanguageServerId,
9903 token: ProgressToken,
9904 progress: LanguageServerProgress,
9905 cx: &mut Context<Self>,
9906 ) {
9907 let mut did_update = false;
9908 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9909 match status.pending_work.entry(token.clone()) {
9910 btree_map::Entry::Vacant(entry) => {
9911 entry.insert(progress.clone());
9912 did_update = true;
9913 }
9914 btree_map::Entry::Occupied(mut entry) => {
9915 let entry = entry.get_mut();
9916 if (progress.last_update_at - entry.last_update_at)
9917 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9918 {
9919 entry.last_update_at = progress.last_update_at;
9920 if progress.message.is_some() {
9921 entry.message = progress.message.clone();
9922 }
9923 if progress.percentage.is_some() {
9924 entry.percentage = progress.percentage;
9925 }
9926 if progress.is_cancellable != entry.is_cancellable {
9927 entry.is_cancellable = progress.is_cancellable;
9928 }
9929 did_update = true;
9930 }
9931 }
9932 }
9933 }
9934
9935 if did_update {
9936 cx.emit(LspStoreEvent::LanguageServerUpdate {
9937 language_server_id,
9938 name: self
9939 .language_server_adapter_for_id(language_server_id)
9940 .map(|adapter| adapter.name()),
9941 message: proto::update_language_server::Variant::WorkProgress(
9942 proto::LspWorkProgress {
9943 token: Some(token.to_proto()),
9944 message: progress.message,
9945 percentage: progress.percentage.map(|p| p as u32),
9946 is_cancellable: Some(progress.is_cancellable),
9947 },
9948 ),
9949 })
9950 }
9951 }
9952
9953 fn on_lsp_work_end(
9954 &mut self,
9955 language_server_id: LanguageServerId,
9956 token: ProgressToken,
9957 cx: &mut Context<Self>,
9958 ) {
9959 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9960 if let Some(work) = status.pending_work.remove(&token)
9961 && !work.is_disk_based_diagnostics_progress
9962 {
9963 cx.emit(LspStoreEvent::RefreshInlayHints {
9964 server_id: language_server_id,
9965 request_id: None,
9966 });
9967 }
9968 cx.notify();
9969 }
9970
9971 cx.emit(LspStoreEvent::LanguageServerUpdate {
9972 language_server_id,
9973 name: self
9974 .language_server_adapter_for_id(language_server_id)
9975 .map(|adapter| adapter.name()),
9976 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9977 token: Some(token.to_proto()),
9978 }),
9979 })
9980 }
9981
9982 pub async fn handle_resolve_completion_documentation(
9983 this: Entity<Self>,
9984 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9985 mut cx: AsyncApp,
9986 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9987 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9988
9989 let completion = this
9990 .read_with(&cx, |this, cx| {
9991 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9992 let server = this
9993 .language_server_for_id(id)
9994 .with_context(|| format!("No language server {id}"))?;
9995
9996 anyhow::Ok(cx.background_spawn(async move {
9997 let can_resolve = server
9998 .capabilities()
9999 .completion_provider
10000 .as_ref()
10001 .and_then(|options| options.resolve_provider)
10002 .unwrap_or(false);
10003 if can_resolve {
10004 server
10005 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10006 .await
10007 .into_response()
10008 .context("resolve completion item")
10009 } else {
10010 anyhow::Ok(lsp_completion)
10011 }
10012 }))
10013 })??
10014 .await?;
10015
10016 let mut documentation_is_markdown = false;
10017 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10018 let documentation = match completion.documentation {
10019 Some(lsp::Documentation::String(text)) => text,
10020
10021 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10022 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10023 value
10024 }
10025
10026 _ => String::new(),
10027 };
10028
10029 // If we have a new buffer_id, that means we're talking to a new client
10030 // and want to check for new text_edits in the completion too.
10031 let mut old_replace_start = None;
10032 let mut old_replace_end = None;
10033 let mut old_insert_start = None;
10034 let mut old_insert_end = None;
10035 let mut new_text = String::default();
10036 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10037 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10038 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10039 anyhow::Ok(buffer.read(cx).snapshot())
10040 })??;
10041
10042 if let Some(text_edit) = completion.text_edit.as_ref() {
10043 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10044
10045 if let Some(mut edit) = edit {
10046 LineEnding::normalize(&mut edit.new_text);
10047
10048 new_text = edit.new_text;
10049 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10050 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10051 if let Some(insert_range) = edit.insert_range {
10052 old_insert_start = Some(serialize_anchor(&insert_range.start));
10053 old_insert_end = Some(serialize_anchor(&insert_range.end));
10054 }
10055 }
10056 }
10057 }
10058
10059 Ok(proto::ResolveCompletionDocumentationResponse {
10060 documentation,
10061 documentation_is_markdown,
10062 old_replace_start,
10063 old_replace_end,
10064 new_text,
10065 lsp_completion,
10066 old_insert_start,
10067 old_insert_end,
10068 })
10069 }
10070
10071 async fn handle_on_type_formatting(
10072 this: Entity<Self>,
10073 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10074 mut cx: AsyncApp,
10075 ) -> Result<proto::OnTypeFormattingResponse> {
10076 let on_type_formatting = this.update(&mut cx, |this, cx| {
10077 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10078 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10079 let position = envelope
10080 .payload
10081 .position
10082 .and_then(deserialize_anchor)
10083 .context("invalid position")?;
10084 anyhow::Ok(this.apply_on_type_formatting(
10085 buffer,
10086 position,
10087 envelope.payload.trigger.clone(),
10088 cx,
10089 ))
10090 })??;
10091
10092 let transaction = on_type_formatting
10093 .await?
10094 .as_ref()
10095 .map(language::proto::serialize_transaction);
10096 Ok(proto::OnTypeFormattingResponse { transaction })
10097 }
10098
10099 async fn handle_refresh_inlay_hints(
10100 lsp_store: Entity<Self>,
10101 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10102 mut cx: AsyncApp,
10103 ) -> Result<proto::Ack> {
10104 lsp_store.update(&mut cx, |_, cx| {
10105 cx.emit(LspStoreEvent::RefreshInlayHints {
10106 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10107 request_id: envelope.payload.request_id.map(|id| id as usize),
10108 });
10109 })?;
10110 Ok(proto::Ack {})
10111 }
10112
10113 async fn handle_pull_workspace_diagnostics(
10114 lsp_store: Entity<Self>,
10115 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10116 mut cx: AsyncApp,
10117 ) -> Result<proto::Ack> {
10118 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10119 lsp_store.update(&mut cx, |lsp_store, _| {
10120 lsp_store.pull_workspace_diagnostics(server_id);
10121 })?;
10122 Ok(proto::Ack {})
10123 }
10124
10125 async fn handle_get_color_presentation(
10126 lsp_store: Entity<Self>,
10127 envelope: TypedEnvelope<proto::GetColorPresentation>,
10128 mut cx: AsyncApp,
10129 ) -> Result<proto::GetColorPresentationResponse> {
10130 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10131 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10132 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10133 })??;
10134
10135 let color = envelope
10136 .payload
10137 .color
10138 .context("invalid color resolve request")?;
10139 let start = color
10140 .lsp_range_start
10141 .context("invalid color resolve request")?;
10142 let end = color
10143 .lsp_range_end
10144 .context("invalid color resolve request")?;
10145
10146 let color = DocumentColor {
10147 lsp_range: lsp::Range {
10148 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10149 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10150 },
10151 color: lsp::Color {
10152 red: color.red,
10153 green: color.green,
10154 blue: color.blue,
10155 alpha: color.alpha,
10156 },
10157 resolved: false,
10158 color_presentations: Vec::new(),
10159 };
10160 let resolved_color = lsp_store
10161 .update(&mut cx, |lsp_store, cx| {
10162 lsp_store.resolve_color_presentation(
10163 color,
10164 buffer.clone(),
10165 LanguageServerId(envelope.payload.server_id as usize),
10166 cx,
10167 )
10168 })?
10169 .await
10170 .context("resolving color presentation")?;
10171
10172 Ok(proto::GetColorPresentationResponse {
10173 presentations: resolved_color
10174 .color_presentations
10175 .into_iter()
10176 .map(|presentation| proto::ColorPresentation {
10177 label: presentation.label.to_string(),
10178 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10179 additional_text_edits: presentation
10180 .additional_text_edits
10181 .into_iter()
10182 .map(serialize_lsp_edit)
10183 .collect(),
10184 })
10185 .collect(),
10186 })
10187 }
10188
10189 async fn handle_resolve_inlay_hint(
10190 lsp_store: Entity<Self>,
10191 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10192 mut cx: AsyncApp,
10193 ) -> Result<proto::ResolveInlayHintResponse> {
10194 let proto_hint = envelope
10195 .payload
10196 .hint
10197 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10198 let hint = InlayHints::proto_to_project_hint(proto_hint)
10199 .context("resolved proto inlay hint conversion")?;
10200 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10201 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10202 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10203 })??;
10204 let response_hint = lsp_store
10205 .update(&mut cx, |lsp_store, cx| {
10206 lsp_store.resolve_inlay_hint(
10207 hint,
10208 buffer,
10209 LanguageServerId(envelope.payload.language_server_id as usize),
10210 cx,
10211 )
10212 })?
10213 .await
10214 .context("inlay hints fetch")?;
10215 Ok(proto::ResolveInlayHintResponse {
10216 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10217 })
10218 }
10219
10220 async fn handle_refresh_code_lens(
10221 this: Entity<Self>,
10222 _: TypedEnvelope<proto::RefreshCodeLens>,
10223 mut cx: AsyncApp,
10224 ) -> Result<proto::Ack> {
10225 this.update(&mut cx, |_, cx| {
10226 cx.emit(LspStoreEvent::RefreshCodeLens);
10227 })?;
10228 Ok(proto::Ack {})
10229 }
10230
10231 async fn handle_open_buffer_for_symbol(
10232 this: Entity<Self>,
10233 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10234 mut cx: AsyncApp,
10235 ) -> Result<proto::OpenBufferForSymbolResponse> {
10236 let peer_id = envelope.original_sender_id().unwrap_or_default();
10237 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10238 let symbol = Self::deserialize_symbol(symbol)?;
10239 this.read_with(&cx, |this, _| {
10240 if let SymbolLocation::OutsideProject {
10241 abs_path,
10242 signature,
10243 } = &symbol.path
10244 {
10245 let new_signature = this.symbol_signature(&abs_path);
10246 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10247 }
10248 Ok(())
10249 })??;
10250 let buffer = this
10251 .update(&mut cx, |this, cx| {
10252 this.open_buffer_for_symbol(
10253 &Symbol {
10254 language_server_name: symbol.language_server_name,
10255 source_worktree_id: symbol.source_worktree_id,
10256 source_language_server_id: symbol.source_language_server_id,
10257 path: symbol.path,
10258 name: symbol.name,
10259 kind: symbol.kind,
10260 range: symbol.range,
10261 label: CodeLabel::default(),
10262 },
10263 cx,
10264 )
10265 })?
10266 .await?;
10267
10268 this.update(&mut cx, |this, cx| {
10269 let is_private = buffer
10270 .read(cx)
10271 .file()
10272 .map(|f| f.is_private())
10273 .unwrap_or_default();
10274 if is_private {
10275 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10276 } else {
10277 this.buffer_store
10278 .update(cx, |buffer_store, cx| {
10279 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10280 })
10281 .detach_and_log_err(cx);
10282 let buffer_id = buffer.read(cx).remote_id().to_proto();
10283 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10284 }
10285 })?
10286 }
10287
10288 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10289 let mut hasher = Sha256::new();
10290 hasher.update(abs_path.to_string_lossy().as_bytes());
10291 hasher.update(self.nonce.to_be_bytes());
10292 hasher.finalize().as_slice().try_into().unwrap()
10293 }
10294
10295 pub async fn handle_get_project_symbols(
10296 this: Entity<Self>,
10297 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10298 mut cx: AsyncApp,
10299 ) -> Result<proto::GetProjectSymbolsResponse> {
10300 let symbols = this
10301 .update(&mut cx, |this, cx| {
10302 this.symbols(&envelope.payload.query, cx)
10303 })?
10304 .await?;
10305
10306 Ok(proto::GetProjectSymbolsResponse {
10307 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10308 })
10309 }
10310
10311 pub async fn handle_restart_language_servers(
10312 this: Entity<Self>,
10313 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10314 mut cx: AsyncApp,
10315 ) -> Result<proto::Ack> {
10316 this.update(&mut cx, |lsp_store, cx| {
10317 let buffers =
10318 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10319 lsp_store.restart_language_servers_for_buffers(
10320 buffers,
10321 envelope
10322 .payload
10323 .only_servers
10324 .into_iter()
10325 .filter_map(|selector| {
10326 Some(match selector.selector? {
10327 proto::language_server_selector::Selector::ServerId(server_id) => {
10328 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10329 }
10330 proto::language_server_selector::Selector::Name(name) => {
10331 LanguageServerSelector::Name(LanguageServerName(
10332 SharedString::from(name),
10333 ))
10334 }
10335 })
10336 })
10337 .collect(),
10338 cx,
10339 );
10340 })?;
10341
10342 Ok(proto::Ack {})
10343 }
10344
10345 pub async fn handle_stop_language_servers(
10346 lsp_store: Entity<Self>,
10347 envelope: TypedEnvelope<proto::StopLanguageServers>,
10348 mut cx: AsyncApp,
10349 ) -> Result<proto::Ack> {
10350 lsp_store.update(&mut cx, |lsp_store, cx| {
10351 if envelope.payload.all
10352 && envelope.payload.also_servers.is_empty()
10353 && envelope.payload.buffer_ids.is_empty()
10354 {
10355 lsp_store.stop_all_language_servers(cx);
10356 } else {
10357 let buffers =
10358 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10359 lsp_store
10360 .stop_language_servers_for_buffers(
10361 buffers,
10362 envelope
10363 .payload
10364 .also_servers
10365 .into_iter()
10366 .filter_map(|selector| {
10367 Some(match selector.selector? {
10368 proto::language_server_selector::Selector::ServerId(
10369 server_id,
10370 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10371 server_id,
10372 )),
10373 proto::language_server_selector::Selector::Name(name) => {
10374 LanguageServerSelector::Name(LanguageServerName(
10375 SharedString::from(name),
10376 ))
10377 }
10378 })
10379 })
10380 .collect(),
10381 cx,
10382 )
10383 .detach_and_log_err(cx);
10384 }
10385 })?;
10386
10387 Ok(proto::Ack {})
10388 }
10389
10390 pub async fn handle_cancel_language_server_work(
10391 lsp_store: Entity<Self>,
10392 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10393 mut cx: AsyncApp,
10394 ) -> Result<proto::Ack> {
10395 lsp_store.update(&mut cx, |lsp_store, cx| {
10396 if let Some(work) = envelope.payload.work {
10397 match work {
10398 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10399 let buffers =
10400 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10401 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10402 }
10403 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10404 let server_id = LanguageServerId::from_proto(work.language_server_id);
10405 let token = work
10406 .token
10407 .map(|token| {
10408 ProgressToken::from_proto(token)
10409 .context("invalid work progress token")
10410 })
10411 .transpose()?;
10412 lsp_store.cancel_language_server_work(server_id, token, cx);
10413 }
10414 }
10415 }
10416 anyhow::Ok(())
10417 })??;
10418
10419 Ok(proto::Ack {})
10420 }
10421
10422 fn buffer_ids_to_buffers(
10423 &mut self,
10424 buffer_ids: impl Iterator<Item = u64>,
10425 cx: &mut Context<Self>,
10426 ) -> Vec<Entity<Buffer>> {
10427 buffer_ids
10428 .into_iter()
10429 .flat_map(|buffer_id| {
10430 self.buffer_store
10431 .read(cx)
10432 .get(BufferId::new(buffer_id).log_err()?)
10433 })
10434 .collect::<Vec<_>>()
10435 }
10436
10437 async fn handle_apply_additional_edits_for_completion(
10438 this: Entity<Self>,
10439 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10440 mut cx: AsyncApp,
10441 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10442 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10443 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10444 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10445 let completion = Self::deserialize_completion(
10446 envelope.payload.completion.context("invalid completion")?,
10447 )?;
10448 anyhow::Ok((buffer, completion))
10449 })??;
10450
10451 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10452 this.apply_additional_edits_for_completion(
10453 buffer,
10454 Rc::new(RefCell::new(Box::new([Completion {
10455 replace_range: completion.replace_range,
10456 new_text: completion.new_text,
10457 source: completion.source,
10458 documentation: None,
10459 label: CodeLabel::default(),
10460 match_start: None,
10461 snippet_deduplication_key: None,
10462 insert_text_mode: None,
10463 icon_path: None,
10464 confirm: None,
10465 }]))),
10466 0,
10467 false,
10468 cx,
10469 )
10470 })?;
10471
10472 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10473 transaction: apply_additional_edits
10474 .await?
10475 .as_ref()
10476 .map(language::proto::serialize_transaction),
10477 })
10478 }
10479
10480 pub fn last_formatting_failure(&self) -> Option<&str> {
10481 self.last_formatting_failure.as_deref()
10482 }
10483
10484 pub fn reset_last_formatting_failure(&mut self) {
10485 self.last_formatting_failure = None;
10486 }
10487
10488 pub fn environment_for_buffer(
10489 &self,
10490 buffer: &Entity<Buffer>,
10491 cx: &mut Context<Self>,
10492 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10493 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10494 environment.update(cx, |env, cx| {
10495 env.buffer_environment(buffer, &self.worktree_store, cx)
10496 })
10497 } else {
10498 Task::ready(None).shared()
10499 }
10500 }
10501
10502 pub fn format(
10503 &mut self,
10504 buffers: HashSet<Entity<Buffer>>,
10505 target: LspFormatTarget,
10506 push_to_history: bool,
10507 trigger: FormatTrigger,
10508 cx: &mut Context<Self>,
10509 ) -> Task<anyhow::Result<ProjectTransaction>> {
10510 let logger = zlog::scoped!("format");
10511 if self.as_local().is_some() {
10512 zlog::trace!(logger => "Formatting locally");
10513 let logger = zlog::scoped!(logger => "local");
10514 let buffers = buffers
10515 .into_iter()
10516 .map(|buffer_handle| {
10517 let buffer = buffer_handle.read(cx);
10518 let buffer_abs_path = File::from_dyn(buffer.file())
10519 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10520
10521 (buffer_handle, buffer_abs_path, buffer.remote_id())
10522 })
10523 .collect::<Vec<_>>();
10524
10525 cx.spawn(async move |lsp_store, cx| {
10526 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10527
10528 for (handle, abs_path, id) in buffers {
10529 let env = lsp_store
10530 .update(cx, |lsp_store, cx| {
10531 lsp_store.environment_for_buffer(&handle, cx)
10532 })?
10533 .await;
10534
10535 let ranges = match &target {
10536 LspFormatTarget::Buffers => None,
10537 LspFormatTarget::Ranges(ranges) => {
10538 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10539 }
10540 };
10541
10542 formattable_buffers.push(FormattableBuffer {
10543 handle,
10544 abs_path,
10545 env,
10546 ranges,
10547 });
10548 }
10549 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10550
10551 let format_timer = zlog::time!(logger => "Formatting buffers");
10552 let result = LocalLspStore::format_locally(
10553 lsp_store.clone(),
10554 formattable_buffers,
10555 push_to_history,
10556 trigger,
10557 logger,
10558 cx,
10559 )
10560 .await;
10561 format_timer.end();
10562
10563 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10564
10565 lsp_store.update(cx, |lsp_store, _| {
10566 lsp_store.update_last_formatting_failure(&result);
10567 })?;
10568
10569 result
10570 })
10571 } else if let Some((client, project_id)) = self.upstream_client() {
10572 zlog::trace!(logger => "Formatting remotely");
10573 let logger = zlog::scoped!(logger => "remote");
10574 // Don't support formatting ranges via remote
10575 match target {
10576 LspFormatTarget::Buffers => {}
10577 LspFormatTarget::Ranges(_) => {
10578 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10579 return Task::ready(Ok(ProjectTransaction::default()));
10580 }
10581 }
10582
10583 let buffer_store = self.buffer_store();
10584 cx.spawn(async move |lsp_store, cx| {
10585 zlog::trace!(logger => "Sending remote format request");
10586 let request_timer = zlog::time!(logger => "remote format request");
10587 let result = client
10588 .request(proto::FormatBuffers {
10589 project_id,
10590 trigger: trigger as i32,
10591 buffer_ids: buffers
10592 .iter()
10593 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10594 .collect::<Result<_>>()?,
10595 })
10596 .await
10597 .and_then(|result| result.transaction.context("missing transaction"));
10598 request_timer.end();
10599
10600 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10601
10602 lsp_store.update(cx, |lsp_store, _| {
10603 lsp_store.update_last_formatting_failure(&result);
10604 })?;
10605
10606 let transaction_response = result?;
10607 let _timer = zlog::time!(logger => "deserializing project transaction");
10608 buffer_store
10609 .update(cx, |buffer_store, cx| {
10610 buffer_store.deserialize_project_transaction(
10611 transaction_response,
10612 push_to_history,
10613 cx,
10614 )
10615 })?
10616 .await
10617 })
10618 } else {
10619 zlog::trace!(logger => "Not formatting");
10620 Task::ready(Ok(ProjectTransaction::default()))
10621 }
10622 }
10623
10624 async fn handle_format_buffers(
10625 this: Entity<Self>,
10626 envelope: TypedEnvelope<proto::FormatBuffers>,
10627 mut cx: AsyncApp,
10628 ) -> Result<proto::FormatBuffersResponse> {
10629 let sender_id = envelope.original_sender_id().unwrap_or_default();
10630 let format = this.update(&mut cx, |this, cx| {
10631 let mut buffers = HashSet::default();
10632 for buffer_id in &envelope.payload.buffer_ids {
10633 let buffer_id = BufferId::new(*buffer_id)?;
10634 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10635 }
10636 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10637 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10638 })??;
10639
10640 let project_transaction = format.await?;
10641 let project_transaction = this.update(&mut cx, |this, cx| {
10642 this.buffer_store.update(cx, |buffer_store, cx| {
10643 buffer_store.serialize_project_transaction_for_peer(
10644 project_transaction,
10645 sender_id,
10646 cx,
10647 )
10648 })
10649 })?;
10650 Ok(proto::FormatBuffersResponse {
10651 transaction: Some(project_transaction),
10652 })
10653 }
10654
10655 async fn handle_apply_code_action_kind(
10656 this: Entity<Self>,
10657 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10658 mut cx: AsyncApp,
10659 ) -> Result<proto::ApplyCodeActionKindResponse> {
10660 let sender_id = envelope.original_sender_id().unwrap_or_default();
10661 let format = this.update(&mut cx, |this, cx| {
10662 let mut buffers = HashSet::default();
10663 for buffer_id in &envelope.payload.buffer_ids {
10664 let buffer_id = BufferId::new(*buffer_id)?;
10665 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10666 }
10667 let kind = match envelope.payload.kind.as_str() {
10668 "" => CodeActionKind::EMPTY,
10669 "quickfix" => CodeActionKind::QUICKFIX,
10670 "refactor" => CodeActionKind::REFACTOR,
10671 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10672 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10673 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10674 "source" => CodeActionKind::SOURCE,
10675 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10676 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10677 _ => anyhow::bail!(
10678 "Invalid code action kind {}",
10679 envelope.payload.kind.as_str()
10680 ),
10681 };
10682 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10683 })??;
10684
10685 let project_transaction = format.await?;
10686 let project_transaction = this.update(&mut cx, |this, cx| {
10687 this.buffer_store.update(cx, |buffer_store, cx| {
10688 buffer_store.serialize_project_transaction_for_peer(
10689 project_transaction,
10690 sender_id,
10691 cx,
10692 )
10693 })
10694 })?;
10695 Ok(proto::ApplyCodeActionKindResponse {
10696 transaction: Some(project_transaction),
10697 })
10698 }
10699
10700 async fn shutdown_language_server(
10701 server_state: Option<LanguageServerState>,
10702 name: LanguageServerName,
10703 cx: &mut AsyncApp,
10704 ) {
10705 let server = match server_state {
10706 Some(LanguageServerState::Starting { startup, .. }) => {
10707 let mut timer = cx
10708 .background_executor()
10709 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10710 .fuse();
10711
10712 select! {
10713 server = startup.fuse() => server,
10714 () = timer => {
10715 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10716 None
10717 },
10718 }
10719 }
10720
10721 Some(LanguageServerState::Running { server, .. }) => Some(server),
10722
10723 None => None,
10724 };
10725
10726 if let Some(server) = server
10727 && let Some(shutdown) = server.shutdown()
10728 {
10729 shutdown.await;
10730 }
10731 }
10732
10733 // Returns a list of all of the worktrees which no longer have a language server and the root path
10734 // for the stopped server
10735 fn stop_local_language_server(
10736 &mut self,
10737 server_id: LanguageServerId,
10738 cx: &mut Context<Self>,
10739 ) -> Task<()> {
10740 let local = match &mut self.mode {
10741 LspStoreMode::Local(local) => local,
10742 _ => {
10743 return Task::ready(());
10744 }
10745 };
10746
10747 // Remove this server ID from all entries in the given worktree.
10748 local
10749 .language_server_ids
10750 .retain(|_, state| state.id != server_id);
10751 self.buffer_store.update(cx, |buffer_store, cx| {
10752 for buffer in buffer_store.buffers() {
10753 buffer.update(cx, |buffer, cx| {
10754 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10755 buffer.set_completion_triggers(server_id, Default::default(), cx);
10756 });
10757 }
10758 });
10759
10760 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10761 summaries.retain(|path, summaries_by_server_id| {
10762 if summaries_by_server_id.remove(&server_id).is_some() {
10763 if let Some((client, project_id)) = self.downstream_client.clone() {
10764 client
10765 .send(proto::UpdateDiagnosticSummary {
10766 project_id,
10767 worktree_id: worktree_id.to_proto(),
10768 summary: Some(proto::DiagnosticSummary {
10769 path: path.as_ref().to_proto(),
10770 language_server_id: server_id.0 as u64,
10771 error_count: 0,
10772 warning_count: 0,
10773 }),
10774 more_summaries: Vec::new(),
10775 })
10776 .log_err();
10777 }
10778 !summaries_by_server_id.is_empty()
10779 } else {
10780 true
10781 }
10782 });
10783 }
10784
10785 let local = self.as_local_mut().unwrap();
10786 for diagnostics in local.diagnostics.values_mut() {
10787 diagnostics.retain(|_, diagnostics_by_server_id| {
10788 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10789 diagnostics_by_server_id.remove(ix);
10790 !diagnostics_by_server_id.is_empty()
10791 } else {
10792 true
10793 }
10794 });
10795 }
10796 local.language_server_watched_paths.remove(&server_id);
10797
10798 let server_state = local.language_servers.remove(&server_id);
10799 self.cleanup_lsp_data(server_id);
10800 let name = self
10801 .language_server_statuses
10802 .remove(&server_id)
10803 .map(|status| status.name)
10804 .or_else(|| {
10805 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10806 Some(adapter.name())
10807 } else {
10808 None
10809 }
10810 });
10811
10812 if let Some(name) = name {
10813 log::info!("stopping language server {name}");
10814 self.languages
10815 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10816 cx.notify();
10817
10818 return cx.spawn(async move |lsp_store, cx| {
10819 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10820 lsp_store
10821 .update(cx, |lsp_store, cx| {
10822 lsp_store
10823 .languages
10824 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10825 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10826 cx.notify();
10827 })
10828 .ok();
10829 });
10830 }
10831
10832 if server_state.is_some() {
10833 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10834 }
10835 Task::ready(())
10836 }
10837
10838 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10839 if let Some((client, project_id)) = self.upstream_client() {
10840 let request = client.request(proto::StopLanguageServers {
10841 project_id,
10842 buffer_ids: Vec::new(),
10843 also_servers: Vec::new(),
10844 all: true,
10845 });
10846 cx.background_spawn(request).detach_and_log_err(cx);
10847 } else {
10848 let Some(local) = self.as_local_mut() else {
10849 return;
10850 };
10851 let language_servers_to_stop = local
10852 .language_server_ids
10853 .values()
10854 .map(|state| state.id)
10855 .collect();
10856 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10857 let tasks = language_servers_to_stop
10858 .into_iter()
10859 .map(|server| self.stop_local_language_server(server, cx))
10860 .collect::<Vec<_>>();
10861 cx.background_spawn(async move {
10862 futures::future::join_all(tasks).await;
10863 })
10864 .detach();
10865 }
10866 }
10867
10868 pub fn restart_language_servers_for_buffers(
10869 &mut self,
10870 buffers: Vec<Entity<Buffer>>,
10871 only_restart_servers: HashSet<LanguageServerSelector>,
10872 cx: &mut Context<Self>,
10873 ) {
10874 if let Some((client, project_id)) = self.upstream_client() {
10875 let request = client.request(proto::RestartLanguageServers {
10876 project_id,
10877 buffer_ids: buffers
10878 .into_iter()
10879 .map(|b| b.read(cx).remote_id().to_proto())
10880 .collect(),
10881 only_servers: only_restart_servers
10882 .into_iter()
10883 .map(|selector| {
10884 let selector = match selector {
10885 LanguageServerSelector::Id(language_server_id) => {
10886 proto::language_server_selector::Selector::ServerId(
10887 language_server_id.to_proto(),
10888 )
10889 }
10890 LanguageServerSelector::Name(language_server_name) => {
10891 proto::language_server_selector::Selector::Name(
10892 language_server_name.to_string(),
10893 )
10894 }
10895 };
10896 proto::LanguageServerSelector {
10897 selector: Some(selector),
10898 }
10899 })
10900 .collect(),
10901 all: false,
10902 });
10903 cx.background_spawn(request).detach_and_log_err(cx);
10904 } else {
10905 let stop_task = if only_restart_servers.is_empty() {
10906 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10907 } else {
10908 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10909 };
10910 cx.spawn(async move |lsp_store, cx| {
10911 stop_task.await;
10912 lsp_store
10913 .update(cx, |lsp_store, cx| {
10914 for buffer in buffers {
10915 lsp_store.register_buffer_with_language_servers(
10916 &buffer,
10917 only_restart_servers.clone(),
10918 true,
10919 cx,
10920 );
10921 }
10922 })
10923 .ok()
10924 })
10925 .detach();
10926 }
10927 }
10928
10929 pub fn stop_language_servers_for_buffers(
10930 &mut self,
10931 buffers: Vec<Entity<Buffer>>,
10932 also_stop_servers: HashSet<LanguageServerSelector>,
10933 cx: &mut Context<Self>,
10934 ) -> Task<Result<()>> {
10935 if let Some((client, project_id)) = self.upstream_client() {
10936 let request = client.request(proto::StopLanguageServers {
10937 project_id,
10938 buffer_ids: buffers
10939 .into_iter()
10940 .map(|b| b.read(cx).remote_id().to_proto())
10941 .collect(),
10942 also_servers: also_stop_servers
10943 .into_iter()
10944 .map(|selector| {
10945 let selector = match selector {
10946 LanguageServerSelector::Id(language_server_id) => {
10947 proto::language_server_selector::Selector::ServerId(
10948 language_server_id.to_proto(),
10949 )
10950 }
10951 LanguageServerSelector::Name(language_server_name) => {
10952 proto::language_server_selector::Selector::Name(
10953 language_server_name.to_string(),
10954 )
10955 }
10956 };
10957 proto::LanguageServerSelector {
10958 selector: Some(selector),
10959 }
10960 })
10961 .collect(),
10962 all: false,
10963 });
10964 cx.background_spawn(async move {
10965 let _ = request.await?;
10966 Ok(())
10967 })
10968 } else {
10969 let task =
10970 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10971 cx.background_spawn(async move {
10972 task.await;
10973 Ok(())
10974 })
10975 }
10976 }
10977
10978 fn stop_local_language_servers_for_buffers(
10979 &mut self,
10980 buffers: &[Entity<Buffer>],
10981 also_stop_servers: HashSet<LanguageServerSelector>,
10982 cx: &mut Context<Self>,
10983 ) -> Task<()> {
10984 let Some(local) = self.as_local_mut() else {
10985 return Task::ready(());
10986 };
10987 let mut language_server_names_to_stop = BTreeSet::default();
10988 let mut language_servers_to_stop = also_stop_servers
10989 .into_iter()
10990 .flat_map(|selector| match selector {
10991 LanguageServerSelector::Id(id) => Some(id),
10992 LanguageServerSelector::Name(name) => {
10993 language_server_names_to_stop.insert(name);
10994 None
10995 }
10996 })
10997 .collect::<BTreeSet<_>>();
10998
10999 let mut covered_worktrees = HashSet::default();
11000 for buffer in buffers {
11001 buffer.update(cx, |buffer, cx| {
11002 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11003 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11004 && covered_worktrees.insert(worktree_id)
11005 {
11006 language_server_names_to_stop.retain(|name| {
11007 let old_ids_count = language_servers_to_stop.len();
11008 let all_language_servers_with_this_name = local
11009 .language_server_ids
11010 .iter()
11011 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11012 language_servers_to_stop.extend(all_language_servers_with_this_name);
11013 old_ids_count == language_servers_to_stop.len()
11014 });
11015 }
11016 });
11017 }
11018 for name in language_server_names_to_stop {
11019 language_servers_to_stop.extend(
11020 local
11021 .language_server_ids
11022 .iter()
11023 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11024 );
11025 }
11026
11027 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11028 let tasks = language_servers_to_stop
11029 .into_iter()
11030 .map(|server| self.stop_local_language_server(server, cx))
11031 .collect::<Vec<_>>();
11032
11033 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11034 }
11035
11036 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11037 let (worktree, relative_path) =
11038 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11039
11040 let project_path = ProjectPath {
11041 worktree_id: worktree.read(cx).id(),
11042 path: relative_path,
11043 };
11044
11045 Some(
11046 self.buffer_store()
11047 .read(cx)
11048 .get_by_path(&project_path)?
11049 .read(cx),
11050 )
11051 }
11052
11053 #[cfg(any(test, feature = "test-support"))]
11054 pub fn update_diagnostics(
11055 &mut self,
11056 server_id: LanguageServerId,
11057 diagnostics: lsp::PublishDiagnosticsParams,
11058 result_id: Option<SharedString>,
11059 source_kind: DiagnosticSourceKind,
11060 disk_based_sources: &[String],
11061 cx: &mut Context<Self>,
11062 ) -> Result<()> {
11063 self.merge_lsp_diagnostics(
11064 source_kind,
11065 vec![DocumentDiagnosticsUpdate {
11066 diagnostics,
11067 result_id,
11068 server_id,
11069 disk_based_sources: Cow::Borrowed(disk_based_sources),
11070 registration_id: None,
11071 }],
11072 |_, _, _| false,
11073 cx,
11074 )
11075 }
11076
11077 pub fn merge_lsp_diagnostics(
11078 &mut self,
11079 source_kind: DiagnosticSourceKind,
11080 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11081 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11082 cx: &mut Context<Self>,
11083 ) -> Result<()> {
11084 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11085 let updates = lsp_diagnostics
11086 .into_iter()
11087 .filter_map(|update| {
11088 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11089 Some(DocumentDiagnosticsUpdate {
11090 diagnostics: self.lsp_to_document_diagnostics(
11091 abs_path,
11092 source_kind,
11093 update.server_id,
11094 update.diagnostics,
11095 &update.disk_based_sources,
11096 update.registration_id.clone(),
11097 ),
11098 result_id: update.result_id,
11099 server_id: update.server_id,
11100 disk_based_sources: update.disk_based_sources,
11101 registration_id: update.registration_id,
11102 })
11103 })
11104 .collect();
11105 self.merge_diagnostic_entries(updates, merge, cx)?;
11106 Ok(())
11107 }
11108
11109 fn lsp_to_document_diagnostics(
11110 &mut self,
11111 document_abs_path: PathBuf,
11112 source_kind: DiagnosticSourceKind,
11113 server_id: LanguageServerId,
11114 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11115 disk_based_sources: &[String],
11116 registration_id: Option<SharedString>,
11117 ) -> DocumentDiagnostics {
11118 let mut diagnostics = Vec::default();
11119 let mut primary_diagnostic_group_ids = HashMap::default();
11120 let mut sources_by_group_id = HashMap::default();
11121 let mut supporting_diagnostics = HashMap::default();
11122
11123 let adapter = self.language_server_adapter_for_id(server_id);
11124
11125 // Ensure that primary diagnostics are always the most severe
11126 lsp_diagnostics
11127 .diagnostics
11128 .sort_by_key(|item| item.severity);
11129
11130 for diagnostic in &lsp_diagnostics.diagnostics {
11131 let source = diagnostic.source.as_ref();
11132 let range = range_from_lsp(diagnostic.range);
11133 let is_supporting = diagnostic
11134 .related_information
11135 .as_ref()
11136 .is_some_and(|infos| {
11137 infos.iter().any(|info| {
11138 primary_diagnostic_group_ids.contains_key(&(
11139 source,
11140 diagnostic.code.clone(),
11141 range_from_lsp(info.location.range),
11142 ))
11143 })
11144 });
11145
11146 let is_unnecessary = diagnostic
11147 .tags
11148 .as_ref()
11149 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11150
11151 let underline = self
11152 .language_server_adapter_for_id(server_id)
11153 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11154
11155 if is_supporting {
11156 supporting_diagnostics.insert(
11157 (source, diagnostic.code.clone(), range),
11158 (diagnostic.severity, is_unnecessary),
11159 );
11160 } else {
11161 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11162 let is_disk_based =
11163 source.is_some_and(|source| disk_based_sources.contains(source));
11164
11165 sources_by_group_id.insert(group_id, source);
11166 primary_diagnostic_group_ids
11167 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11168
11169 diagnostics.push(DiagnosticEntry {
11170 range,
11171 diagnostic: Diagnostic {
11172 source: diagnostic.source.clone(),
11173 source_kind,
11174 code: diagnostic.code.clone(),
11175 code_description: diagnostic
11176 .code_description
11177 .as_ref()
11178 .and_then(|d| d.href.clone()),
11179 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11180 markdown: adapter.as_ref().and_then(|adapter| {
11181 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11182 }),
11183 message: diagnostic.message.trim().to_string(),
11184 group_id,
11185 is_primary: true,
11186 is_disk_based,
11187 is_unnecessary,
11188 underline,
11189 data: diagnostic.data.clone(),
11190 registration_id: registration_id.clone(),
11191 },
11192 });
11193 if let Some(infos) = &diagnostic.related_information {
11194 for info in infos {
11195 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11196 let range = range_from_lsp(info.location.range);
11197 diagnostics.push(DiagnosticEntry {
11198 range,
11199 diagnostic: Diagnostic {
11200 source: diagnostic.source.clone(),
11201 source_kind,
11202 code: diagnostic.code.clone(),
11203 code_description: diagnostic
11204 .code_description
11205 .as_ref()
11206 .and_then(|d| d.href.clone()),
11207 severity: DiagnosticSeverity::INFORMATION,
11208 markdown: adapter.as_ref().and_then(|adapter| {
11209 adapter.diagnostic_message_to_markdown(&info.message)
11210 }),
11211 message: info.message.trim().to_string(),
11212 group_id,
11213 is_primary: false,
11214 is_disk_based,
11215 is_unnecessary: false,
11216 underline,
11217 data: diagnostic.data.clone(),
11218 registration_id: registration_id.clone(),
11219 },
11220 });
11221 }
11222 }
11223 }
11224 }
11225 }
11226
11227 for entry in &mut diagnostics {
11228 let diagnostic = &mut entry.diagnostic;
11229 if !diagnostic.is_primary {
11230 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11231 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11232 source,
11233 diagnostic.code.clone(),
11234 entry.range.clone(),
11235 )) {
11236 if let Some(severity) = severity {
11237 diagnostic.severity = severity;
11238 }
11239 diagnostic.is_unnecessary = is_unnecessary;
11240 }
11241 }
11242 }
11243
11244 DocumentDiagnostics {
11245 diagnostics,
11246 document_abs_path,
11247 version: lsp_diagnostics.version,
11248 }
11249 }
11250
11251 fn insert_newly_running_language_server(
11252 &mut self,
11253 adapter: Arc<CachedLspAdapter>,
11254 language_server: Arc<LanguageServer>,
11255 server_id: LanguageServerId,
11256 key: LanguageServerSeed,
11257 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11258 cx: &mut Context<Self>,
11259 ) {
11260 let Some(local) = self.as_local_mut() else {
11261 return;
11262 };
11263 // If the language server for this key doesn't match the server id, don't store the
11264 // server. Which will cause it to be dropped, killing the process
11265 if local
11266 .language_server_ids
11267 .get(&key)
11268 .map(|state| state.id != server_id)
11269 .unwrap_or(false)
11270 {
11271 return;
11272 }
11273
11274 // Update language_servers collection with Running variant of LanguageServerState
11275 // indicating that the server is up and running and ready
11276 let workspace_folders = workspace_folders.lock().clone();
11277 language_server.set_workspace_folders(workspace_folders);
11278
11279 let workspace_diagnostics_refresh_tasks = language_server
11280 .capabilities()
11281 .diagnostic_provider
11282 .and_then(|provider| {
11283 local
11284 .language_server_dynamic_registrations
11285 .entry(server_id)
11286 .or_default()
11287 .diagnostics
11288 .entry(None)
11289 .or_insert(provider.clone());
11290 let workspace_refresher =
11291 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11292
11293 Some((None, workspace_refresher))
11294 })
11295 .into_iter()
11296 .collect();
11297 local.language_servers.insert(
11298 server_id,
11299 LanguageServerState::Running {
11300 workspace_diagnostics_refresh_tasks,
11301 adapter: adapter.clone(),
11302 server: language_server.clone(),
11303 simulate_disk_based_diagnostics_completion: None,
11304 },
11305 );
11306 local
11307 .languages
11308 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11309 if let Some(file_ops_caps) = language_server
11310 .capabilities()
11311 .workspace
11312 .as_ref()
11313 .and_then(|ws| ws.file_operations.as_ref())
11314 {
11315 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11316 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11317 if did_rename_caps.or(will_rename_caps).is_some() {
11318 let watcher = RenamePathsWatchedForServer::default()
11319 .with_did_rename_patterns(did_rename_caps)
11320 .with_will_rename_patterns(will_rename_caps);
11321 local
11322 .language_server_paths_watched_for_rename
11323 .insert(server_id, watcher);
11324 }
11325 }
11326
11327 self.language_server_statuses.insert(
11328 server_id,
11329 LanguageServerStatus {
11330 name: language_server.name(),
11331 pending_work: Default::default(),
11332 has_pending_diagnostic_updates: false,
11333 progress_tokens: Default::default(),
11334 worktree: Some(key.worktree_id),
11335 binary: Some(language_server.binary().clone()),
11336 configuration: Some(language_server.configuration().clone()),
11337 workspace_folders: language_server.workspace_folders(),
11338 },
11339 );
11340
11341 cx.emit(LspStoreEvent::LanguageServerAdded(
11342 server_id,
11343 language_server.name(),
11344 Some(key.worktree_id),
11345 ));
11346
11347 let server_capabilities = language_server.capabilities();
11348 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11349 downstream_client
11350 .send(proto::StartLanguageServer {
11351 project_id: *project_id,
11352 server: Some(proto::LanguageServer {
11353 id: server_id.to_proto(),
11354 name: language_server.name().to_string(),
11355 worktree_id: Some(key.worktree_id.to_proto()),
11356 }),
11357 capabilities: serde_json::to_string(&server_capabilities)
11358 .expect("serializing server LSP capabilities"),
11359 })
11360 .log_err();
11361 }
11362 self.lsp_server_capabilities
11363 .insert(server_id, server_capabilities);
11364
11365 // Tell the language server about every open buffer in the worktree that matches the language.
11366 // Also check for buffers in worktrees that reused this server
11367 let mut worktrees_using_server = vec![key.worktree_id];
11368 if let Some(local) = self.as_local() {
11369 // Find all worktrees that have this server in their language server tree
11370 for (worktree_id, servers) in &local.lsp_tree.instances {
11371 if *worktree_id != key.worktree_id {
11372 for server_map in servers.roots.values() {
11373 if server_map
11374 .values()
11375 .any(|(node, _)| node.id() == Some(server_id))
11376 {
11377 worktrees_using_server.push(*worktree_id);
11378 }
11379 }
11380 }
11381 }
11382 }
11383
11384 let mut buffer_paths_registered = Vec::new();
11385 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11386 let mut lsp_adapters = HashMap::default();
11387 for buffer_handle in buffer_store.buffers() {
11388 let buffer = buffer_handle.read(cx);
11389 let file = match File::from_dyn(buffer.file()) {
11390 Some(file) => file,
11391 None => continue,
11392 };
11393 let language = match buffer.language() {
11394 Some(language) => language,
11395 None => continue,
11396 };
11397
11398 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11399 || !lsp_adapters
11400 .entry(language.name())
11401 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11402 .iter()
11403 .any(|a| a.name == key.name)
11404 {
11405 continue;
11406 }
11407 // didOpen
11408 let file = match file.as_local() {
11409 Some(file) => file,
11410 None => continue,
11411 };
11412
11413 let local = self.as_local_mut().unwrap();
11414
11415 let buffer_id = buffer.remote_id();
11416 if local.registered_buffers.contains_key(&buffer_id) {
11417 let versions = local
11418 .buffer_snapshots
11419 .entry(buffer_id)
11420 .or_default()
11421 .entry(server_id)
11422 .and_modify(|_| {
11423 assert!(
11424 false,
11425 "There should not be an existing snapshot for a newly inserted buffer"
11426 )
11427 })
11428 .or_insert_with(|| {
11429 vec![LspBufferSnapshot {
11430 version: 0,
11431 snapshot: buffer.text_snapshot(),
11432 }]
11433 });
11434
11435 let snapshot = versions.last().unwrap();
11436 let version = snapshot.version;
11437 let initial_snapshot = &snapshot.snapshot;
11438 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11439 language_server.register_buffer(
11440 uri,
11441 adapter.language_id(&language.name()),
11442 version,
11443 initial_snapshot.text(),
11444 );
11445 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11446 local
11447 .buffers_opened_in_servers
11448 .entry(buffer_id)
11449 .or_default()
11450 .insert(server_id);
11451 }
11452 buffer_handle.update(cx, |buffer, cx| {
11453 buffer.set_completion_triggers(
11454 server_id,
11455 language_server
11456 .capabilities()
11457 .completion_provider
11458 .as_ref()
11459 .and_then(|provider| {
11460 provider
11461 .trigger_characters
11462 .as_ref()
11463 .map(|characters| characters.iter().cloned().collect())
11464 })
11465 .unwrap_or_default(),
11466 cx,
11467 )
11468 });
11469 }
11470 });
11471
11472 for (buffer_id, abs_path) in buffer_paths_registered {
11473 cx.emit(LspStoreEvent::LanguageServerUpdate {
11474 language_server_id: server_id,
11475 name: Some(adapter.name()),
11476 message: proto::update_language_server::Variant::RegisteredForBuffer(
11477 proto::RegisteredForBuffer {
11478 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11479 buffer_id: buffer_id.to_proto(),
11480 },
11481 ),
11482 });
11483 }
11484
11485 cx.notify();
11486 }
11487
11488 pub fn language_servers_running_disk_based_diagnostics(
11489 &self,
11490 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11491 self.language_server_statuses
11492 .iter()
11493 .filter_map(|(id, status)| {
11494 if status.has_pending_diagnostic_updates {
11495 Some(*id)
11496 } else {
11497 None
11498 }
11499 })
11500 }
11501
11502 pub(crate) fn cancel_language_server_work_for_buffers(
11503 &mut self,
11504 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11505 cx: &mut Context<Self>,
11506 ) {
11507 if let Some((client, project_id)) = self.upstream_client() {
11508 let request = client.request(proto::CancelLanguageServerWork {
11509 project_id,
11510 work: Some(proto::cancel_language_server_work::Work::Buffers(
11511 proto::cancel_language_server_work::Buffers {
11512 buffer_ids: buffers
11513 .into_iter()
11514 .map(|b| b.read(cx).remote_id().to_proto())
11515 .collect(),
11516 },
11517 )),
11518 });
11519 cx.background_spawn(request).detach_and_log_err(cx);
11520 } else if let Some(local) = self.as_local() {
11521 let servers = buffers
11522 .into_iter()
11523 .flat_map(|buffer| {
11524 buffer.update(cx, |buffer, cx| {
11525 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11526 })
11527 })
11528 .collect::<HashSet<_>>();
11529 for server_id in servers {
11530 self.cancel_language_server_work(server_id, None, cx);
11531 }
11532 }
11533 }
11534
11535 pub(crate) fn cancel_language_server_work(
11536 &mut self,
11537 server_id: LanguageServerId,
11538 token_to_cancel: Option<ProgressToken>,
11539 cx: &mut Context<Self>,
11540 ) {
11541 if let Some(local) = self.as_local() {
11542 let status = self.language_server_statuses.get(&server_id);
11543 let server = local.language_servers.get(&server_id);
11544 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11545 {
11546 for (token, progress) in &status.pending_work {
11547 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11548 && token != token_to_cancel
11549 {
11550 continue;
11551 }
11552 if progress.is_cancellable {
11553 server
11554 .notify::<lsp::notification::WorkDoneProgressCancel>(
11555 WorkDoneProgressCancelParams {
11556 token: token.to_lsp(),
11557 },
11558 )
11559 .ok();
11560 }
11561 }
11562 }
11563 } else if let Some((client, project_id)) = self.upstream_client() {
11564 let request = client.request(proto::CancelLanguageServerWork {
11565 project_id,
11566 work: Some(
11567 proto::cancel_language_server_work::Work::LanguageServerWork(
11568 proto::cancel_language_server_work::LanguageServerWork {
11569 language_server_id: server_id.to_proto(),
11570 token: token_to_cancel.map(|token| token.to_proto()),
11571 },
11572 ),
11573 ),
11574 });
11575 cx.background_spawn(request).detach_and_log_err(cx);
11576 }
11577 }
11578
11579 fn register_supplementary_language_server(
11580 &mut self,
11581 id: LanguageServerId,
11582 name: LanguageServerName,
11583 server: Arc<LanguageServer>,
11584 cx: &mut Context<Self>,
11585 ) {
11586 if let Some(local) = self.as_local_mut() {
11587 local
11588 .supplementary_language_servers
11589 .insert(id, (name.clone(), server));
11590 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11591 }
11592 }
11593
11594 fn unregister_supplementary_language_server(
11595 &mut self,
11596 id: LanguageServerId,
11597 cx: &mut Context<Self>,
11598 ) {
11599 if let Some(local) = self.as_local_mut() {
11600 local.supplementary_language_servers.remove(&id);
11601 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11602 }
11603 }
11604
11605 pub(crate) fn supplementary_language_servers(
11606 &self,
11607 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11608 self.as_local().into_iter().flat_map(|local| {
11609 local
11610 .supplementary_language_servers
11611 .iter()
11612 .map(|(id, (name, _))| (*id, name.clone()))
11613 })
11614 }
11615
11616 pub fn language_server_adapter_for_id(
11617 &self,
11618 id: LanguageServerId,
11619 ) -> Option<Arc<CachedLspAdapter>> {
11620 self.as_local()
11621 .and_then(|local| local.language_servers.get(&id))
11622 .and_then(|language_server_state| match language_server_state {
11623 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11624 _ => None,
11625 })
11626 }
11627
11628 pub(super) fn update_local_worktree_language_servers(
11629 &mut self,
11630 worktree_handle: &Entity<Worktree>,
11631 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11632 cx: &mut Context<Self>,
11633 ) {
11634 if changes.is_empty() {
11635 return;
11636 }
11637
11638 let Some(local) = self.as_local() else { return };
11639
11640 local.prettier_store.update(cx, |prettier_store, cx| {
11641 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11642 });
11643
11644 let worktree_id = worktree_handle.read(cx).id();
11645 let mut language_server_ids = local
11646 .language_server_ids
11647 .iter()
11648 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11649 .collect::<Vec<_>>();
11650 language_server_ids.sort();
11651 language_server_ids.dedup();
11652
11653 // let abs_path = worktree_handle.read(cx).abs_path();
11654 for server_id in &language_server_ids {
11655 if let Some(LanguageServerState::Running { server, .. }) =
11656 local.language_servers.get(server_id)
11657 && let Some(watched_paths) = local
11658 .language_server_watched_paths
11659 .get(server_id)
11660 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11661 {
11662 let params = lsp::DidChangeWatchedFilesParams {
11663 changes: changes
11664 .iter()
11665 .filter_map(|(path, _, change)| {
11666 if !watched_paths.is_match(path.as_std_path()) {
11667 return None;
11668 }
11669 let typ = match change {
11670 PathChange::Loaded => return None,
11671 PathChange::Added => lsp::FileChangeType::CREATED,
11672 PathChange::Removed => lsp::FileChangeType::DELETED,
11673 PathChange::Updated => lsp::FileChangeType::CHANGED,
11674 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11675 };
11676 let uri = lsp::Uri::from_file_path(
11677 worktree_handle.read(cx).absolutize(&path),
11678 )
11679 .ok()?;
11680 Some(lsp::FileEvent { uri, typ })
11681 })
11682 .collect(),
11683 };
11684 if !params.changes.is_empty() {
11685 server
11686 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11687 .ok();
11688 }
11689 }
11690 }
11691 for (path, _, _) in changes {
11692 if let Some(file_name) = path.file_name()
11693 && local.watched_manifest_filenames.contains(file_name)
11694 {
11695 self.request_workspace_config_refresh();
11696 break;
11697 }
11698 }
11699 }
11700
11701 pub fn wait_for_remote_buffer(
11702 &mut self,
11703 id: BufferId,
11704 cx: &mut Context<Self>,
11705 ) -> Task<Result<Entity<Buffer>>> {
11706 self.buffer_store.update(cx, |buffer_store, cx| {
11707 buffer_store.wait_for_remote_buffer(id, cx)
11708 })
11709 }
11710
11711 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11712 let mut result = proto::Symbol {
11713 language_server_name: symbol.language_server_name.0.to_string(),
11714 source_worktree_id: symbol.source_worktree_id.to_proto(),
11715 language_server_id: symbol.source_language_server_id.to_proto(),
11716 name: symbol.name.clone(),
11717 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11718 start: Some(proto::PointUtf16 {
11719 row: symbol.range.start.0.row,
11720 column: symbol.range.start.0.column,
11721 }),
11722 end: Some(proto::PointUtf16 {
11723 row: symbol.range.end.0.row,
11724 column: symbol.range.end.0.column,
11725 }),
11726 worktree_id: Default::default(),
11727 path: Default::default(),
11728 signature: Default::default(),
11729 };
11730 match &symbol.path {
11731 SymbolLocation::InProject(path) => {
11732 result.worktree_id = path.worktree_id.to_proto();
11733 result.path = path.path.to_proto();
11734 }
11735 SymbolLocation::OutsideProject {
11736 abs_path,
11737 signature,
11738 } => {
11739 result.path = abs_path.to_string_lossy().into_owned();
11740 result.signature = signature.to_vec();
11741 }
11742 }
11743 result
11744 }
11745
11746 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11747 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11748 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11749 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11750
11751 let path = if serialized_symbol.signature.is_empty() {
11752 SymbolLocation::InProject(ProjectPath {
11753 worktree_id,
11754 path: RelPath::from_proto(&serialized_symbol.path)
11755 .context("invalid symbol path")?,
11756 })
11757 } else {
11758 SymbolLocation::OutsideProject {
11759 abs_path: Path::new(&serialized_symbol.path).into(),
11760 signature: serialized_symbol
11761 .signature
11762 .try_into()
11763 .map_err(|_| anyhow!("invalid signature"))?,
11764 }
11765 };
11766
11767 let start = serialized_symbol.start.context("invalid start")?;
11768 let end = serialized_symbol.end.context("invalid end")?;
11769 Ok(CoreSymbol {
11770 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11771 source_worktree_id,
11772 source_language_server_id: LanguageServerId::from_proto(
11773 serialized_symbol.language_server_id,
11774 ),
11775 path,
11776 name: serialized_symbol.name,
11777 range: Unclipped(PointUtf16::new(start.row, start.column))
11778 ..Unclipped(PointUtf16::new(end.row, end.column)),
11779 kind,
11780 })
11781 }
11782
11783 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11784 let mut serialized_completion = proto::Completion {
11785 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11786 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11787 new_text: completion.new_text.clone(),
11788 ..proto::Completion::default()
11789 };
11790 match &completion.source {
11791 CompletionSource::Lsp {
11792 insert_range,
11793 server_id,
11794 lsp_completion,
11795 lsp_defaults,
11796 resolved,
11797 } => {
11798 let (old_insert_start, old_insert_end) = insert_range
11799 .as_ref()
11800 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11801 .unzip();
11802
11803 serialized_completion.old_insert_start = old_insert_start;
11804 serialized_completion.old_insert_end = old_insert_end;
11805 serialized_completion.source = proto::completion::Source::Lsp as i32;
11806 serialized_completion.server_id = server_id.0 as u64;
11807 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11808 serialized_completion.lsp_defaults = lsp_defaults
11809 .as_deref()
11810 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11811 serialized_completion.resolved = *resolved;
11812 }
11813 CompletionSource::BufferWord {
11814 word_range,
11815 resolved,
11816 } => {
11817 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11818 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11819 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11820 serialized_completion.resolved = *resolved;
11821 }
11822 CompletionSource::Custom => {
11823 serialized_completion.source = proto::completion::Source::Custom as i32;
11824 serialized_completion.resolved = true;
11825 }
11826 CompletionSource::Dap { sort_text } => {
11827 serialized_completion.source = proto::completion::Source::Dap as i32;
11828 serialized_completion.sort_text = Some(sort_text.clone());
11829 }
11830 }
11831
11832 serialized_completion
11833 }
11834
11835 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11836 let old_replace_start = completion
11837 .old_replace_start
11838 .and_then(deserialize_anchor)
11839 .context("invalid old start")?;
11840 let old_replace_end = completion
11841 .old_replace_end
11842 .and_then(deserialize_anchor)
11843 .context("invalid old end")?;
11844 let insert_range = {
11845 match completion.old_insert_start.zip(completion.old_insert_end) {
11846 Some((start, end)) => {
11847 let start = deserialize_anchor(start).context("invalid insert old start")?;
11848 let end = deserialize_anchor(end).context("invalid insert old end")?;
11849 Some(start..end)
11850 }
11851 None => None,
11852 }
11853 };
11854 Ok(CoreCompletion {
11855 replace_range: old_replace_start..old_replace_end,
11856 new_text: completion.new_text,
11857 source: match proto::completion::Source::from_i32(completion.source) {
11858 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11859 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11860 insert_range,
11861 server_id: LanguageServerId::from_proto(completion.server_id),
11862 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11863 lsp_defaults: completion
11864 .lsp_defaults
11865 .as_deref()
11866 .map(serde_json::from_slice)
11867 .transpose()?,
11868 resolved: completion.resolved,
11869 },
11870 Some(proto::completion::Source::BufferWord) => {
11871 let word_range = completion
11872 .buffer_word_start
11873 .and_then(deserialize_anchor)
11874 .context("invalid buffer word start")?
11875 ..completion
11876 .buffer_word_end
11877 .and_then(deserialize_anchor)
11878 .context("invalid buffer word end")?;
11879 CompletionSource::BufferWord {
11880 word_range,
11881 resolved: completion.resolved,
11882 }
11883 }
11884 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11885 sort_text: completion
11886 .sort_text
11887 .context("expected sort text to exist")?,
11888 },
11889 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11890 },
11891 })
11892 }
11893
11894 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11895 let (kind, lsp_action) = match &action.lsp_action {
11896 LspAction::Action(code_action) => (
11897 proto::code_action::Kind::Action as i32,
11898 serde_json::to_vec(code_action).unwrap(),
11899 ),
11900 LspAction::Command(command) => (
11901 proto::code_action::Kind::Command as i32,
11902 serde_json::to_vec(command).unwrap(),
11903 ),
11904 LspAction::CodeLens(code_lens) => (
11905 proto::code_action::Kind::CodeLens as i32,
11906 serde_json::to_vec(code_lens).unwrap(),
11907 ),
11908 };
11909
11910 proto::CodeAction {
11911 server_id: action.server_id.0 as u64,
11912 start: Some(serialize_anchor(&action.range.start)),
11913 end: Some(serialize_anchor(&action.range.end)),
11914 lsp_action,
11915 kind,
11916 resolved: action.resolved,
11917 }
11918 }
11919
11920 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11921 let start = action
11922 .start
11923 .and_then(deserialize_anchor)
11924 .context("invalid start")?;
11925 let end = action
11926 .end
11927 .and_then(deserialize_anchor)
11928 .context("invalid end")?;
11929 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11930 Some(proto::code_action::Kind::Action) => {
11931 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11932 }
11933 Some(proto::code_action::Kind::Command) => {
11934 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11935 }
11936 Some(proto::code_action::Kind::CodeLens) => {
11937 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11938 }
11939 None => anyhow::bail!("Unknown action kind {}", action.kind),
11940 };
11941 Ok(CodeAction {
11942 server_id: LanguageServerId(action.server_id as usize),
11943 range: start..end,
11944 resolved: action.resolved,
11945 lsp_action,
11946 })
11947 }
11948
11949 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11950 match &formatting_result {
11951 Ok(_) => self.last_formatting_failure = None,
11952 Err(error) => {
11953 let error_string = format!("{error:#}");
11954 log::error!("Formatting failed: {error_string}");
11955 self.last_formatting_failure
11956 .replace(error_string.lines().join(" "));
11957 }
11958 }
11959 }
11960
11961 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11962 self.lsp_server_capabilities.remove(&for_server);
11963 for lsp_data in self.lsp_data.values_mut() {
11964 lsp_data.remove_server_data(for_server);
11965 }
11966 if let Some(local) = self.as_local_mut() {
11967 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11968 local
11969 .workspace_pull_diagnostics_result_ids
11970 .remove(&for_server);
11971 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11972 buffer_servers.remove(&for_server);
11973 }
11974 }
11975 }
11976
11977 pub fn result_id_for_buffer_pull(
11978 &self,
11979 server_id: LanguageServerId,
11980 buffer_id: BufferId,
11981 registration_id: &Option<SharedString>,
11982 cx: &App,
11983 ) -> Option<SharedString> {
11984 let abs_path = self
11985 .buffer_store
11986 .read(cx)
11987 .get(buffer_id)
11988 .and_then(|b| File::from_dyn(b.read(cx).file()))
11989 .map(|f| f.abs_path(cx))?;
11990 self.as_local()?
11991 .buffer_pull_diagnostics_result_ids
11992 .get(&server_id)?
11993 .get(registration_id)?
11994 .get(&abs_path)?
11995 .clone()
11996 }
11997
11998 /// Gets all result_ids for a workspace diagnostics pull request.
11999 /// 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.
12000 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12001 pub fn result_ids_for_workspace_refresh(
12002 &self,
12003 server_id: LanguageServerId,
12004 registration_id: &Option<SharedString>,
12005 ) -> HashMap<PathBuf, SharedString> {
12006 let Some(local) = self.as_local() else {
12007 return HashMap::default();
12008 };
12009 local
12010 .workspace_pull_diagnostics_result_ids
12011 .get(&server_id)
12012 .into_iter()
12013 .filter_map(|diagnostics| diagnostics.get(registration_id))
12014 .flatten()
12015 .filter_map(|(abs_path, result_id)| {
12016 let result_id = local
12017 .buffer_pull_diagnostics_result_ids
12018 .get(&server_id)
12019 .and_then(|buffer_ids_result_ids| {
12020 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12021 })
12022 .cloned()
12023 .flatten()
12024 .or_else(|| result_id.clone())?;
12025 Some((abs_path.clone(), result_id))
12026 })
12027 .collect()
12028 }
12029
12030 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12031 if let Some(LanguageServerState::Running {
12032 workspace_diagnostics_refresh_tasks,
12033 ..
12034 }) = self
12035 .as_local_mut()
12036 .and_then(|local| local.language_servers.get_mut(&server_id))
12037 {
12038 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12039 diagnostics.refresh_tx.try_send(()).ok();
12040 }
12041 }
12042 }
12043
12044 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12045 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12046 return;
12047 };
12048 let Some(local) = self.as_local_mut() else {
12049 return;
12050 };
12051
12052 for server_id in buffer.update(cx, |buffer, cx| {
12053 local.language_server_ids_for_buffer(buffer, cx)
12054 }) {
12055 if let Some(LanguageServerState::Running {
12056 workspace_diagnostics_refresh_tasks,
12057 ..
12058 }) = local.language_servers.get_mut(&server_id)
12059 {
12060 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12061 diagnostics.refresh_tx.try_send(()).ok();
12062 }
12063 }
12064 }
12065 }
12066
12067 fn apply_workspace_diagnostic_report(
12068 &mut self,
12069 server_id: LanguageServerId,
12070 report: lsp::WorkspaceDiagnosticReportResult,
12071 registration_id: Option<SharedString>,
12072 cx: &mut Context<Self>,
12073 ) {
12074 let workspace_diagnostics =
12075 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12076 report,
12077 server_id,
12078 registration_id,
12079 );
12080 let mut unchanged_buffers = HashMap::default();
12081 let workspace_diagnostics_updates = workspace_diagnostics
12082 .into_iter()
12083 .filter_map(
12084 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12085 LspPullDiagnostics::Response {
12086 server_id,
12087 uri,
12088 diagnostics,
12089 registration_id,
12090 } => Some((
12091 server_id,
12092 uri,
12093 diagnostics,
12094 workspace_diagnostics.version,
12095 registration_id,
12096 )),
12097 LspPullDiagnostics::Default => None,
12098 },
12099 )
12100 .fold(
12101 HashMap::default(),
12102 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12103 let (result_id, diagnostics) = match diagnostics {
12104 PulledDiagnostics::Unchanged { result_id } => {
12105 unchanged_buffers
12106 .entry(new_registration_id.clone())
12107 .or_insert_with(HashSet::default)
12108 .insert(uri.clone());
12109 (Some(result_id), Vec::new())
12110 }
12111 PulledDiagnostics::Changed {
12112 result_id,
12113 diagnostics,
12114 } => (result_id, diagnostics),
12115 };
12116 let disk_based_sources = Cow::Owned(
12117 self.language_server_adapter_for_id(server_id)
12118 .as_ref()
12119 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12120 .unwrap_or(&[])
12121 .to_vec(),
12122 );
12123
12124 let Some(abs_path) = uri.to_file_path().ok() else {
12125 return acc;
12126 };
12127 let Some((worktree, relative_path)) =
12128 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12129 else {
12130 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12131 return acc;
12132 };
12133 let worktree_id = worktree.read(cx).id();
12134 let project_path = ProjectPath {
12135 worktree_id,
12136 path: relative_path,
12137 };
12138 if let Some(local_lsp_store) = self.as_local_mut() {
12139 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12140 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12141 }
12142 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12143 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12144 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12145 acc.entry(server_id)
12146 .or_insert_with(HashMap::default)
12147 .entry(new_registration_id.clone())
12148 .or_insert_with(Vec::new)
12149 .push(DocumentDiagnosticsUpdate {
12150 server_id,
12151 diagnostics: lsp::PublishDiagnosticsParams {
12152 uri,
12153 diagnostics,
12154 version,
12155 },
12156 result_id,
12157 disk_based_sources,
12158 registration_id: new_registration_id,
12159 });
12160 }
12161 acc
12162 },
12163 );
12164
12165 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12166 for (registration_id, diagnostic_updates) in diagnostic_updates {
12167 self.merge_lsp_diagnostics(
12168 DiagnosticSourceKind::Pulled,
12169 diagnostic_updates,
12170 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12171 DiagnosticSourceKind::Pulled => {
12172 old_diagnostic.registration_id != registration_id
12173 || unchanged_buffers
12174 .get(&old_diagnostic.registration_id)
12175 .is_some_and(|unchanged_buffers| {
12176 unchanged_buffers.contains(&document_uri)
12177 })
12178 }
12179 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12180 },
12181 cx,
12182 )
12183 .log_err();
12184 }
12185 }
12186 }
12187
12188 fn register_server_capabilities(
12189 &mut self,
12190 server_id: LanguageServerId,
12191 params: lsp::RegistrationParams,
12192 cx: &mut Context<Self>,
12193 ) -> anyhow::Result<()> {
12194 let server = self
12195 .language_server_for_id(server_id)
12196 .with_context(|| format!("no server {server_id} found"))?;
12197 for reg in params.registrations {
12198 match reg.method.as_str() {
12199 "workspace/didChangeWatchedFiles" => {
12200 if let Some(options) = reg.register_options {
12201 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12202 let caps = serde_json::from_value(options)?;
12203 local_lsp_store
12204 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12205 true
12206 } else {
12207 false
12208 };
12209 if notify {
12210 notify_server_capabilities_updated(&server, cx);
12211 }
12212 }
12213 }
12214 "workspace/didChangeConfiguration" => {
12215 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12216 }
12217 "workspace/didChangeWorkspaceFolders" => {
12218 // In this case register options is an empty object, we can ignore it
12219 let caps = lsp::WorkspaceFoldersServerCapabilities {
12220 supported: Some(true),
12221 change_notifications: Some(OneOf::Right(reg.id)),
12222 };
12223 server.update_capabilities(|capabilities| {
12224 capabilities
12225 .workspace
12226 .get_or_insert_default()
12227 .workspace_folders = Some(caps);
12228 });
12229 notify_server_capabilities_updated(&server, cx);
12230 }
12231 "workspace/symbol" => {
12232 let options = parse_register_capabilities(reg)?;
12233 server.update_capabilities(|capabilities| {
12234 capabilities.workspace_symbol_provider = Some(options);
12235 });
12236 notify_server_capabilities_updated(&server, cx);
12237 }
12238 "workspace/fileOperations" => {
12239 if let Some(options) = reg.register_options {
12240 let caps = serde_json::from_value(options)?;
12241 server.update_capabilities(|capabilities| {
12242 capabilities
12243 .workspace
12244 .get_or_insert_default()
12245 .file_operations = Some(caps);
12246 });
12247 notify_server_capabilities_updated(&server, cx);
12248 }
12249 }
12250 "workspace/executeCommand" => {
12251 if let Some(options) = reg.register_options {
12252 let options = serde_json::from_value(options)?;
12253 server.update_capabilities(|capabilities| {
12254 capabilities.execute_command_provider = Some(options);
12255 });
12256 notify_server_capabilities_updated(&server, cx);
12257 }
12258 }
12259 "textDocument/rangeFormatting" => {
12260 let options = parse_register_capabilities(reg)?;
12261 server.update_capabilities(|capabilities| {
12262 capabilities.document_range_formatting_provider = Some(options);
12263 });
12264 notify_server_capabilities_updated(&server, cx);
12265 }
12266 "textDocument/onTypeFormatting" => {
12267 if let Some(options) = reg
12268 .register_options
12269 .map(serde_json::from_value)
12270 .transpose()?
12271 {
12272 server.update_capabilities(|capabilities| {
12273 capabilities.document_on_type_formatting_provider = Some(options);
12274 });
12275 notify_server_capabilities_updated(&server, cx);
12276 }
12277 }
12278 "textDocument/formatting" => {
12279 let options = parse_register_capabilities(reg)?;
12280 server.update_capabilities(|capabilities| {
12281 capabilities.document_formatting_provider = Some(options);
12282 });
12283 notify_server_capabilities_updated(&server, cx);
12284 }
12285 "textDocument/rename" => {
12286 let options = parse_register_capabilities(reg)?;
12287 server.update_capabilities(|capabilities| {
12288 capabilities.rename_provider = Some(options);
12289 });
12290 notify_server_capabilities_updated(&server, cx);
12291 }
12292 "textDocument/inlayHint" => {
12293 let options = parse_register_capabilities(reg)?;
12294 server.update_capabilities(|capabilities| {
12295 capabilities.inlay_hint_provider = Some(options);
12296 });
12297 notify_server_capabilities_updated(&server, cx);
12298 }
12299 "textDocument/documentSymbol" => {
12300 let options = parse_register_capabilities(reg)?;
12301 server.update_capabilities(|capabilities| {
12302 capabilities.document_symbol_provider = Some(options);
12303 });
12304 notify_server_capabilities_updated(&server, cx);
12305 }
12306 "textDocument/codeAction" => {
12307 let options = parse_register_capabilities(reg)?;
12308 let provider = match options {
12309 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12310 OneOf::Right(caps) => caps,
12311 };
12312 server.update_capabilities(|capabilities| {
12313 capabilities.code_action_provider = Some(provider);
12314 });
12315 notify_server_capabilities_updated(&server, cx);
12316 }
12317 "textDocument/definition" => {
12318 let options = parse_register_capabilities(reg)?;
12319 server.update_capabilities(|capabilities| {
12320 capabilities.definition_provider = Some(options);
12321 });
12322 notify_server_capabilities_updated(&server, cx);
12323 }
12324 "textDocument/completion" => {
12325 if let Some(caps) = reg
12326 .register_options
12327 .map(serde_json::from_value::<CompletionOptions>)
12328 .transpose()?
12329 {
12330 server.update_capabilities(|capabilities| {
12331 capabilities.completion_provider = Some(caps.clone());
12332 });
12333
12334 if let Some(local) = self.as_local() {
12335 let mut buffers_with_language_server = Vec::new();
12336 for handle in self.buffer_store.read(cx).buffers() {
12337 let buffer_id = handle.read(cx).remote_id();
12338 if local
12339 .buffers_opened_in_servers
12340 .get(&buffer_id)
12341 .filter(|s| s.contains(&server_id))
12342 .is_some()
12343 {
12344 buffers_with_language_server.push(handle);
12345 }
12346 }
12347 let triggers = caps
12348 .trigger_characters
12349 .unwrap_or_default()
12350 .into_iter()
12351 .collect::<BTreeSet<_>>();
12352 for handle in buffers_with_language_server {
12353 let triggers = triggers.clone();
12354 let _ = handle.update(cx, move |buffer, cx| {
12355 buffer.set_completion_triggers(server_id, triggers, cx);
12356 });
12357 }
12358 }
12359 notify_server_capabilities_updated(&server, cx);
12360 }
12361 }
12362 "textDocument/hover" => {
12363 let options = parse_register_capabilities(reg)?;
12364 let provider = match options {
12365 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12366 OneOf::Right(caps) => caps,
12367 };
12368 server.update_capabilities(|capabilities| {
12369 capabilities.hover_provider = Some(provider);
12370 });
12371 notify_server_capabilities_updated(&server, cx);
12372 }
12373 "textDocument/signatureHelp" => {
12374 if let Some(caps) = reg
12375 .register_options
12376 .map(serde_json::from_value)
12377 .transpose()?
12378 {
12379 server.update_capabilities(|capabilities| {
12380 capabilities.signature_help_provider = Some(caps);
12381 });
12382 notify_server_capabilities_updated(&server, cx);
12383 }
12384 }
12385 "textDocument/didChange" => {
12386 if let Some(sync_kind) = reg
12387 .register_options
12388 .and_then(|opts| opts.get("syncKind").cloned())
12389 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12390 .transpose()?
12391 {
12392 server.update_capabilities(|capabilities| {
12393 let mut sync_options =
12394 Self::take_text_document_sync_options(capabilities);
12395 sync_options.change = Some(sync_kind);
12396 capabilities.text_document_sync =
12397 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12398 });
12399 notify_server_capabilities_updated(&server, cx);
12400 }
12401 }
12402 "textDocument/didSave" => {
12403 if let Some(include_text) = reg
12404 .register_options
12405 .map(|opts| {
12406 let transpose = opts
12407 .get("includeText")
12408 .cloned()
12409 .map(serde_json::from_value::<Option<bool>>)
12410 .transpose();
12411 match transpose {
12412 Ok(value) => Ok(value.flatten()),
12413 Err(e) => Err(e),
12414 }
12415 })
12416 .transpose()?
12417 {
12418 server.update_capabilities(|capabilities| {
12419 let mut sync_options =
12420 Self::take_text_document_sync_options(capabilities);
12421 sync_options.save =
12422 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12423 include_text,
12424 }));
12425 capabilities.text_document_sync =
12426 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12427 });
12428 notify_server_capabilities_updated(&server, cx);
12429 }
12430 }
12431 "textDocument/codeLens" => {
12432 if let Some(caps) = reg
12433 .register_options
12434 .map(serde_json::from_value)
12435 .transpose()?
12436 {
12437 server.update_capabilities(|capabilities| {
12438 capabilities.code_lens_provider = Some(caps);
12439 });
12440 notify_server_capabilities_updated(&server, cx);
12441 }
12442 }
12443 "textDocument/diagnostic" => {
12444 if let Some(caps) = reg
12445 .register_options
12446 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12447 .transpose()?
12448 {
12449 let local = self
12450 .as_local_mut()
12451 .context("Expected LSP Store to be local")?;
12452 let state = local
12453 .language_servers
12454 .get_mut(&server_id)
12455 .context("Could not obtain Language Servers state")?;
12456 local
12457 .language_server_dynamic_registrations
12458 .entry(server_id)
12459 .or_default()
12460 .diagnostics
12461 .insert(Some(reg.id.clone()), caps.clone());
12462
12463 let supports_workspace_diagnostics =
12464 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12465 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12466 diagnostic_options.workspace_diagnostics
12467 }
12468 DiagnosticServerCapabilities::RegistrationOptions(
12469 diagnostic_registration_options,
12470 ) => {
12471 diagnostic_registration_options
12472 .diagnostic_options
12473 .workspace_diagnostics
12474 }
12475 };
12476
12477 if supports_workspace_diagnostics(&caps) {
12478 if let LanguageServerState::Running {
12479 workspace_diagnostics_refresh_tasks,
12480 ..
12481 } = state
12482 && let Some(task) = lsp_workspace_diagnostics_refresh(
12483 Some(reg.id.clone()),
12484 caps.clone(),
12485 server.clone(),
12486 cx,
12487 )
12488 {
12489 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12490 }
12491 }
12492
12493 server.update_capabilities(|capabilities| {
12494 capabilities.diagnostic_provider = Some(caps);
12495 });
12496
12497 notify_server_capabilities_updated(&server, cx);
12498 }
12499 }
12500 "textDocument/documentColor" => {
12501 let options = parse_register_capabilities(reg)?;
12502 let provider = match options {
12503 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12504 OneOf::Right(caps) => caps,
12505 };
12506 server.update_capabilities(|capabilities| {
12507 capabilities.color_provider = Some(provider);
12508 });
12509 notify_server_capabilities_updated(&server, cx);
12510 }
12511 _ => log::warn!("unhandled capability registration: {reg:?}"),
12512 }
12513 }
12514
12515 Ok(())
12516 }
12517
12518 fn unregister_server_capabilities(
12519 &mut self,
12520 server_id: LanguageServerId,
12521 params: lsp::UnregistrationParams,
12522 cx: &mut Context<Self>,
12523 ) -> anyhow::Result<()> {
12524 let server = self
12525 .language_server_for_id(server_id)
12526 .with_context(|| format!("no server {server_id} found"))?;
12527 for unreg in params.unregisterations.iter() {
12528 match unreg.method.as_str() {
12529 "workspace/didChangeWatchedFiles" => {
12530 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12531 local_lsp_store
12532 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12533 true
12534 } else {
12535 false
12536 };
12537 if notify {
12538 notify_server_capabilities_updated(&server, cx);
12539 }
12540 }
12541 "workspace/didChangeConfiguration" => {
12542 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12543 }
12544 "workspace/didChangeWorkspaceFolders" => {
12545 server.update_capabilities(|capabilities| {
12546 capabilities
12547 .workspace
12548 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12549 workspace_folders: None,
12550 file_operations: None,
12551 })
12552 .workspace_folders = None;
12553 });
12554 notify_server_capabilities_updated(&server, cx);
12555 }
12556 "workspace/symbol" => {
12557 server.update_capabilities(|capabilities| {
12558 capabilities.workspace_symbol_provider = None
12559 });
12560 notify_server_capabilities_updated(&server, cx);
12561 }
12562 "workspace/fileOperations" => {
12563 server.update_capabilities(|capabilities| {
12564 capabilities
12565 .workspace
12566 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12567 workspace_folders: None,
12568 file_operations: None,
12569 })
12570 .file_operations = None;
12571 });
12572 notify_server_capabilities_updated(&server, cx);
12573 }
12574 "workspace/executeCommand" => {
12575 server.update_capabilities(|capabilities| {
12576 capabilities.execute_command_provider = None;
12577 });
12578 notify_server_capabilities_updated(&server, cx);
12579 }
12580 "textDocument/rangeFormatting" => {
12581 server.update_capabilities(|capabilities| {
12582 capabilities.document_range_formatting_provider = None
12583 });
12584 notify_server_capabilities_updated(&server, cx);
12585 }
12586 "textDocument/onTypeFormatting" => {
12587 server.update_capabilities(|capabilities| {
12588 capabilities.document_on_type_formatting_provider = None;
12589 });
12590 notify_server_capabilities_updated(&server, cx);
12591 }
12592 "textDocument/formatting" => {
12593 server.update_capabilities(|capabilities| {
12594 capabilities.document_formatting_provider = None;
12595 });
12596 notify_server_capabilities_updated(&server, cx);
12597 }
12598 "textDocument/rename" => {
12599 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12600 notify_server_capabilities_updated(&server, cx);
12601 }
12602 "textDocument/codeAction" => {
12603 server.update_capabilities(|capabilities| {
12604 capabilities.code_action_provider = None;
12605 });
12606 notify_server_capabilities_updated(&server, cx);
12607 }
12608 "textDocument/definition" => {
12609 server.update_capabilities(|capabilities| {
12610 capabilities.definition_provider = None;
12611 });
12612 notify_server_capabilities_updated(&server, cx);
12613 }
12614 "textDocument/completion" => {
12615 server.update_capabilities(|capabilities| {
12616 capabilities.completion_provider = None;
12617 });
12618 notify_server_capabilities_updated(&server, cx);
12619 }
12620 "textDocument/hover" => {
12621 server.update_capabilities(|capabilities| {
12622 capabilities.hover_provider = None;
12623 });
12624 notify_server_capabilities_updated(&server, cx);
12625 }
12626 "textDocument/signatureHelp" => {
12627 server.update_capabilities(|capabilities| {
12628 capabilities.signature_help_provider = None;
12629 });
12630 notify_server_capabilities_updated(&server, cx);
12631 }
12632 "textDocument/didChange" => {
12633 server.update_capabilities(|capabilities| {
12634 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12635 sync_options.change = None;
12636 capabilities.text_document_sync =
12637 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12638 });
12639 notify_server_capabilities_updated(&server, cx);
12640 }
12641 "textDocument/didSave" => {
12642 server.update_capabilities(|capabilities| {
12643 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12644 sync_options.save = None;
12645 capabilities.text_document_sync =
12646 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12647 });
12648 notify_server_capabilities_updated(&server, cx);
12649 }
12650 "textDocument/codeLens" => {
12651 server.update_capabilities(|capabilities| {
12652 capabilities.code_lens_provider = None;
12653 });
12654 notify_server_capabilities_updated(&server, cx);
12655 }
12656 "textDocument/diagnostic" => {
12657 let local = self
12658 .as_local_mut()
12659 .context("Expected LSP Store to be local")?;
12660
12661 let state = local
12662 .language_servers
12663 .get_mut(&server_id)
12664 .context("Could not obtain Language Servers state")?;
12665 let registrations = local
12666 .language_server_dynamic_registrations
12667 .get_mut(&server_id)
12668 .with_context(|| {
12669 format!("Expected dynamic registration to exist for server {server_id}")
12670 })?;
12671 registrations.diagnostics
12672 .remove(&Some(unreg.id.clone()))
12673 .with_context(|| format!(
12674 "Attempted to unregister non-existent diagnostic registration with ID {}",
12675 unreg.id)
12676 )?;
12677 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12678
12679 if let LanguageServerState::Running {
12680 workspace_diagnostics_refresh_tasks,
12681 ..
12682 } = state
12683 {
12684 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12685 }
12686
12687 if removed_last_diagnostic_provider {
12688 server.update_capabilities(|capabilities| {
12689 debug_assert!(capabilities.diagnostic_provider.is_some());
12690 capabilities.diagnostic_provider = None;
12691 });
12692 }
12693
12694 notify_server_capabilities_updated(&server, cx);
12695 }
12696 "textDocument/documentColor" => {
12697 server.update_capabilities(|capabilities| {
12698 capabilities.color_provider = None;
12699 });
12700 notify_server_capabilities_updated(&server, cx);
12701 }
12702 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12703 }
12704 }
12705
12706 Ok(())
12707 }
12708
12709 async fn deduplicate_range_based_lsp_requests<T>(
12710 lsp_store: &Entity<Self>,
12711 server_id: Option<LanguageServerId>,
12712 lsp_request_id: LspRequestId,
12713 proto_request: &T::ProtoRequest,
12714 range: Range<Anchor>,
12715 cx: &mut AsyncApp,
12716 ) -> Result<()>
12717 where
12718 T: LspCommand,
12719 T::ProtoRequest: proto::LspRequestMessage,
12720 {
12721 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12722 let version = deserialize_version(proto_request.buffer_version());
12723 let buffer = lsp_store.update(cx, |this, cx| {
12724 this.buffer_store.read(cx).get_existing(buffer_id)
12725 })??;
12726 buffer
12727 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12728 .await?;
12729 lsp_store.update(cx, |lsp_store, cx| {
12730 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12731 let chunks_queried_for = lsp_data
12732 .inlay_hints
12733 .applicable_chunks(&[range])
12734 .collect::<Vec<_>>();
12735 match chunks_queried_for.as_slice() {
12736 &[chunk] => {
12737 let key = LspKey {
12738 request_type: TypeId::of::<T>(),
12739 server_queried: server_id,
12740 };
12741 let previous_request = lsp_data
12742 .chunk_lsp_requests
12743 .entry(key)
12744 .or_default()
12745 .insert(chunk, lsp_request_id);
12746 if let Some((previous_request, running_requests)) =
12747 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12748 {
12749 running_requests.remove(&previous_request);
12750 }
12751 }
12752 _ambiguous_chunks => {
12753 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12754 // there, a buffer version-based check will be performed and outdated requests discarded.
12755 }
12756 }
12757 anyhow::Ok(())
12758 })??;
12759
12760 Ok(())
12761 }
12762
12763 async fn query_lsp_locally<T>(
12764 lsp_store: Entity<Self>,
12765 for_server_id: Option<LanguageServerId>,
12766 sender_id: proto::PeerId,
12767 lsp_request_id: LspRequestId,
12768 proto_request: T::ProtoRequest,
12769 position: Option<Anchor>,
12770 cx: &mut AsyncApp,
12771 ) -> Result<()>
12772 where
12773 T: LspCommand + Clone,
12774 T::ProtoRequest: proto::LspRequestMessage,
12775 <T::ProtoRequest as proto::RequestMessage>::Response:
12776 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12777 {
12778 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12779 let version = deserialize_version(proto_request.buffer_version());
12780 let buffer = lsp_store.update(cx, |this, cx| {
12781 this.buffer_store.read(cx).get_existing(buffer_id)
12782 })??;
12783 buffer
12784 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12785 .await?;
12786 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12787 let request =
12788 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12789 let key = LspKey {
12790 request_type: TypeId::of::<T>(),
12791 server_queried: for_server_id,
12792 };
12793 lsp_store.update(cx, |lsp_store, cx| {
12794 let request_task = match for_server_id {
12795 Some(server_id) => {
12796 let server_task = lsp_store.request_lsp(
12797 buffer.clone(),
12798 LanguageServerToQuery::Other(server_id),
12799 request.clone(),
12800 cx,
12801 );
12802 cx.background_spawn(async move {
12803 let mut responses = Vec::new();
12804 match server_task.await {
12805 Ok(response) => responses.push((server_id, response)),
12806 // rust-analyzer likes to error with this when its still loading up
12807 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12808 Err(e) => log::error!(
12809 "Error handling response for request {request:?}: {e:#}"
12810 ),
12811 }
12812 responses
12813 })
12814 }
12815 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12816 };
12817 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12818 if T::ProtoRequest::stop_previous_requests() {
12819 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12820 lsp_requests.clear();
12821 }
12822 }
12823 lsp_data.lsp_requests.entry(key).or_default().insert(
12824 lsp_request_id,
12825 cx.spawn(async move |lsp_store, cx| {
12826 let response = request_task.await;
12827 lsp_store
12828 .update(cx, |lsp_store, cx| {
12829 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12830 {
12831 let response = response
12832 .into_iter()
12833 .map(|(server_id, response)| {
12834 (
12835 server_id.to_proto(),
12836 T::response_to_proto(
12837 response,
12838 lsp_store,
12839 sender_id,
12840 &buffer_version,
12841 cx,
12842 )
12843 .into(),
12844 )
12845 })
12846 .collect::<HashMap<_, _>>();
12847 match client.send_lsp_response::<T::ProtoRequest>(
12848 project_id,
12849 lsp_request_id,
12850 response,
12851 ) {
12852 Ok(()) => {}
12853 Err(e) => {
12854 log::error!("Failed to send LSP response: {e:#}",)
12855 }
12856 }
12857 }
12858 })
12859 .ok();
12860 }),
12861 );
12862 })?;
12863 Ok(())
12864 }
12865
12866 fn take_text_document_sync_options(
12867 capabilities: &mut lsp::ServerCapabilities,
12868 ) -> lsp::TextDocumentSyncOptions {
12869 match capabilities.text_document_sync.take() {
12870 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12871 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12872 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12873 sync_options.change = Some(sync_kind);
12874 sync_options
12875 }
12876 None => lsp::TextDocumentSyncOptions::default(),
12877 }
12878 }
12879
12880 #[cfg(any(test, feature = "test-support"))]
12881 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12882 Some(
12883 self.lsp_data
12884 .get_mut(&buffer_id)?
12885 .code_lens
12886 .take()?
12887 .update
12888 .take()?
12889 .1,
12890 )
12891 }
12892
12893 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12894 self.downstream_client.clone()
12895 }
12896
12897 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12898 self.worktree_store.clone()
12899 }
12900
12901 /// Gets what's stored in the LSP data for the given buffer.
12902 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12903 self.lsp_data.get_mut(&buffer_id)
12904 }
12905
12906 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12907 /// new [`BufferLspData`] will be created to replace the previous state.
12908 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12909 let (buffer_id, buffer_version) =
12910 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12911 let lsp_data = self
12912 .lsp_data
12913 .entry(buffer_id)
12914 .or_insert_with(|| BufferLspData::new(buffer, cx));
12915 if buffer_version.changed_since(&lsp_data.buffer_version) {
12916 *lsp_data = BufferLspData::new(buffer, cx);
12917 }
12918 lsp_data
12919 }
12920}
12921
12922// Registration with registerOptions as null, should fallback to true.
12923// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12924fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12925 reg: lsp::Registration,
12926) -> Result<OneOf<bool, T>> {
12927 Ok(match reg.register_options {
12928 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12929 None => OneOf::Left(true),
12930 })
12931}
12932
12933fn subscribe_to_binary_statuses(
12934 languages: &Arc<LanguageRegistry>,
12935 cx: &mut Context<'_, LspStore>,
12936) -> Task<()> {
12937 let mut server_statuses = languages.language_server_binary_statuses();
12938 cx.spawn(async move |lsp_store, cx| {
12939 while let Some((server_name, binary_status)) = server_statuses.next().await {
12940 if lsp_store
12941 .update(cx, |_, cx| {
12942 let mut message = None;
12943 let binary_status = match binary_status {
12944 BinaryStatus::None => proto::ServerBinaryStatus::None,
12945 BinaryStatus::CheckingForUpdate => {
12946 proto::ServerBinaryStatus::CheckingForUpdate
12947 }
12948 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12949 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12950 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12951 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12952 BinaryStatus::Failed { error } => {
12953 message = Some(error);
12954 proto::ServerBinaryStatus::Failed
12955 }
12956 };
12957 cx.emit(LspStoreEvent::LanguageServerUpdate {
12958 // Binary updates are about the binary that might not have any language server id at that point.
12959 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12960 language_server_id: LanguageServerId(0),
12961 name: Some(server_name),
12962 message: proto::update_language_server::Variant::StatusUpdate(
12963 proto::StatusUpdate {
12964 message,
12965 status: Some(proto::status_update::Status::Binary(
12966 binary_status as i32,
12967 )),
12968 },
12969 ),
12970 });
12971 })
12972 .is_err()
12973 {
12974 break;
12975 }
12976 }
12977 })
12978}
12979
12980fn lsp_workspace_diagnostics_refresh(
12981 registration_id: Option<String>,
12982 options: DiagnosticServerCapabilities,
12983 server: Arc<LanguageServer>,
12984 cx: &mut Context<'_, LspStore>,
12985) -> Option<WorkspaceRefreshTask> {
12986 let identifier = workspace_diagnostic_identifier(&options)?;
12987 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
12988
12989 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12990 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12991 refresh_tx.try_send(()).ok();
12992
12993 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12994 let mut attempts = 0;
12995 let max_attempts = 50;
12996 let mut requests = 0;
12997
12998 loop {
12999 let Some(()) = refresh_rx.recv().await else {
13000 return;
13001 };
13002
13003 'request: loop {
13004 requests += 1;
13005 if attempts > max_attempts {
13006 log::error!(
13007 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13008 );
13009 return;
13010 }
13011 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13012 cx.background_executor()
13013 .timer(Duration::from_millis(backoff_millis))
13014 .await;
13015 attempts += 1;
13016
13017 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13018 lsp_store
13019 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13020 .into_iter()
13021 .filter_map(|(abs_path, result_id)| {
13022 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13023 Some(lsp::PreviousResultId {
13024 uri,
13025 value: result_id.to_string(),
13026 })
13027 })
13028 .collect()
13029 }) else {
13030 return;
13031 };
13032
13033 let token = if let Some(registration_id) = ®istration_id {
13034 format!(
13035 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13036 server.server_id(),
13037 )
13038 } else {
13039 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13040 };
13041
13042 progress_rx.try_recv().ok();
13043 let timer =
13044 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13045 let progress = pin!(progress_rx.recv().fuse());
13046 let response_result = server
13047 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13048 lsp::WorkspaceDiagnosticParams {
13049 previous_result_ids,
13050 identifier: identifier.clone(),
13051 work_done_progress_params: Default::default(),
13052 partial_result_params: lsp::PartialResultParams {
13053 partial_result_token: Some(lsp::ProgressToken::String(token)),
13054 },
13055 },
13056 select(timer, progress).then(|either| match either {
13057 Either::Left((message, ..)) => ready(message).left_future(),
13058 Either::Right(..) => pending::<String>().right_future(),
13059 }),
13060 )
13061 .await;
13062
13063 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13064 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13065 match response_result {
13066 ConnectionResult::Timeout => {
13067 log::error!("Timeout during workspace diagnostics pull");
13068 continue 'request;
13069 }
13070 ConnectionResult::ConnectionReset => {
13071 log::error!("Server closed a workspace diagnostics pull request");
13072 continue 'request;
13073 }
13074 ConnectionResult::Result(Err(e)) => {
13075 log::error!("Error during workspace diagnostics pull: {e:#}");
13076 break 'request;
13077 }
13078 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13079 attempts = 0;
13080 if lsp_store
13081 .update(cx, |lsp_store, cx| {
13082 lsp_store.apply_workspace_diagnostic_report(
13083 server.server_id(),
13084 pulled_diagnostics,
13085 registration_id_shared.clone(),
13086 cx,
13087 )
13088 })
13089 .is_err()
13090 {
13091 return;
13092 }
13093 break 'request;
13094 }
13095 }
13096 }
13097 }
13098 });
13099
13100 Some(WorkspaceRefreshTask {
13101 refresh_tx,
13102 progress_tx,
13103 task: workspace_query_language_server,
13104 })
13105}
13106
13107fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13108 match &options {
13109 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13110 diagnostic_options.identifier.clone()
13111 }
13112 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13113 let diagnostic_options = ®istration_options.diagnostic_options;
13114 diagnostic_options.identifier.clone()
13115 }
13116 }
13117}
13118
13119fn workspace_diagnostic_identifier(
13120 options: &DiagnosticServerCapabilities,
13121) -> Option<Option<String>> {
13122 match &options {
13123 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13124 if !diagnostic_options.workspace_diagnostics {
13125 return None;
13126 }
13127 Some(diagnostic_options.identifier.clone())
13128 }
13129 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13130 let diagnostic_options = ®istration_options.diagnostic_options;
13131 if !diagnostic_options.workspace_diagnostics {
13132 return None;
13133 }
13134 Some(diagnostic_options.identifier.clone())
13135 }
13136 }
13137}
13138
13139fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13140 let CompletionSource::BufferWord {
13141 word_range,
13142 resolved,
13143 } = &mut completion.source
13144 else {
13145 return;
13146 };
13147 if *resolved {
13148 return;
13149 }
13150
13151 if completion.new_text
13152 != snapshot
13153 .text_for_range(word_range.clone())
13154 .collect::<String>()
13155 {
13156 return;
13157 }
13158
13159 let mut offset = 0;
13160 for chunk in snapshot.chunks(word_range.clone(), true) {
13161 let end_offset = offset + chunk.text.len();
13162 if let Some(highlight_id) = chunk.syntax_highlight_id {
13163 completion
13164 .label
13165 .runs
13166 .push((offset..end_offset, highlight_id));
13167 }
13168 offset = end_offset;
13169 }
13170 *resolved = true;
13171}
13172
13173impl EventEmitter<LspStoreEvent> for LspStore {}
13174
13175fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13176 hover
13177 .contents
13178 .retain(|hover_block| !hover_block.text.trim().is_empty());
13179 if hover.contents.is_empty() {
13180 None
13181 } else {
13182 Some(hover)
13183 }
13184}
13185
13186async fn populate_labels_for_completions(
13187 new_completions: Vec<CoreCompletion>,
13188 language: Option<Arc<Language>>,
13189 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13190) -> Vec<Completion> {
13191 let lsp_completions = new_completions
13192 .iter()
13193 .filter_map(|new_completion| {
13194 new_completion
13195 .source
13196 .lsp_completion(true)
13197 .map(|lsp_completion| lsp_completion.into_owned())
13198 })
13199 .collect::<Vec<_>>();
13200
13201 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13202 lsp_adapter
13203 .labels_for_completions(&lsp_completions, language)
13204 .await
13205 .log_err()
13206 .unwrap_or_default()
13207 } else {
13208 Vec::new()
13209 }
13210 .into_iter()
13211 .fuse();
13212
13213 let mut completions = Vec::new();
13214 for completion in new_completions {
13215 match completion.source.lsp_completion(true) {
13216 Some(lsp_completion) => {
13217 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13218
13219 let mut label = labels.next().flatten().unwrap_or_else(|| {
13220 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13221 });
13222 ensure_uniform_list_compatible_label(&mut label);
13223 completions.push(Completion {
13224 label,
13225 documentation,
13226 replace_range: completion.replace_range,
13227 new_text: completion.new_text,
13228 insert_text_mode: lsp_completion.insert_text_mode,
13229 source: completion.source,
13230 icon_path: None,
13231 confirm: None,
13232 match_start: None,
13233 snippet_deduplication_key: None,
13234 });
13235 }
13236 None => {
13237 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13238 ensure_uniform_list_compatible_label(&mut label);
13239 completions.push(Completion {
13240 label,
13241 documentation: None,
13242 replace_range: completion.replace_range,
13243 new_text: completion.new_text,
13244 source: completion.source,
13245 insert_text_mode: None,
13246 icon_path: None,
13247 confirm: None,
13248 match_start: None,
13249 snippet_deduplication_key: None,
13250 });
13251 }
13252 }
13253 }
13254 completions
13255}
13256
13257#[derive(Debug)]
13258pub enum LanguageServerToQuery {
13259 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13260 FirstCapable,
13261 /// Query a specific language server.
13262 Other(LanguageServerId),
13263}
13264
13265#[derive(Default)]
13266struct RenamePathsWatchedForServer {
13267 did_rename: Vec<RenameActionPredicate>,
13268 will_rename: Vec<RenameActionPredicate>,
13269}
13270
13271impl RenamePathsWatchedForServer {
13272 fn with_did_rename_patterns(
13273 mut self,
13274 did_rename: Option<&FileOperationRegistrationOptions>,
13275 ) -> Self {
13276 if let Some(did_rename) = did_rename {
13277 self.did_rename = did_rename
13278 .filters
13279 .iter()
13280 .filter_map(|filter| filter.try_into().log_err())
13281 .collect();
13282 }
13283 self
13284 }
13285 fn with_will_rename_patterns(
13286 mut self,
13287 will_rename: Option<&FileOperationRegistrationOptions>,
13288 ) -> Self {
13289 if let Some(will_rename) = will_rename {
13290 self.will_rename = will_rename
13291 .filters
13292 .iter()
13293 .filter_map(|filter| filter.try_into().log_err())
13294 .collect();
13295 }
13296 self
13297 }
13298
13299 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13300 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13301 }
13302 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13303 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13304 }
13305}
13306
13307impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13308 type Error = globset::Error;
13309 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13310 Ok(Self {
13311 kind: ops.pattern.matches.clone(),
13312 glob: GlobBuilder::new(&ops.pattern.glob)
13313 .case_insensitive(
13314 ops.pattern
13315 .options
13316 .as_ref()
13317 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13318 )
13319 .build()?
13320 .compile_matcher(),
13321 })
13322 }
13323}
13324struct RenameActionPredicate {
13325 glob: GlobMatcher,
13326 kind: Option<FileOperationPatternKind>,
13327}
13328
13329impl RenameActionPredicate {
13330 // Returns true if language server should be notified
13331 fn eval(&self, path: &str, is_dir: bool) -> bool {
13332 self.kind.as_ref().is_none_or(|kind| {
13333 let expected_kind = if is_dir {
13334 FileOperationPatternKind::Folder
13335 } else {
13336 FileOperationPatternKind::File
13337 };
13338 kind == &expected_kind
13339 }) && self.glob.is_match(path)
13340 }
13341}
13342
13343#[derive(Default)]
13344struct LanguageServerWatchedPaths {
13345 worktree_paths: HashMap<WorktreeId, GlobSet>,
13346 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13347}
13348
13349#[derive(Default)]
13350struct LanguageServerWatchedPathsBuilder {
13351 worktree_paths: HashMap<WorktreeId, GlobSet>,
13352 abs_paths: HashMap<Arc<Path>, GlobSet>,
13353}
13354
13355impl LanguageServerWatchedPathsBuilder {
13356 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13357 self.worktree_paths.insert(worktree_id, glob_set);
13358 }
13359 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13360 self.abs_paths.insert(path, glob_set);
13361 }
13362 fn build(
13363 self,
13364 fs: Arc<dyn Fs>,
13365 language_server_id: LanguageServerId,
13366 cx: &mut Context<LspStore>,
13367 ) -> LanguageServerWatchedPaths {
13368 let lsp_store = cx.weak_entity();
13369
13370 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13371 let abs_paths = self
13372 .abs_paths
13373 .into_iter()
13374 .map(|(abs_path, globset)| {
13375 let task = cx.spawn({
13376 let abs_path = abs_path.clone();
13377 let fs = fs.clone();
13378
13379 let lsp_store = lsp_store.clone();
13380 async move |_, cx| {
13381 maybe!(async move {
13382 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13383 while let Some(update) = push_updates.0.next().await {
13384 let action = lsp_store
13385 .update(cx, |this, _| {
13386 let Some(local) = this.as_local() else {
13387 return ControlFlow::Break(());
13388 };
13389 let Some(watcher) = local
13390 .language_server_watched_paths
13391 .get(&language_server_id)
13392 else {
13393 return ControlFlow::Break(());
13394 };
13395 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13396 "Watched abs path is not registered with a watcher",
13397 );
13398 let matching_entries = update
13399 .into_iter()
13400 .filter(|event| globs.is_match(&event.path))
13401 .collect::<Vec<_>>();
13402 this.lsp_notify_abs_paths_changed(
13403 language_server_id,
13404 matching_entries,
13405 );
13406 ControlFlow::Continue(())
13407 })
13408 .ok()?;
13409
13410 if action.is_break() {
13411 break;
13412 }
13413 }
13414 Some(())
13415 })
13416 .await;
13417 }
13418 });
13419 (abs_path, (globset, task))
13420 })
13421 .collect();
13422 LanguageServerWatchedPaths {
13423 worktree_paths: self.worktree_paths,
13424 abs_paths,
13425 }
13426 }
13427}
13428
13429struct LspBufferSnapshot {
13430 version: i32,
13431 snapshot: TextBufferSnapshot,
13432}
13433
13434/// A prompt requested by LSP server.
13435#[derive(Clone, Debug)]
13436pub struct LanguageServerPromptRequest {
13437 pub level: PromptLevel,
13438 pub message: String,
13439 pub actions: Vec<MessageActionItem>,
13440 pub lsp_name: String,
13441 pub(crate) response_channel: Sender<MessageActionItem>,
13442}
13443
13444impl LanguageServerPromptRequest {
13445 pub async fn respond(self, index: usize) -> Option<()> {
13446 if let Some(response) = self.actions.into_iter().nth(index) {
13447 self.response_channel.send(response).await.ok()
13448 } else {
13449 None
13450 }
13451 }
13452}
13453impl PartialEq for LanguageServerPromptRequest {
13454 fn eq(&self, other: &Self) -> bool {
13455 self.message == other.message && self.actions == other.actions
13456 }
13457}
13458
13459#[derive(Clone, Debug, PartialEq)]
13460pub enum LanguageServerLogType {
13461 Log(MessageType),
13462 Trace { verbose_info: Option<String> },
13463 Rpc { received: bool },
13464}
13465
13466impl LanguageServerLogType {
13467 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13468 match self {
13469 Self::Log(log_type) => {
13470 use proto::log_message::LogLevel;
13471 let level = match *log_type {
13472 MessageType::ERROR => LogLevel::Error,
13473 MessageType::WARNING => LogLevel::Warning,
13474 MessageType::INFO => LogLevel::Info,
13475 MessageType::LOG => LogLevel::Log,
13476 other => {
13477 log::warn!("Unknown lsp log message type: {other:?}");
13478 LogLevel::Log
13479 }
13480 };
13481 proto::language_server_log::LogType::Log(proto::LogMessage {
13482 level: level as i32,
13483 })
13484 }
13485 Self::Trace { verbose_info } => {
13486 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13487 verbose_info: verbose_info.to_owned(),
13488 })
13489 }
13490 Self::Rpc { received } => {
13491 let kind = if *received {
13492 proto::rpc_message::Kind::Received
13493 } else {
13494 proto::rpc_message::Kind::Sent
13495 };
13496 let kind = kind as i32;
13497 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13498 }
13499 }
13500 }
13501
13502 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13503 use proto::log_message::LogLevel;
13504 use proto::rpc_message;
13505 match log_type {
13506 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13507 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13508 LogLevel::Error => MessageType::ERROR,
13509 LogLevel::Warning => MessageType::WARNING,
13510 LogLevel::Info => MessageType::INFO,
13511 LogLevel::Log => MessageType::LOG,
13512 },
13513 ),
13514 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13515 verbose_info: trace_message.verbose_info,
13516 },
13517 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13518 received: match rpc_message::Kind::from_i32(message.kind)
13519 .unwrap_or(rpc_message::Kind::Received)
13520 {
13521 rpc_message::Kind::Received => true,
13522 rpc_message::Kind::Sent => false,
13523 },
13524 },
13525 }
13526 }
13527}
13528
13529pub struct WorkspaceRefreshTask {
13530 refresh_tx: mpsc::Sender<()>,
13531 progress_tx: mpsc::Sender<()>,
13532 #[allow(dead_code)]
13533 task: Task<()>,
13534}
13535
13536pub enum LanguageServerState {
13537 Starting {
13538 startup: Task<Option<Arc<LanguageServer>>>,
13539 /// List of language servers that will be added to the workspace once it's initialization completes.
13540 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13541 },
13542
13543 Running {
13544 adapter: Arc<CachedLspAdapter>,
13545 server: Arc<LanguageServer>,
13546 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13547 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13548 },
13549}
13550
13551impl LanguageServerState {
13552 fn add_workspace_folder(&self, uri: Uri) {
13553 match self {
13554 LanguageServerState::Starting {
13555 pending_workspace_folders,
13556 ..
13557 } => {
13558 pending_workspace_folders.lock().insert(uri);
13559 }
13560 LanguageServerState::Running { server, .. } => {
13561 server.add_workspace_folder(uri);
13562 }
13563 }
13564 }
13565 fn _remove_workspace_folder(&self, uri: Uri) {
13566 match self {
13567 LanguageServerState::Starting {
13568 pending_workspace_folders,
13569 ..
13570 } => {
13571 pending_workspace_folders.lock().remove(&uri);
13572 }
13573 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13574 }
13575 }
13576}
13577
13578impl std::fmt::Debug for LanguageServerState {
13579 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13580 match self {
13581 LanguageServerState::Starting { .. } => {
13582 f.debug_struct("LanguageServerState::Starting").finish()
13583 }
13584 LanguageServerState::Running { .. } => {
13585 f.debug_struct("LanguageServerState::Running").finish()
13586 }
13587 }
13588 }
13589}
13590
13591#[derive(Clone, Debug, Serialize)]
13592pub struct LanguageServerProgress {
13593 pub is_disk_based_diagnostics_progress: bool,
13594 pub is_cancellable: bool,
13595 pub title: Option<String>,
13596 pub message: Option<String>,
13597 pub percentage: Option<usize>,
13598 #[serde(skip_serializing)]
13599 pub last_update_at: Instant,
13600}
13601
13602#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13603pub struct DiagnosticSummary {
13604 pub error_count: usize,
13605 pub warning_count: usize,
13606}
13607
13608impl DiagnosticSummary {
13609 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13610 let mut this = Self {
13611 error_count: 0,
13612 warning_count: 0,
13613 };
13614
13615 for entry in diagnostics {
13616 if entry.diagnostic.is_primary {
13617 match entry.diagnostic.severity {
13618 DiagnosticSeverity::ERROR => this.error_count += 1,
13619 DiagnosticSeverity::WARNING => this.warning_count += 1,
13620 _ => {}
13621 }
13622 }
13623 }
13624
13625 this
13626 }
13627
13628 pub fn is_empty(&self) -> bool {
13629 self.error_count == 0 && self.warning_count == 0
13630 }
13631
13632 pub fn to_proto(
13633 self,
13634 language_server_id: LanguageServerId,
13635 path: &RelPath,
13636 ) -> proto::DiagnosticSummary {
13637 proto::DiagnosticSummary {
13638 path: path.to_proto(),
13639 language_server_id: language_server_id.0 as u64,
13640 error_count: self.error_count as u32,
13641 warning_count: self.warning_count as u32,
13642 }
13643 }
13644}
13645
13646#[derive(Clone, Debug)]
13647pub enum CompletionDocumentation {
13648 /// There is no documentation for this completion.
13649 Undocumented,
13650 /// A single line of documentation.
13651 SingleLine(SharedString),
13652 /// Multiple lines of plain text documentation.
13653 MultiLinePlainText(SharedString),
13654 /// Markdown documentation.
13655 MultiLineMarkdown(SharedString),
13656 /// Both single line and multiple lines of plain text documentation.
13657 SingleLineAndMultiLinePlainText {
13658 single_line: SharedString,
13659 plain_text: Option<SharedString>,
13660 },
13661}
13662
13663impl CompletionDocumentation {
13664 #[cfg(any(test, feature = "test-support"))]
13665 pub fn text(&self) -> SharedString {
13666 match self {
13667 CompletionDocumentation::Undocumented => "".into(),
13668 CompletionDocumentation::SingleLine(s) => s.clone(),
13669 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13670 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13671 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13672 single_line.clone()
13673 }
13674 }
13675 }
13676}
13677
13678impl From<lsp::Documentation> for CompletionDocumentation {
13679 fn from(docs: lsp::Documentation) -> Self {
13680 match docs {
13681 lsp::Documentation::String(text) => {
13682 if text.lines().count() <= 1 {
13683 CompletionDocumentation::SingleLine(text.into())
13684 } else {
13685 CompletionDocumentation::MultiLinePlainText(text.into())
13686 }
13687 }
13688
13689 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13690 lsp::MarkupKind::PlainText => {
13691 if value.lines().count() <= 1 {
13692 CompletionDocumentation::SingleLine(value.into())
13693 } else {
13694 CompletionDocumentation::MultiLinePlainText(value.into())
13695 }
13696 }
13697
13698 lsp::MarkupKind::Markdown => {
13699 CompletionDocumentation::MultiLineMarkdown(value.into())
13700 }
13701 },
13702 }
13703 }
13704}
13705
13706pub enum ResolvedHint {
13707 Resolved(InlayHint),
13708 Resolving(Shared<Task<()>>),
13709}
13710
13711fn glob_literal_prefix(glob: &Path) -> PathBuf {
13712 glob.components()
13713 .take_while(|component| match component {
13714 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13715 _ => true,
13716 })
13717 .collect()
13718}
13719
13720pub struct SshLspAdapter {
13721 name: LanguageServerName,
13722 binary: LanguageServerBinary,
13723 initialization_options: Option<String>,
13724 code_action_kinds: Option<Vec<CodeActionKind>>,
13725}
13726
13727impl SshLspAdapter {
13728 pub fn new(
13729 name: LanguageServerName,
13730 binary: LanguageServerBinary,
13731 initialization_options: Option<String>,
13732 code_action_kinds: Option<String>,
13733 ) -> Self {
13734 Self {
13735 name,
13736 binary,
13737 initialization_options,
13738 code_action_kinds: code_action_kinds
13739 .as_ref()
13740 .and_then(|c| serde_json::from_str(c).ok()),
13741 }
13742 }
13743}
13744
13745impl LspInstaller for SshLspAdapter {
13746 type BinaryVersion = ();
13747 async fn check_if_user_installed(
13748 &self,
13749 _: &dyn LspAdapterDelegate,
13750 _: Option<Toolchain>,
13751 _: &AsyncApp,
13752 ) -> Option<LanguageServerBinary> {
13753 Some(self.binary.clone())
13754 }
13755
13756 async fn cached_server_binary(
13757 &self,
13758 _: PathBuf,
13759 _: &dyn LspAdapterDelegate,
13760 ) -> Option<LanguageServerBinary> {
13761 None
13762 }
13763
13764 async fn fetch_latest_server_version(
13765 &self,
13766 _: &dyn LspAdapterDelegate,
13767 _: bool,
13768 _: &mut AsyncApp,
13769 ) -> Result<()> {
13770 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13771 }
13772
13773 async fn fetch_server_binary(
13774 &self,
13775 _: (),
13776 _: PathBuf,
13777 _: &dyn LspAdapterDelegate,
13778 ) -> Result<LanguageServerBinary> {
13779 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13780 }
13781}
13782
13783#[async_trait(?Send)]
13784impl LspAdapter for SshLspAdapter {
13785 fn name(&self) -> LanguageServerName {
13786 self.name.clone()
13787 }
13788
13789 async fn initialization_options(
13790 self: Arc<Self>,
13791 _: &Arc<dyn LspAdapterDelegate>,
13792 ) -> Result<Option<serde_json::Value>> {
13793 let Some(options) = &self.initialization_options else {
13794 return Ok(None);
13795 };
13796 let result = serde_json::from_str(options)?;
13797 Ok(result)
13798 }
13799
13800 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13801 self.code_action_kinds.clone()
13802 }
13803}
13804
13805pub fn language_server_settings<'a>(
13806 delegate: &'a dyn LspAdapterDelegate,
13807 language: &LanguageServerName,
13808 cx: &'a App,
13809) -> Option<&'a LspSettings> {
13810 language_server_settings_for(
13811 SettingsLocation {
13812 worktree_id: delegate.worktree_id(),
13813 path: RelPath::empty(),
13814 },
13815 language,
13816 cx,
13817 )
13818}
13819
13820pub fn language_server_settings_for<'a>(
13821 location: SettingsLocation<'a>,
13822 language: &LanguageServerName,
13823 cx: &'a App,
13824) -> Option<&'a LspSettings> {
13825 ProjectSettings::get(Some(location), cx).lsp.get(language)
13826}
13827
13828pub struct LocalLspAdapterDelegate {
13829 lsp_store: WeakEntity<LspStore>,
13830 worktree: worktree::Snapshot,
13831 fs: Arc<dyn Fs>,
13832 http_client: Arc<dyn HttpClient>,
13833 language_registry: Arc<LanguageRegistry>,
13834 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13835}
13836
13837impl LocalLspAdapterDelegate {
13838 pub fn new(
13839 language_registry: Arc<LanguageRegistry>,
13840 environment: &Entity<ProjectEnvironment>,
13841 lsp_store: WeakEntity<LspStore>,
13842 worktree: &Entity<Worktree>,
13843 http_client: Arc<dyn HttpClient>,
13844 fs: Arc<dyn Fs>,
13845 cx: &mut App,
13846 ) -> Arc<Self> {
13847 let load_shell_env_task =
13848 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13849
13850 Arc::new(Self {
13851 lsp_store,
13852 worktree: worktree.read(cx).snapshot(),
13853 fs,
13854 http_client,
13855 language_registry,
13856 load_shell_env_task,
13857 })
13858 }
13859
13860 fn from_local_lsp(
13861 local: &LocalLspStore,
13862 worktree: &Entity<Worktree>,
13863 cx: &mut App,
13864 ) -> Arc<Self> {
13865 Self::new(
13866 local.languages.clone(),
13867 &local.environment,
13868 local.weak.clone(),
13869 worktree,
13870 local.http_client.clone(),
13871 local.fs.clone(),
13872 cx,
13873 )
13874 }
13875}
13876
13877#[async_trait]
13878impl LspAdapterDelegate for LocalLspAdapterDelegate {
13879 fn show_notification(&self, message: &str, cx: &mut App) {
13880 self.lsp_store
13881 .update(cx, |_, cx| {
13882 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13883 })
13884 .ok();
13885 }
13886
13887 fn http_client(&self) -> Arc<dyn HttpClient> {
13888 self.http_client.clone()
13889 }
13890
13891 fn worktree_id(&self) -> WorktreeId {
13892 self.worktree.id()
13893 }
13894
13895 fn worktree_root_path(&self) -> &Path {
13896 self.worktree.abs_path().as_ref()
13897 }
13898
13899 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13900 self.worktree.resolve_executable_path(path)
13901 }
13902
13903 async fn shell_env(&self) -> HashMap<String, String> {
13904 let task = self.load_shell_env_task.clone();
13905 task.await.unwrap_or_default()
13906 }
13907
13908 async fn npm_package_installed_version(
13909 &self,
13910 package_name: &str,
13911 ) -> Result<Option<(PathBuf, String)>> {
13912 let local_package_directory = self.worktree_root_path();
13913 let node_modules_directory = local_package_directory.join("node_modules");
13914
13915 if let Some(version) =
13916 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13917 {
13918 return Ok(Some((node_modules_directory, version)));
13919 }
13920 let Some(npm) = self.which("npm".as_ref()).await else {
13921 log::warn!(
13922 "Failed to find npm executable for {:?}",
13923 local_package_directory
13924 );
13925 return Ok(None);
13926 };
13927
13928 let env = self.shell_env().await;
13929 let output = util::command::new_smol_command(&npm)
13930 .args(["root", "-g"])
13931 .envs(env)
13932 .current_dir(local_package_directory)
13933 .output()
13934 .await?;
13935 let global_node_modules =
13936 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13937
13938 if let Some(version) =
13939 read_package_installed_version(global_node_modules.clone(), package_name).await?
13940 {
13941 return Ok(Some((global_node_modules, version)));
13942 }
13943 return Ok(None);
13944 }
13945
13946 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13947 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13948 if self.fs.is_file(&worktree_abs_path).await {
13949 worktree_abs_path.pop();
13950 }
13951
13952 let env = self.shell_env().await;
13953
13954 let shell_path = env.get("PATH").cloned();
13955
13956 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13957 }
13958
13959 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13960 let mut working_dir = self.worktree_root_path().to_path_buf();
13961 if self.fs.is_file(&working_dir).await {
13962 working_dir.pop();
13963 }
13964 let output = util::command::new_smol_command(&command.path)
13965 .args(command.arguments)
13966 .envs(command.env.clone().unwrap_or_default())
13967 .current_dir(working_dir)
13968 .output()
13969 .await?;
13970
13971 anyhow::ensure!(
13972 output.status.success(),
13973 "{}, stdout: {:?}, stderr: {:?}",
13974 output.status,
13975 String::from_utf8_lossy(&output.stdout),
13976 String::from_utf8_lossy(&output.stderr)
13977 );
13978 Ok(())
13979 }
13980
13981 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13982 self.language_registry
13983 .update_lsp_binary_status(server_name, status);
13984 }
13985
13986 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13987 self.language_registry
13988 .all_lsp_adapters()
13989 .into_iter()
13990 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13991 .collect()
13992 }
13993
13994 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13995 let dir = self.language_registry.language_server_download_dir(name)?;
13996
13997 if !dir.exists() {
13998 smol::fs::create_dir_all(&dir)
13999 .await
14000 .context("failed to create container directory")
14001 .log_err()?;
14002 }
14003
14004 Some(dir)
14005 }
14006
14007 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14008 let entry = self
14009 .worktree
14010 .entry_for_path(path)
14011 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14012 let abs_path = self.worktree.absolutize(&entry.path);
14013 self.fs.load(&abs_path).await
14014 }
14015}
14016
14017async fn populate_labels_for_symbols(
14018 symbols: Vec<CoreSymbol>,
14019 language_registry: &Arc<LanguageRegistry>,
14020 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14021 output: &mut Vec<Symbol>,
14022) {
14023 #[allow(clippy::mutable_key_type)]
14024 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14025
14026 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14027 for symbol in symbols {
14028 let Some(file_name) = symbol.path.file_name() else {
14029 continue;
14030 };
14031 let language = language_registry
14032 .load_language_for_file_path(Path::new(file_name))
14033 .await
14034 .ok()
14035 .or_else(|| {
14036 unknown_paths.insert(file_name.into());
14037 None
14038 });
14039 symbols_by_language
14040 .entry(language)
14041 .or_default()
14042 .push(symbol);
14043 }
14044
14045 for unknown_path in unknown_paths {
14046 log::info!("no language found for symbol in file {unknown_path:?}");
14047 }
14048
14049 let mut label_params = Vec::new();
14050 for (language, mut symbols) in symbols_by_language {
14051 label_params.clear();
14052 label_params.extend(
14053 symbols
14054 .iter_mut()
14055 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14056 );
14057
14058 let mut labels = Vec::new();
14059 if let Some(language) = language {
14060 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14061 language_registry
14062 .lsp_adapters(&language.name())
14063 .first()
14064 .cloned()
14065 });
14066 if let Some(lsp_adapter) = lsp_adapter {
14067 labels = lsp_adapter
14068 .labels_for_symbols(&label_params, &language)
14069 .await
14070 .log_err()
14071 .unwrap_or_default();
14072 }
14073 }
14074
14075 for ((symbol, (name, _)), label) in symbols
14076 .into_iter()
14077 .zip(label_params.drain(..))
14078 .zip(labels.into_iter().chain(iter::repeat(None)))
14079 {
14080 output.push(Symbol {
14081 language_server_name: symbol.language_server_name,
14082 source_worktree_id: symbol.source_worktree_id,
14083 source_language_server_id: symbol.source_language_server_id,
14084 path: symbol.path,
14085 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14086 name,
14087 kind: symbol.kind,
14088 range: symbol.range,
14089 });
14090 }
14091 }
14092}
14093
14094fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14095 match server.capabilities().text_document_sync.as_ref()? {
14096 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14097 // Server wants didSave but didn't specify includeText.
14098 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14099 // Server doesn't want didSave at all.
14100 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14101 // Server provided SaveOptions.
14102 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14103 Some(save_options.include_text.unwrap_or(false))
14104 }
14105 },
14106 // We do not have any save info. Kind affects didChange only.
14107 lsp::TextDocumentSyncCapability::Kind(_) => None,
14108 }
14109}
14110
14111/// Completion items are displayed in a `UniformList`.
14112/// Usually, those items are single-line strings, but in LSP responses,
14113/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14114/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14115/// 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,
14116/// breaking the completions menu presentation.
14117///
14118/// 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.
14119fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14120 let mut new_text = String::with_capacity(label.text.len());
14121 let mut offset_map = vec![0; label.text.len() + 1];
14122 let mut last_char_was_space = false;
14123 let mut new_idx = 0;
14124 let chars = label.text.char_indices().fuse();
14125 let mut newlines_removed = false;
14126
14127 for (idx, c) in chars {
14128 offset_map[idx] = new_idx;
14129
14130 match c {
14131 '\n' if last_char_was_space => {
14132 newlines_removed = true;
14133 }
14134 '\t' | ' ' if last_char_was_space => {}
14135 '\n' if !last_char_was_space => {
14136 new_text.push(' ');
14137 new_idx += 1;
14138 last_char_was_space = true;
14139 newlines_removed = true;
14140 }
14141 ' ' | '\t' => {
14142 new_text.push(' ');
14143 new_idx += 1;
14144 last_char_was_space = true;
14145 }
14146 _ => {
14147 new_text.push(c);
14148 new_idx += c.len_utf8();
14149 last_char_was_space = false;
14150 }
14151 }
14152 }
14153 offset_map[label.text.len()] = new_idx;
14154
14155 // Only modify the label if newlines were removed.
14156 if !newlines_removed {
14157 return;
14158 }
14159
14160 let last_index = new_idx;
14161 let mut run_ranges_errors = Vec::new();
14162 label.runs.retain_mut(|(range, _)| {
14163 match offset_map.get(range.start) {
14164 Some(&start) => range.start = start,
14165 None => {
14166 run_ranges_errors.push(range.clone());
14167 return false;
14168 }
14169 }
14170
14171 match offset_map.get(range.end) {
14172 Some(&end) => range.end = end,
14173 None => {
14174 run_ranges_errors.push(range.clone());
14175 range.end = last_index;
14176 }
14177 }
14178 true
14179 });
14180 if !run_ranges_errors.is_empty() {
14181 log::error!(
14182 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14183 label.text
14184 );
14185 }
14186
14187 let mut wrong_filter_range = None;
14188 if label.filter_range == (0..label.text.len()) {
14189 label.filter_range = 0..new_text.len();
14190 } else {
14191 let mut original_filter_range = Some(label.filter_range.clone());
14192 match offset_map.get(label.filter_range.start) {
14193 Some(&start) => label.filter_range.start = start,
14194 None => {
14195 wrong_filter_range = original_filter_range.take();
14196 label.filter_range.start = last_index;
14197 }
14198 }
14199
14200 match offset_map.get(label.filter_range.end) {
14201 Some(&end) => label.filter_range.end = end,
14202 None => {
14203 wrong_filter_range = original_filter_range.take();
14204 label.filter_range.end = last_index;
14205 }
14206 }
14207 }
14208 if let Some(wrong_filter_range) = wrong_filter_range {
14209 log::error!(
14210 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14211 label.text
14212 );
14213 }
14214
14215 label.text = new_text;
14216}
14217
14218#[cfg(test)]
14219mod tests {
14220 use language::HighlightId;
14221
14222 use super::*;
14223
14224 #[test]
14225 fn test_glob_literal_prefix() {
14226 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14227 assert_eq!(
14228 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14229 Path::new("node_modules")
14230 );
14231 assert_eq!(
14232 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14233 Path::new("foo")
14234 );
14235 assert_eq!(
14236 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14237 Path::new("foo/bar/baz.js")
14238 );
14239
14240 #[cfg(target_os = "windows")]
14241 {
14242 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14243 assert_eq!(
14244 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14245 Path::new("node_modules")
14246 );
14247 assert_eq!(
14248 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14249 Path::new("foo")
14250 );
14251 assert_eq!(
14252 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14253 Path::new("foo/bar/baz.js")
14254 );
14255 }
14256 }
14257
14258 #[test]
14259 fn test_multi_len_chars_normalization() {
14260 let mut label = CodeLabel::new(
14261 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14262 0..6,
14263 vec![(0..6, HighlightId(1))],
14264 );
14265 ensure_uniform_list_compatible_label(&mut label);
14266 assert_eq!(
14267 label,
14268 CodeLabel::new(
14269 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14270 0..6,
14271 vec![(0..6, HighlightId(1))],
14272 )
14273 );
14274 }
14275}