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 }
429 });
430
431 let startup = {
432 let server_name = adapter.name.0.clone();
433 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
434 let key = key.clone();
435 let adapter = adapter.clone();
436 let lsp_store = self.weak.clone();
437 let pending_workspace_folders = pending_workspace_folders.clone();
438
439 let pull_diagnostics = ProjectSettings::get_global(cx)
440 .diagnostics
441 .lsp_pull_diagnostics
442 .enabled;
443 cx.spawn(async move |cx| {
444 let result = async {
445 let language_server = pending_server.await?;
446
447 let workspace_config = Self::workspace_configuration_for_adapter(
448 adapter.adapter.clone(),
449 &delegate,
450 toolchain,
451 None,
452 cx,
453 )
454 .await?;
455
456 let mut initialization_options = Self::initialization_options_for_adapter(
457 adapter.adapter.clone(),
458 &delegate,
459 )
460 .await?;
461
462 match (&mut initialization_options, override_options) {
463 (Some(initialization_options), Some(override_options)) => {
464 merge_json_value_into(override_options, initialization_options);
465 }
466 (None, override_options) => initialization_options = override_options,
467 _ => {}
468 }
469
470 let initialization_params = cx.update(|cx| {
471 let mut params =
472 language_server.default_initialize_params(pull_diagnostics, cx);
473 params.initialization_options = initialization_options;
474 adapter.adapter.prepare_initialize_params(params, cx)
475 })??;
476
477 Self::setup_lsp_messages(
478 lsp_store.clone(),
479 &language_server,
480 delegate.clone(),
481 adapter.clone(),
482 );
483
484 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
485 settings: workspace_config,
486 };
487 let language_server = cx
488 .update(|cx| {
489 language_server.initialize(
490 initialization_params,
491 Arc::new(did_change_configuration_params.clone()),
492 cx,
493 )
494 })?
495 .await
496 .inspect_err(|_| {
497 if let Some(lsp_store) = lsp_store.upgrade() {
498 lsp_store
499 .update(cx, |lsp_store, cx| {
500 lsp_store.cleanup_lsp_data(server_id);
501 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
502 })
503 .ok();
504 }
505 })?;
506
507 language_server.notify::<lsp::notification::DidChangeConfiguration>(
508 did_change_configuration_params,
509 )?;
510
511 anyhow::Ok(language_server)
512 }
513 .await;
514
515 match result {
516 Ok(server) => {
517 lsp_store
518 .update(cx, |lsp_store, cx| {
519 lsp_store.insert_newly_running_language_server(
520 adapter,
521 server.clone(),
522 server_id,
523 key,
524 pending_workspace_folders,
525 cx,
526 );
527 })
528 .ok();
529 stderr_capture.lock().take();
530 Some(server)
531 }
532
533 Err(err) => {
534 let log = stderr_capture.lock().take().unwrap_or_default();
535 delegate.update_status(
536 adapter.name(),
537 BinaryStatus::Failed {
538 error: if log.is_empty() {
539 format!("{err:#}")
540 } else {
541 format!("{err:#}\n-- stderr --\n{log}")
542 },
543 },
544 );
545 log::error!("Failed to start language server {server_name:?}: {err:?}");
546 if !log.is_empty() {
547 log::error!("server stderr: {log}");
548 }
549 None
550 }
551 }
552 })
553 };
554 let state = LanguageServerState::Starting {
555 startup,
556 pending_workspace_folders,
557 };
558
559 self.languages
560 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
561
562 self.language_servers.insert(server_id, state);
563 self.language_server_ids
564 .entry(key)
565 .or_insert(UnifiedLanguageServer {
566 id: server_id,
567 project_roots: Default::default(),
568 });
569 server_id
570 }
571
572 fn get_language_server_binary(
573 &self,
574 adapter: Arc<CachedLspAdapter>,
575 settings: Arc<LspSettings>,
576 toolchain: Option<Toolchain>,
577 delegate: Arc<dyn LspAdapterDelegate>,
578 allow_binary_download: bool,
579 cx: &mut App,
580 ) -> Task<Result<LanguageServerBinary>> {
581 if let Some(settings) = &settings.binary
582 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
583 {
584 let settings = settings.clone();
585
586 return cx.background_spawn(async move {
587 let mut env = delegate.shell_env().await;
588 env.extend(settings.env.unwrap_or_default());
589
590 Ok(LanguageServerBinary {
591 path: delegate.resolve_executable_path(path),
592 env: Some(env),
593 arguments: settings
594 .arguments
595 .unwrap_or_default()
596 .iter()
597 .map(Into::into)
598 .collect(),
599 })
600 });
601 }
602 let lsp_binary_options = LanguageServerBinaryOptions {
603 allow_path_lookup: !settings
604 .binary
605 .as_ref()
606 .and_then(|b| b.ignore_system_version)
607 .unwrap_or_default(),
608 allow_binary_download,
609 pre_release: settings
610 .fetch
611 .as_ref()
612 .and_then(|f| f.pre_release)
613 .unwrap_or(false),
614 };
615
616 cx.spawn(async move |cx| {
617 let (existing_binary, maybe_download_binary) = adapter
618 .clone()
619 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
620 .await
621 .await;
622
623 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
624
625 let mut binary = match (existing_binary, maybe_download_binary) {
626 (binary, None) => binary?,
627 (Err(_), Some(downloader)) => downloader.await?,
628 (Ok(existing_binary), Some(downloader)) => {
629 let mut download_timeout = cx
630 .background_executor()
631 .timer(SERVER_DOWNLOAD_TIMEOUT)
632 .fuse();
633 let mut downloader = downloader.fuse();
634 futures::select! {
635 _ = download_timeout => {
636 // Return existing binary and kick the existing work to the background.
637 cx.spawn(async move |_| downloader.await).detach();
638 Ok(existing_binary)
639 },
640 downloaded_or_existing_binary = downloader => {
641 // If download fails, this results in the existing binary.
642 downloaded_or_existing_binary
643 }
644 }?
645 }
646 };
647 let mut shell_env = delegate.shell_env().await;
648
649 shell_env.extend(binary.env.unwrap_or_default());
650
651 if let Some(settings) = settings.binary.as_ref() {
652 if let Some(arguments) = &settings.arguments {
653 binary.arguments = arguments.iter().map(Into::into).collect();
654 }
655 if let Some(env) = &settings.env {
656 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
657 }
658 }
659
660 binary.env = Some(shell_env);
661 Ok(binary)
662 })
663 }
664
665 fn setup_lsp_messages(
666 lsp_store: WeakEntity<LspStore>,
667 language_server: &LanguageServer,
668 delegate: Arc<dyn LspAdapterDelegate>,
669 adapter: Arc<CachedLspAdapter>,
670 ) {
671 let name = language_server.name();
672 let server_id = language_server.server_id();
673 language_server
674 .on_notification::<lsp::notification::PublishDiagnostics, _>({
675 let adapter = adapter.clone();
676 let this = lsp_store.clone();
677 move |mut params, cx| {
678 let adapter = adapter.clone();
679 if let Some(this) = this.upgrade() {
680 this.update(cx, |this, cx| {
681 {
682 let buffer = params
683 .uri
684 .to_file_path()
685 .map(|file_path| this.get_buffer(&file_path, cx))
686 .ok()
687 .flatten();
688 adapter.process_diagnostics(&mut params, server_id, buffer);
689 }
690
691 this.merge_lsp_diagnostics(
692 DiagnosticSourceKind::Pushed,
693 vec![DocumentDiagnosticsUpdate {
694 server_id,
695 diagnostics: params,
696 result_id: None,
697 disk_based_sources: Cow::Borrowed(
698 &adapter.disk_based_diagnostic_sources,
699 ),
700 registration_id: None,
701 }],
702 |_, diagnostic, cx| match diagnostic.source_kind {
703 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
704 adapter.retain_old_diagnostic(diagnostic, cx)
705 }
706 DiagnosticSourceKind::Pulled => true,
707 },
708 cx,
709 )
710 .log_err();
711 })
712 .ok();
713 }
714 }
715 })
716 .detach();
717 language_server
718 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
719 let adapter = adapter.adapter.clone();
720 let delegate = delegate.clone();
721 let this = lsp_store.clone();
722 move |params, cx| {
723 let adapter = adapter.clone();
724 let delegate = delegate.clone();
725 let this = this.clone();
726 let mut cx = cx.clone();
727 async move {
728 let toolchain_for_id = this
729 .update(&mut cx, |this, _| {
730 this.as_local()?.language_server_ids.iter().find_map(
731 |(seed, value)| {
732 (value.id == server_id).then(|| seed.toolchain.clone())
733 },
734 )
735 })?
736 .context("Expected the LSP store to be in a local mode")?;
737
738 let mut scope_uri_to_workspace_config = BTreeMap::new();
739 for item in ¶ms.items {
740 let scope_uri = item.scope_uri.clone();
741 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
742 scope_uri_to_workspace_config.entry(scope_uri.clone())
743 else {
744 // We've already queried workspace configuration of this URI.
745 continue;
746 };
747 let workspace_config = Self::workspace_configuration_for_adapter(
748 adapter.clone(),
749 &delegate,
750 toolchain_for_id.clone(),
751 scope_uri,
752 &mut cx,
753 )
754 .await?;
755 new_scope_uri.insert(workspace_config);
756 }
757
758 Ok(params
759 .items
760 .into_iter()
761 .filter_map(|item| {
762 let workspace_config =
763 scope_uri_to_workspace_config.get(&item.scope_uri)?;
764 if let Some(section) = &item.section {
765 Some(
766 workspace_config
767 .get(section)
768 .cloned()
769 .unwrap_or(serde_json::Value::Null),
770 )
771 } else {
772 Some(workspace_config.clone())
773 }
774 })
775 .collect())
776 }
777 }
778 })
779 .detach();
780
781 language_server
782 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
783 let this = lsp_store.clone();
784 move |_, cx| {
785 let this = this.clone();
786 let cx = cx.clone();
787 async move {
788 let Some(server) =
789 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
790 else {
791 return Ok(None);
792 };
793 let root = server.workspace_folders();
794 Ok(Some(
795 root.into_iter()
796 .map(|uri| WorkspaceFolder {
797 uri,
798 name: Default::default(),
799 })
800 .collect(),
801 ))
802 }
803 }
804 })
805 .detach();
806 // Even though we don't have handling for these requests, respond to them to
807 // avoid stalling any language server like `gopls` which waits for a response
808 // to these requests when initializing.
809 language_server
810 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
811 let this = lsp_store.clone();
812 move |params, cx| {
813 let this = this.clone();
814 let mut cx = cx.clone();
815 async move {
816 this.update(&mut cx, |this, _| {
817 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
818 {
819 status
820 .progress_tokens
821 .insert(ProgressToken::from_lsp(params.token));
822 }
823 })?;
824
825 Ok(())
826 }
827 }
828 })
829 .detach();
830
831 language_server
832 .on_request::<lsp::request::RegisterCapability, _, _>({
833 let lsp_store = lsp_store.clone();
834 move |params, cx| {
835 let lsp_store = lsp_store.clone();
836 let mut cx = cx.clone();
837 async move {
838 lsp_store
839 .update(&mut cx, |lsp_store, cx| {
840 if lsp_store.as_local().is_some() {
841 match lsp_store
842 .register_server_capabilities(server_id, params, cx)
843 {
844 Ok(()) => {}
845 Err(e) => {
846 log::error!(
847 "Failed to register server capabilities: {e:#}"
848 );
849 }
850 };
851 }
852 })
853 .ok();
854 Ok(())
855 }
856 }
857 })
858 .detach();
859
860 language_server
861 .on_request::<lsp::request::UnregisterCapability, _, _>({
862 let lsp_store = lsp_store.clone();
863 move |params, cx| {
864 let lsp_store = lsp_store.clone();
865 let mut cx = cx.clone();
866 async move {
867 lsp_store
868 .update(&mut cx, |lsp_store, cx| {
869 if lsp_store.as_local().is_some() {
870 match lsp_store
871 .unregister_server_capabilities(server_id, params, cx)
872 {
873 Ok(()) => {}
874 Err(e) => {
875 log::error!(
876 "Failed to unregister server capabilities: {e:#}"
877 );
878 }
879 }
880 }
881 })
882 .ok();
883 Ok(())
884 }
885 }
886 })
887 .detach();
888
889 language_server
890 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
891 let this = lsp_store.clone();
892 move |params, cx| {
893 let mut cx = cx.clone();
894 let this = this.clone();
895 async move {
896 LocalLspStore::on_lsp_workspace_edit(
897 this.clone(),
898 params,
899 server_id,
900 &mut cx,
901 )
902 .await
903 }
904 }
905 })
906 .detach();
907
908 language_server
909 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
910 let lsp_store = lsp_store.clone();
911 let request_id = Arc::new(AtomicUsize::new(0));
912 move |(), cx| {
913 let lsp_store = lsp_store.clone();
914 let request_id = request_id.clone();
915 let mut cx = cx.clone();
916 async move {
917 lsp_store
918 .update(&mut cx, |lsp_store, cx| {
919 let request_id =
920 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
921 cx.emit(LspStoreEvent::RefreshInlayHints {
922 server_id,
923 request_id,
924 });
925 lsp_store
926 .downstream_client
927 .as_ref()
928 .map(|(client, project_id)| {
929 client.send(proto::RefreshInlayHints {
930 project_id: *project_id,
931 server_id: server_id.to_proto(),
932 request_id: request_id.map(|id| id as u64),
933 })
934 })
935 })?
936 .transpose()?;
937 Ok(())
938 }
939 }
940 })
941 .detach();
942
943 language_server
944 .on_request::<lsp::request::CodeLensRefresh, _, _>({
945 let this = lsp_store.clone();
946 move |(), cx| {
947 let this = this.clone();
948 let mut cx = cx.clone();
949 async move {
950 this.update(&mut cx, |this, cx| {
951 cx.emit(LspStoreEvent::RefreshCodeLens);
952 this.downstream_client.as_ref().map(|(client, project_id)| {
953 client.send(proto::RefreshCodeLens {
954 project_id: *project_id,
955 })
956 })
957 })?
958 .transpose()?;
959 Ok(())
960 }
961 }
962 })
963 .detach();
964
965 language_server
966 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
967 let this = lsp_store.clone();
968 move |(), cx| {
969 let this = this.clone();
970 let mut cx = cx.clone();
971 async move {
972 this.update(&mut cx, |lsp_store, _| {
973 lsp_store.pull_workspace_diagnostics(server_id);
974 lsp_store
975 .downstream_client
976 .as_ref()
977 .map(|(client, project_id)| {
978 client.send(proto::PullWorkspaceDiagnostics {
979 project_id: *project_id,
980 server_id: server_id.to_proto(),
981 })
982 })
983 })?
984 .transpose()?;
985 Ok(())
986 }
987 }
988 })
989 .detach();
990
991 language_server
992 .on_request::<lsp::request::ShowMessageRequest, _, _>({
993 let this = lsp_store.clone();
994 let name = name.to_string();
995 move |params, cx| {
996 let this = this.clone();
997 let name = name.to_string();
998 let mut cx = cx.clone();
999 async move {
1000 let actions = params.actions.unwrap_or_default();
1001 let (tx, rx) = smol::channel::bounded(1);
1002 let request = LanguageServerPromptRequest {
1003 level: match params.typ {
1004 lsp::MessageType::ERROR => PromptLevel::Critical,
1005 lsp::MessageType::WARNING => PromptLevel::Warning,
1006 _ => PromptLevel::Info,
1007 },
1008 message: params.message,
1009 actions,
1010 response_channel: tx,
1011 lsp_name: name.clone(),
1012 };
1013
1014 let did_update = this
1015 .update(&mut cx, |_, cx| {
1016 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1017 })
1018 .is_ok();
1019 if did_update {
1020 let response = rx.recv().await.ok();
1021 Ok(response)
1022 } else {
1023 Ok(None)
1024 }
1025 }
1026 }
1027 })
1028 .detach();
1029 language_server
1030 .on_notification::<lsp::notification::ShowMessage, _>({
1031 let this = lsp_store.clone();
1032 let name = name.to_string();
1033 move |params, cx| {
1034 let this = this.clone();
1035 let name = name.to_string();
1036 let mut cx = cx.clone();
1037
1038 let (tx, _) = smol::channel::bounded(1);
1039 let request = LanguageServerPromptRequest {
1040 level: match params.typ {
1041 lsp::MessageType::ERROR => PromptLevel::Critical,
1042 lsp::MessageType::WARNING => PromptLevel::Warning,
1043 _ => PromptLevel::Info,
1044 },
1045 message: params.message,
1046 actions: vec![],
1047 response_channel: tx,
1048 lsp_name: name,
1049 };
1050
1051 let _ = this.update(&mut cx, |_, cx| {
1052 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1053 });
1054 }
1055 })
1056 .detach();
1057
1058 let disk_based_diagnostics_progress_token =
1059 adapter.disk_based_diagnostics_progress_token.clone();
1060
1061 language_server
1062 .on_notification::<lsp::notification::Progress, _>({
1063 let this = lsp_store.clone();
1064 move |params, cx| {
1065 if let Some(this) = this.upgrade() {
1066 this.update(cx, |this, cx| {
1067 this.on_lsp_progress(
1068 params,
1069 server_id,
1070 disk_based_diagnostics_progress_token.clone(),
1071 cx,
1072 );
1073 })
1074 .ok();
1075 }
1076 }
1077 })
1078 .detach();
1079
1080 language_server
1081 .on_notification::<lsp::notification::LogMessage, _>({
1082 let this = lsp_store.clone();
1083 move |params, cx| {
1084 if let Some(this) = this.upgrade() {
1085 this.update(cx, |_, cx| {
1086 cx.emit(LspStoreEvent::LanguageServerLog(
1087 server_id,
1088 LanguageServerLogType::Log(params.typ),
1089 params.message,
1090 ));
1091 })
1092 .ok();
1093 }
1094 }
1095 })
1096 .detach();
1097
1098 language_server
1099 .on_notification::<lsp::notification::LogTrace, _>({
1100 let this = lsp_store.clone();
1101 move |params, cx| {
1102 let mut cx = cx.clone();
1103 if let Some(this) = this.upgrade() {
1104 this.update(&mut cx, |_, cx| {
1105 cx.emit(LspStoreEvent::LanguageServerLog(
1106 server_id,
1107 LanguageServerLogType::Trace {
1108 verbose_info: params.verbose,
1109 },
1110 params.message,
1111 ));
1112 })
1113 .ok();
1114 }
1115 }
1116 })
1117 .detach();
1118
1119 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1120 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1121 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1122 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1123 }
1124
1125 fn shutdown_language_servers_on_quit(
1126 &mut self,
1127 _: &mut Context<LspStore>,
1128 ) -> impl Future<Output = ()> + use<> {
1129 let shutdown_futures = self
1130 .language_servers
1131 .drain()
1132 .map(|(_, server_state)| Self::shutdown_server(server_state))
1133 .collect::<Vec<_>>();
1134
1135 async move {
1136 join_all(shutdown_futures).await;
1137 }
1138 }
1139
1140 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1141 match server_state {
1142 LanguageServerState::Running { server, .. } => {
1143 if let Some(shutdown) = server.shutdown() {
1144 shutdown.await;
1145 }
1146 }
1147 LanguageServerState::Starting { startup, .. } => {
1148 if let Some(server) = startup.await
1149 && let Some(shutdown) = server.shutdown()
1150 {
1151 shutdown.await;
1152 }
1153 }
1154 }
1155 Ok(())
1156 }
1157
1158 fn language_servers_for_worktree(
1159 &self,
1160 worktree_id: WorktreeId,
1161 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1162 self.language_server_ids
1163 .iter()
1164 .filter_map(move |(seed, state)| {
1165 if seed.worktree_id != worktree_id {
1166 return None;
1167 }
1168
1169 if let Some(LanguageServerState::Running { server, .. }) =
1170 self.language_servers.get(&state.id)
1171 {
1172 Some(server)
1173 } else {
1174 None
1175 }
1176 })
1177 }
1178
1179 fn language_server_ids_for_project_path(
1180 &self,
1181 project_path: ProjectPath,
1182 language: &Language,
1183 cx: &mut App,
1184 ) -> Vec<LanguageServerId> {
1185 let Some(worktree) = self
1186 .worktree_store
1187 .read(cx)
1188 .worktree_for_id(project_path.worktree_id, cx)
1189 else {
1190 return Vec::new();
1191 };
1192 let delegate: Arc<dyn ManifestDelegate> =
1193 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1194
1195 self.lsp_tree
1196 .get(
1197 project_path,
1198 language.name(),
1199 language.manifest(),
1200 &delegate,
1201 cx,
1202 )
1203 .collect::<Vec<_>>()
1204 }
1205
1206 fn language_server_ids_for_buffer(
1207 &self,
1208 buffer: &Buffer,
1209 cx: &mut App,
1210 ) -> Vec<LanguageServerId> {
1211 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1212 let worktree_id = file.worktree_id(cx);
1213
1214 let path: Arc<RelPath> = file
1215 .path()
1216 .parent()
1217 .map(Arc::from)
1218 .unwrap_or_else(|| file.path().clone());
1219 let worktree_path = ProjectPath { worktree_id, path };
1220 self.language_server_ids_for_project_path(worktree_path, language, cx)
1221 } else {
1222 Vec::new()
1223 }
1224 }
1225
1226 fn language_servers_for_buffer<'a>(
1227 &'a self,
1228 buffer: &'a Buffer,
1229 cx: &'a mut App,
1230 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1231 self.language_server_ids_for_buffer(buffer, cx)
1232 .into_iter()
1233 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1234 LanguageServerState::Running {
1235 adapter, server, ..
1236 } => Some((adapter, server)),
1237 _ => None,
1238 })
1239 }
1240
1241 async fn execute_code_action_kind_locally(
1242 lsp_store: WeakEntity<LspStore>,
1243 mut buffers: Vec<Entity<Buffer>>,
1244 kind: CodeActionKind,
1245 push_to_history: bool,
1246 cx: &mut AsyncApp,
1247 ) -> anyhow::Result<ProjectTransaction> {
1248 // Do not allow multiple concurrent code actions requests for the
1249 // same buffer.
1250 lsp_store.update(cx, |this, cx| {
1251 let this = this.as_local_mut().unwrap();
1252 buffers.retain(|buffer| {
1253 this.buffers_being_formatted
1254 .insert(buffer.read(cx).remote_id())
1255 });
1256 })?;
1257 let _cleanup = defer({
1258 let this = lsp_store.clone();
1259 let mut cx = cx.clone();
1260 let buffers = &buffers;
1261 move || {
1262 this.update(&mut cx, |this, cx| {
1263 let this = this.as_local_mut().unwrap();
1264 for buffer in buffers {
1265 this.buffers_being_formatted
1266 .remove(&buffer.read(cx).remote_id());
1267 }
1268 })
1269 .ok();
1270 }
1271 });
1272 let mut project_transaction = ProjectTransaction::default();
1273
1274 for buffer in &buffers {
1275 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1276 buffer.update(cx, |buffer, cx| {
1277 lsp_store
1278 .as_local()
1279 .unwrap()
1280 .language_servers_for_buffer(buffer, cx)
1281 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1282 .collect::<Vec<_>>()
1283 })
1284 })?;
1285 for (_, language_server) in adapters_and_servers.iter() {
1286 let actions = Self::get_server_code_actions_from_action_kinds(
1287 &lsp_store,
1288 language_server.server_id(),
1289 vec![kind.clone()],
1290 buffer,
1291 cx,
1292 )
1293 .await?;
1294 Self::execute_code_actions_on_server(
1295 &lsp_store,
1296 language_server,
1297 actions,
1298 push_to_history,
1299 &mut project_transaction,
1300 cx,
1301 )
1302 .await?;
1303 }
1304 }
1305 Ok(project_transaction)
1306 }
1307
1308 async fn format_locally(
1309 lsp_store: WeakEntity<LspStore>,
1310 mut buffers: Vec<FormattableBuffer>,
1311 push_to_history: bool,
1312 trigger: FormatTrigger,
1313 logger: zlog::Logger,
1314 cx: &mut AsyncApp,
1315 ) -> anyhow::Result<ProjectTransaction> {
1316 // Do not allow multiple concurrent formatting requests for the
1317 // same buffer.
1318 lsp_store.update(cx, |this, cx| {
1319 let this = this.as_local_mut().unwrap();
1320 buffers.retain(|buffer| {
1321 this.buffers_being_formatted
1322 .insert(buffer.handle.read(cx).remote_id())
1323 });
1324 })?;
1325
1326 let _cleanup = defer({
1327 let this = lsp_store.clone();
1328 let mut cx = cx.clone();
1329 let buffers = &buffers;
1330 move || {
1331 this.update(&mut cx, |this, cx| {
1332 let this = this.as_local_mut().unwrap();
1333 for buffer in buffers {
1334 this.buffers_being_formatted
1335 .remove(&buffer.handle.read(cx).remote_id());
1336 }
1337 })
1338 .ok();
1339 }
1340 });
1341
1342 let mut project_transaction = ProjectTransaction::default();
1343
1344 for buffer in &buffers {
1345 zlog::debug!(
1346 logger =>
1347 "formatting buffer '{:?}'",
1348 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1349 );
1350 // Create an empty transaction to hold all of the formatting edits.
1351 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1352 // ensure no transactions created while formatting are
1353 // grouped with the previous transaction in the history
1354 // based on the transaction group interval
1355 buffer.finalize_last_transaction();
1356 buffer
1357 .start_transaction()
1358 .context("transaction already open")?;
1359 buffer.end_transaction(cx);
1360 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1361 buffer.finalize_last_transaction();
1362 anyhow::Ok(transaction_id)
1363 })??;
1364
1365 let result = Self::format_buffer_locally(
1366 lsp_store.clone(),
1367 buffer,
1368 formatting_transaction_id,
1369 trigger,
1370 logger,
1371 cx,
1372 )
1373 .await;
1374
1375 buffer.handle.update(cx, |buffer, cx| {
1376 let Some(formatting_transaction) =
1377 buffer.get_transaction(formatting_transaction_id).cloned()
1378 else {
1379 zlog::warn!(logger => "no formatting transaction");
1380 return;
1381 };
1382 if formatting_transaction.edit_ids.is_empty() {
1383 zlog::debug!(logger => "no changes made while formatting");
1384 buffer.forget_transaction(formatting_transaction_id);
1385 return;
1386 }
1387 if !push_to_history {
1388 zlog::trace!(logger => "forgetting format transaction");
1389 buffer.forget_transaction(formatting_transaction.id);
1390 }
1391 project_transaction
1392 .0
1393 .insert(cx.entity(), formatting_transaction);
1394 })?;
1395
1396 result?;
1397 }
1398
1399 Ok(project_transaction)
1400 }
1401
1402 async fn format_buffer_locally(
1403 lsp_store: WeakEntity<LspStore>,
1404 buffer: &FormattableBuffer,
1405 formatting_transaction_id: clock::Lamport,
1406 trigger: FormatTrigger,
1407 logger: zlog::Logger,
1408 cx: &mut AsyncApp,
1409 ) -> Result<()> {
1410 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1411 buffer.handle.update(cx, |buffer, cx| {
1412 let adapters_and_servers = lsp_store
1413 .as_local()
1414 .unwrap()
1415 .language_servers_for_buffer(buffer, cx)
1416 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1417 .collect::<Vec<_>>();
1418 let settings =
1419 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1420 .into_owned();
1421 (adapters_and_servers, settings)
1422 })
1423 })?;
1424
1425 /// Apply edits to the buffer that will become part of the formatting transaction.
1426 /// Fails if the buffer has been edited since the start of that transaction.
1427 fn extend_formatting_transaction(
1428 buffer: &FormattableBuffer,
1429 formatting_transaction_id: text::TransactionId,
1430 cx: &mut AsyncApp,
1431 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1432 ) -> anyhow::Result<()> {
1433 buffer.handle.update(cx, |buffer, cx| {
1434 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1435 if last_transaction_id != Some(formatting_transaction_id) {
1436 anyhow::bail!("Buffer edited while formatting. Aborting")
1437 }
1438 buffer.start_transaction();
1439 operation(buffer, cx);
1440 if let Some(transaction_id) = buffer.end_transaction(cx) {
1441 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1442 }
1443 Ok(())
1444 })?
1445 }
1446
1447 // handle whitespace formatting
1448 if settings.remove_trailing_whitespace_on_save {
1449 zlog::trace!(logger => "removing trailing whitespace");
1450 let diff = buffer
1451 .handle
1452 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1453 .await;
1454 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1455 buffer.apply_diff(diff, cx);
1456 })?;
1457 }
1458
1459 if settings.ensure_final_newline_on_save {
1460 zlog::trace!(logger => "ensuring final newline");
1461 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1462 buffer.ensure_final_newline(cx);
1463 })?;
1464 }
1465
1466 // Formatter for `code_actions_on_format` that runs before
1467 // the rest of the formatters
1468 let mut code_actions_on_format_formatters = None;
1469 let should_run_code_actions_on_format = !matches!(
1470 (trigger, &settings.format_on_save),
1471 (FormatTrigger::Save, &FormatOnSave::Off)
1472 );
1473 if should_run_code_actions_on_format {
1474 let have_code_actions_to_run_on_format = settings
1475 .code_actions_on_format
1476 .values()
1477 .any(|enabled| *enabled);
1478 if have_code_actions_to_run_on_format {
1479 zlog::trace!(logger => "going to run code actions on format");
1480 code_actions_on_format_formatters = Some(
1481 settings
1482 .code_actions_on_format
1483 .iter()
1484 .filter_map(|(action, enabled)| enabled.then_some(action))
1485 .cloned()
1486 .map(Formatter::CodeAction)
1487 .collect::<Vec<_>>(),
1488 );
1489 }
1490 }
1491
1492 let formatters = match (trigger, &settings.format_on_save) {
1493 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1494 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1495 settings.formatter.as_ref()
1496 }
1497 };
1498
1499 let formatters = code_actions_on_format_formatters
1500 .iter()
1501 .flatten()
1502 .chain(formatters);
1503
1504 for formatter in formatters {
1505 let formatter = if formatter == &Formatter::Auto {
1506 if settings.prettier.allowed {
1507 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1508 &Formatter::Prettier
1509 } else {
1510 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1511 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1512 }
1513 } else {
1514 formatter
1515 };
1516 match formatter {
1517 Formatter::Auto => unreachable!("Auto resolved above"),
1518 Formatter::Prettier => {
1519 let logger = zlog::scoped!(logger => "prettier");
1520 zlog::trace!(logger => "formatting");
1521 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1522
1523 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1524 lsp_store.prettier_store().unwrap().downgrade()
1525 })?;
1526 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1527 .await
1528 .transpose()?;
1529 let Some(diff) = diff else {
1530 zlog::trace!(logger => "No changes");
1531 continue;
1532 };
1533
1534 extend_formatting_transaction(
1535 buffer,
1536 formatting_transaction_id,
1537 cx,
1538 |buffer, cx| {
1539 buffer.apply_diff(diff, cx);
1540 },
1541 )?;
1542 }
1543 Formatter::External { command, arguments } => {
1544 let logger = zlog::scoped!(logger => "command");
1545 zlog::trace!(logger => "formatting");
1546 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1547
1548 let diff = Self::format_via_external_command(
1549 buffer,
1550 command.as_ref(),
1551 arguments.as_deref(),
1552 cx,
1553 )
1554 .await
1555 .with_context(|| {
1556 format!("Failed to format buffer via external command: {}", command)
1557 })?;
1558 let Some(diff) = diff else {
1559 zlog::trace!(logger => "No changes");
1560 continue;
1561 };
1562
1563 extend_formatting_transaction(
1564 buffer,
1565 formatting_transaction_id,
1566 cx,
1567 |buffer, cx| {
1568 buffer.apply_diff(diff, cx);
1569 },
1570 )?;
1571 }
1572 Formatter::LanguageServer(specifier) => {
1573 let logger = zlog::scoped!(logger => "language-server");
1574 zlog::trace!(logger => "formatting");
1575 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1576
1577 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1578 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1579 continue;
1580 };
1581
1582 let language_server = match specifier {
1583 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1584 adapters_and_servers.iter().find_map(|(adapter, server)| {
1585 if adapter.name.0.as_ref() == name {
1586 Some(server.clone())
1587 } else {
1588 None
1589 }
1590 })
1591 }
1592 settings::LanguageServerFormatterSpecifier::Current => {
1593 adapters_and_servers.first().map(|e| e.1.clone())
1594 }
1595 };
1596
1597 let Some(language_server) = language_server else {
1598 log::debug!(
1599 "No language server found to format buffer '{:?}'. Skipping",
1600 buffer_path_abs.as_path().to_string_lossy()
1601 );
1602 continue;
1603 };
1604
1605 zlog::trace!(
1606 logger =>
1607 "Formatting buffer '{:?}' using language server '{:?}'",
1608 buffer_path_abs.as_path().to_string_lossy(),
1609 language_server.name()
1610 );
1611
1612 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1613 zlog::trace!(logger => "formatting ranges");
1614 Self::format_ranges_via_lsp(
1615 &lsp_store,
1616 &buffer.handle,
1617 ranges,
1618 buffer_path_abs,
1619 &language_server,
1620 &settings,
1621 cx,
1622 )
1623 .await
1624 .context("Failed to format ranges via language server")?
1625 } else {
1626 zlog::trace!(logger => "formatting full");
1627 Self::format_via_lsp(
1628 &lsp_store,
1629 &buffer.handle,
1630 buffer_path_abs,
1631 &language_server,
1632 &settings,
1633 cx,
1634 )
1635 .await
1636 .context("failed to format via language server")?
1637 };
1638
1639 if edits.is_empty() {
1640 zlog::trace!(logger => "No changes");
1641 continue;
1642 }
1643 extend_formatting_transaction(
1644 buffer,
1645 formatting_transaction_id,
1646 cx,
1647 |buffer, cx| {
1648 buffer.edit(edits, None, cx);
1649 },
1650 )?;
1651 }
1652 Formatter::CodeAction(code_action_name) => {
1653 let logger = zlog::scoped!(logger => "code-actions");
1654 zlog::trace!(logger => "formatting");
1655 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1656
1657 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1658 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1659 continue;
1660 };
1661
1662 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1663 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1664
1665 let mut actions_and_servers = Vec::new();
1666
1667 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1668 let actions_result = Self::get_server_code_actions_from_action_kinds(
1669 &lsp_store,
1670 language_server.server_id(),
1671 vec![code_action_kind.clone()],
1672 &buffer.handle,
1673 cx,
1674 )
1675 .await
1676 .with_context(|| {
1677 format!(
1678 "Failed to resolve code action {:?} with language server {}",
1679 code_action_kind,
1680 language_server.name()
1681 )
1682 });
1683 let Ok(actions) = actions_result else {
1684 // note: it may be better to set result to the error and break formatters here
1685 // but for now we try to execute the actions that we can resolve and skip the rest
1686 zlog::error!(
1687 logger =>
1688 "Failed to resolve code action {:?} with language server {}",
1689 code_action_kind,
1690 language_server.name()
1691 );
1692 continue;
1693 };
1694 for action in actions {
1695 actions_and_servers.push((action, index));
1696 }
1697 }
1698
1699 if actions_and_servers.is_empty() {
1700 zlog::warn!(logger => "No code actions were resolved, continuing");
1701 continue;
1702 }
1703
1704 'actions: for (mut action, server_index) in actions_and_servers {
1705 let server = &adapters_and_servers[server_index].1;
1706
1707 let describe_code_action = |action: &CodeAction| {
1708 format!(
1709 "code action '{}' with title \"{}\" on server {}",
1710 action
1711 .lsp_action
1712 .action_kind()
1713 .unwrap_or("unknown".into())
1714 .as_str(),
1715 action.lsp_action.title(),
1716 server.name(),
1717 )
1718 };
1719
1720 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1721
1722 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1723 zlog::error!(
1724 logger =>
1725 "Failed to resolve {}. Error: {}",
1726 describe_code_action(&action),
1727 err
1728 );
1729 continue;
1730 }
1731
1732 if let Some(edit) = action.lsp_action.edit().cloned() {
1733 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1734 // but filters out and logs warnings for code actions that require unreasonably
1735 // difficult handling on our part, such as:
1736 // - applying edits that call commands
1737 // which can result in arbitrary workspace edits being sent from the server that
1738 // have no way of being tied back to the command that initiated them (i.e. we
1739 // can't know which edits are part of the format request, or if the server is done sending
1740 // actions in response to the command)
1741 // - actions that create/delete/modify/rename files other than the one we are formatting
1742 // as we then would need to handle such changes correctly in the local history as well
1743 // as the remote history through the ProjectTransaction
1744 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1745 // Supporting these actions is not impossible, but not supported as of yet.
1746 if edit.changes.is_none() && edit.document_changes.is_none() {
1747 zlog::trace!(
1748 logger =>
1749 "No changes for code action. Skipping {}",
1750 describe_code_action(&action),
1751 );
1752 continue;
1753 }
1754
1755 let mut operations = Vec::new();
1756 if let Some(document_changes) = edit.document_changes {
1757 match document_changes {
1758 lsp::DocumentChanges::Edits(edits) => operations.extend(
1759 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1760 ),
1761 lsp::DocumentChanges::Operations(ops) => operations = ops,
1762 }
1763 } else if let Some(changes) = edit.changes {
1764 operations.extend(changes.into_iter().map(|(uri, edits)| {
1765 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1766 text_document:
1767 lsp::OptionalVersionedTextDocumentIdentifier {
1768 uri,
1769 version: None,
1770 },
1771 edits: edits.into_iter().map(Edit::Plain).collect(),
1772 })
1773 }));
1774 }
1775
1776 let mut edits = Vec::with_capacity(operations.len());
1777
1778 if operations.is_empty() {
1779 zlog::trace!(
1780 logger =>
1781 "No changes for code action. Skipping {}",
1782 describe_code_action(&action),
1783 );
1784 continue;
1785 }
1786 for operation in operations {
1787 let op = match operation {
1788 lsp::DocumentChangeOperation::Edit(op) => op,
1789 lsp::DocumentChangeOperation::Op(_) => {
1790 zlog::warn!(
1791 logger =>
1792 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1793 describe_code_action(&action),
1794 );
1795 continue 'actions;
1796 }
1797 };
1798 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1799 zlog::warn!(
1800 logger =>
1801 "Failed to convert URI '{:?}' to file path. Skipping {}",
1802 &op.text_document.uri,
1803 describe_code_action(&action),
1804 );
1805 continue 'actions;
1806 };
1807 if &file_path != buffer_path_abs {
1808 zlog::warn!(
1809 logger =>
1810 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1811 file_path,
1812 buffer_path_abs,
1813 describe_code_action(&action),
1814 );
1815 continue 'actions;
1816 }
1817
1818 let mut lsp_edits = Vec::new();
1819 for edit in op.edits {
1820 match edit {
1821 Edit::Plain(edit) => {
1822 if !lsp_edits.contains(&edit) {
1823 lsp_edits.push(edit);
1824 }
1825 }
1826 Edit::Annotated(edit) => {
1827 if !lsp_edits.contains(&edit.text_edit) {
1828 lsp_edits.push(edit.text_edit);
1829 }
1830 }
1831 Edit::Snippet(_) => {
1832 zlog::warn!(
1833 logger =>
1834 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1835 describe_code_action(&action),
1836 );
1837 continue 'actions;
1838 }
1839 }
1840 }
1841 let edits_result = lsp_store
1842 .update(cx, |lsp_store, cx| {
1843 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1844 &buffer.handle,
1845 lsp_edits,
1846 server.server_id(),
1847 op.text_document.version,
1848 cx,
1849 )
1850 })?
1851 .await;
1852 let Ok(resolved_edits) = edits_result else {
1853 zlog::warn!(
1854 logger =>
1855 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1856 buffer_path_abs.as_path(),
1857 describe_code_action(&action),
1858 );
1859 continue 'actions;
1860 };
1861 edits.extend(resolved_edits);
1862 }
1863
1864 if edits.is_empty() {
1865 zlog::warn!(logger => "No edits resolved from LSP");
1866 continue;
1867 }
1868
1869 extend_formatting_transaction(
1870 buffer,
1871 formatting_transaction_id,
1872 cx,
1873 |buffer, cx| {
1874 zlog::info!(
1875 "Applying edits {edits:?}. Content: {:?}",
1876 buffer.text()
1877 );
1878 buffer.edit(edits, None, cx);
1879 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1880 },
1881 )?;
1882 }
1883
1884 if let Some(command) = action.lsp_action.command() {
1885 zlog::warn!(
1886 logger =>
1887 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1888 &command.command,
1889 );
1890
1891 // bail early if command is invalid
1892 let server_capabilities = server.capabilities();
1893 let available_commands = server_capabilities
1894 .execute_command_provider
1895 .as_ref()
1896 .map(|options| options.commands.as_slice())
1897 .unwrap_or_default();
1898 if !available_commands.contains(&command.command) {
1899 zlog::warn!(
1900 logger =>
1901 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1902 command.command,
1903 server.name(),
1904 );
1905 continue;
1906 }
1907
1908 // noop so we just ensure buffer hasn't been edited since resolving code actions
1909 extend_formatting_transaction(
1910 buffer,
1911 formatting_transaction_id,
1912 cx,
1913 |_, _| {},
1914 )?;
1915 zlog::info!(logger => "Executing command {}", &command.command);
1916
1917 lsp_store.update(cx, |this, _| {
1918 this.as_local_mut()
1919 .unwrap()
1920 .last_workspace_edits_by_language_server
1921 .remove(&server.server_id());
1922 })?;
1923
1924 let execute_command_result = server
1925 .request::<lsp::request::ExecuteCommand>(
1926 lsp::ExecuteCommandParams {
1927 command: command.command.clone(),
1928 arguments: command.arguments.clone().unwrap_or_default(),
1929 ..Default::default()
1930 },
1931 )
1932 .await
1933 .into_response();
1934
1935 if execute_command_result.is_err() {
1936 zlog::error!(
1937 logger =>
1938 "Failed to execute command '{}' as part of {}",
1939 &command.command,
1940 describe_code_action(&action),
1941 );
1942 continue 'actions;
1943 }
1944
1945 let mut project_transaction_command =
1946 lsp_store.update(cx, |this, _| {
1947 this.as_local_mut()
1948 .unwrap()
1949 .last_workspace_edits_by_language_server
1950 .remove(&server.server_id())
1951 .unwrap_or_default()
1952 })?;
1953
1954 if let Some(transaction) =
1955 project_transaction_command.0.remove(&buffer.handle)
1956 {
1957 zlog::trace!(
1958 logger =>
1959 "Successfully captured {} edits that resulted from command {}",
1960 transaction.edit_ids.len(),
1961 &command.command,
1962 );
1963 let transaction_id_project_transaction = transaction.id;
1964 buffer.handle.update(cx, |buffer, _| {
1965 // it may have been removed from history if push_to_history was
1966 // false in deserialize_workspace_edit. If so push it so we
1967 // can merge it with the format transaction
1968 // and pop the combined transaction off the history stack
1969 // later if push_to_history is false
1970 if buffer.get_transaction(transaction.id).is_none() {
1971 buffer.push_transaction(transaction, Instant::now());
1972 }
1973 buffer.merge_transactions(
1974 transaction_id_project_transaction,
1975 formatting_transaction_id,
1976 );
1977 })?;
1978 }
1979
1980 if !project_transaction_command.0.is_empty() {
1981 let mut extra_buffers = String::new();
1982 for buffer in project_transaction_command.0.keys() {
1983 buffer
1984 .read_with(cx, |b, cx| {
1985 if let Some(path) = b.project_path(cx) {
1986 if !extra_buffers.is_empty() {
1987 extra_buffers.push_str(", ");
1988 }
1989 extra_buffers.push_str(path.path.as_unix_str());
1990 }
1991 })
1992 .ok();
1993 }
1994 zlog::warn!(
1995 logger =>
1996 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1997 &command.command,
1998 extra_buffers,
1999 );
2000 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2001 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2002 // add it so it's included, and merge it into the format transaction when its created later
2003 }
2004 }
2005 }
2006 }
2007 }
2008 }
2009
2010 Ok(())
2011 }
2012
2013 pub async fn format_ranges_via_lsp(
2014 this: &WeakEntity<LspStore>,
2015 buffer_handle: &Entity<Buffer>,
2016 ranges: &[Range<Anchor>],
2017 abs_path: &Path,
2018 language_server: &Arc<LanguageServer>,
2019 settings: &LanguageSettings,
2020 cx: &mut AsyncApp,
2021 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2022 let capabilities = &language_server.capabilities();
2023 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2024 if range_formatting_provider == Some(&OneOf::Left(false)) {
2025 anyhow::bail!(
2026 "{} language server does not support range formatting",
2027 language_server.name()
2028 );
2029 }
2030
2031 let uri = file_path_to_lsp_url(abs_path)?;
2032 let text_document = lsp::TextDocumentIdentifier::new(uri);
2033
2034 let lsp_edits = {
2035 let mut lsp_ranges = Vec::new();
2036 this.update(cx, |_this, cx| {
2037 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2038 // not have been sent to the language server. This seems like a fairly systemic
2039 // issue, though, the resolution probably is not specific to formatting.
2040 //
2041 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2042 // LSP.
2043 let snapshot = buffer_handle.read(cx).snapshot();
2044 for range in ranges {
2045 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2046 }
2047 anyhow::Ok(())
2048 })??;
2049
2050 let mut edits = None;
2051 for range in lsp_ranges {
2052 if let Some(mut edit) = language_server
2053 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2054 text_document: text_document.clone(),
2055 range,
2056 options: lsp_command::lsp_formatting_options(settings),
2057 work_done_progress_params: Default::default(),
2058 })
2059 .await
2060 .into_response()?
2061 {
2062 edits.get_or_insert_with(Vec::new).append(&mut edit);
2063 }
2064 }
2065 edits
2066 };
2067
2068 if let Some(lsp_edits) = lsp_edits {
2069 this.update(cx, |this, cx| {
2070 this.as_local_mut().unwrap().edits_from_lsp(
2071 buffer_handle,
2072 lsp_edits,
2073 language_server.server_id(),
2074 None,
2075 cx,
2076 )
2077 })?
2078 .await
2079 } else {
2080 Ok(Vec::with_capacity(0))
2081 }
2082 }
2083
2084 async fn format_via_lsp(
2085 this: &WeakEntity<LspStore>,
2086 buffer: &Entity<Buffer>,
2087 abs_path: &Path,
2088 language_server: &Arc<LanguageServer>,
2089 settings: &LanguageSettings,
2090 cx: &mut AsyncApp,
2091 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2092 let logger = zlog::scoped!("lsp_format");
2093 zlog::debug!(logger => "Formatting via LSP");
2094
2095 let uri = file_path_to_lsp_url(abs_path)?;
2096 let text_document = lsp::TextDocumentIdentifier::new(uri);
2097 let capabilities = &language_server.capabilities();
2098
2099 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2100 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2101
2102 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2103 let _timer = zlog::time!(logger => "format-full");
2104 language_server
2105 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2106 text_document,
2107 options: lsp_command::lsp_formatting_options(settings),
2108 work_done_progress_params: Default::default(),
2109 })
2110 .await
2111 .into_response()?
2112 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2113 let _timer = zlog::time!(logger => "format-range");
2114 let buffer_start = lsp::Position::new(0, 0);
2115 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2116 language_server
2117 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2118 text_document: text_document.clone(),
2119 range: lsp::Range::new(buffer_start, buffer_end),
2120 options: lsp_command::lsp_formatting_options(settings),
2121 work_done_progress_params: Default::default(),
2122 })
2123 .await
2124 .into_response()?
2125 } else {
2126 None
2127 };
2128
2129 if let Some(lsp_edits) = lsp_edits {
2130 this.update(cx, |this, cx| {
2131 this.as_local_mut().unwrap().edits_from_lsp(
2132 buffer,
2133 lsp_edits,
2134 language_server.server_id(),
2135 None,
2136 cx,
2137 )
2138 })?
2139 .await
2140 } else {
2141 Ok(Vec::with_capacity(0))
2142 }
2143 }
2144
2145 async fn format_via_external_command(
2146 buffer: &FormattableBuffer,
2147 command: &str,
2148 arguments: Option<&[String]>,
2149 cx: &mut AsyncApp,
2150 ) -> Result<Option<Diff>> {
2151 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2152 let file = File::from_dyn(buffer.file())?;
2153 let worktree = file.worktree.read(cx);
2154 let mut worktree_path = worktree.abs_path().to_path_buf();
2155 if worktree.root_entry()?.is_file() {
2156 worktree_path.pop();
2157 }
2158 Some(worktree_path)
2159 })?;
2160
2161 let mut child = util::command::new_smol_command(command);
2162
2163 if let Some(buffer_env) = buffer.env.as_ref() {
2164 child.envs(buffer_env);
2165 }
2166
2167 if let Some(working_dir_path) = working_dir_path {
2168 child.current_dir(working_dir_path);
2169 }
2170
2171 if let Some(arguments) = arguments {
2172 child.args(arguments.iter().map(|arg| {
2173 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2174 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2175 } else {
2176 arg.replace("{buffer_path}", "Untitled")
2177 }
2178 }));
2179 }
2180
2181 let mut child = child
2182 .stdin(smol::process::Stdio::piped())
2183 .stdout(smol::process::Stdio::piped())
2184 .stderr(smol::process::Stdio::piped())
2185 .spawn()?;
2186
2187 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2188 let text = buffer
2189 .handle
2190 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2191 for chunk in text.chunks() {
2192 stdin.write_all(chunk.as_bytes()).await?;
2193 }
2194 stdin.flush().await?;
2195
2196 let output = child.output().await?;
2197 anyhow::ensure!(
2198 output.status.success(),
2199 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2200 output.status.code(),
2201 String::from_utf8_lossy(&output.stdout),
2202 String::from_utf8_lossy(&output.stderr),
2203 );
2204
2205 let stdout = String::from_utf8(output.stdout)?;
2206 Ok(Some(
2207 buffer
2208 .handle
2209 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2210 .await,
2211 ))
2212 }
2213
2214 async fn try_resolve_code_action(
2215 lang_server: &LanguageServer,
2216 action: &mut CodeAction,
2217 ) -> anyhow::Result<()> {
2218 match &mut action.lsp_action {
2219 LspAction::Action(lsp_action) => {
2220 if !action.resolved
2221 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2222 && lsp_action.data.is_some()
2223 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2224 {
2225 *lsp_action = Box::new(
2226 lang_server
2227 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2228 .await
2229 .into_response()?,
2230 );
2231 }
2232 }
2233 LspAction::CodeLens(lens) => {
2234 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2235 *lens = lang_server
2236 .request::<lsp::request::CodeLensResolve>(lens.clone())
2237 .await
2238 .into_response()?;
2239 }
2240 }
2241 LspAction::Command(_) => {}
2242 }
2243
2244 action.resolved = true;
2245 anyhow::Ok(())
2246 }
2247
2248 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2249 let buffer = buffer_handle.read(cx);
2250
2251 let file = buffer.file().cloned();
2252
2253 let Some(file) = File::from_dyn(file.as_ref()) else {
2254 return;
2255 };
2256 if !file.is_local() {
2257 return;
2258 }
2259 let path = ProjectPath::from_file(file, cx);
2260 let worktree_id = file.worktree_id(cx);
2261 let language = buffer.language().cloned();
2262
2263 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2264 for (server_id, diagnostics) in
2265 diagnostics.get(file.path()).cloned().unwrap_or_default()
2266 {
2267 self.update_buffer_diagnostics(
2268 buffer_handle,
2269 server_id,
2270 None,
2271 None,
2272 None,
2273 Vec::new(),
2274 diagnostics,
2275 cx,
2276 )
2277 .log_err();
2278 }
2279 }
2280 let Some(language) = language else {
2281 return;
2282 };
2283 let Some(snapshot) = self
2284 .worktree_store
2285 .read(cx)
2286 .worktree_for_id(worktree_id, cx)
2287 .map(|worktree| worktree.read(cx).snapshot())
2288 else {
2289 return;
2290 };
2291 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2292
2293 for server_id in
2294 self.lsp_tree
2295 .get(path, language.name(), language.manifest(), &delegate, cx)
2296 {
2297 let server = self
2298 .language_servers
2299 .get(&server_id)
2300 .and_then(|server_state| {
2301 if let LanguageServerState::Running { server, .. } = server_state {
2302 Some(server.clone())
2303 } else {
2304 None
2305 }
2306 });
2307 let server = match server {
2308 Some(server) => server,
2309 None => continue,
2310 };
2311
2312 buffer_handle.update(cx, |buffer, cx| {
2313 buffer.set_completion_triggers(
2314 server.server_id(),
2315 server
2316 .capabilities()
2317 .completion_provider
2318 .as_ref()
2319 .and_then(|provider| {
2320 provider
2321 .trigger_characters
2322 .as_ref()
2323 .map(|characters| characters.iter().cloned().collect())
2324 })
2325 .unwrap_or_default(),
2326 cx,
2327 );
2328 });
2329 }
2330 }
2331
2332 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2333 buffer.update(cx, |buffer, cx| {
2334 let Some(language) = buffer.language() else {
2335 return;
2336 };
2337 let path = ProjectPath {
2338 worktree_id: old_file.worktree_id(cx),
2339 path: old_file.path.clone(),
2340 };
2341 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2342 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2343 buffer.set_completion_triggers(server_id, Default::default(), cx);
2344 }
2345 });
2346 }
2347
2348 fn update_buffer_diagnostics(
2349 &mut self,
2350 buffer: &Entity<Buffer>,
2351 server_id: LanguageServerId,
2352 registration_id: Option<Option<SharedString>>,
2353 result_id: Option<SharedString>,
2354 version: Option<i32>,
2355 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2356 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2357 cx: &mut Context<LspStore>,
2358 ) -> Result<()> {
2359 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2360 Ordering::Equal
2361 .then_with(|| b.is_primary.cmp(&a.is_primary))
2362 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2363 .then_with(|| a.severity.cmp(&b.severity))
2364 .then_with(|| a.message.cmp(&b.message))
2365 }
2366
2367 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2368 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2369 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2370
2371 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2372 Ordering::Equal
2373 .then_with(|| a.range.start.cmp(&b.range.start))
2374 .then_with(|| b.range.end.cmp(&a.range.end))
2375 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2376 });
2377
2378 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2379
2380 let edits_since_save = std::cell::LazyCell::new(|| {
2381 let saved_version = buffer.read(cx).saved_version();
2382 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2383 });
2384
2385 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2386
2387 for (new_diagnostic, entry) in diagnostics {
2388 let start;
2389 let end;
2390 if new_diagnostic && entry.diagnostic.is_disk_based {
2391 // Some diagnostics are based on files on disk instead of buffers'
2392 // current contents. Adjust these diagnostics' ranges to reflect
2393 // any unsaved edits.
2394 // Do not alter the reused ones though, as their coordinates were stored as anchors
2395 // and were properly adjusted on reuse.
2396 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2397 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2398 } else {
2399 start = entry.range.start;
2400 end = entry.range.end;
2401 }
2402
2403 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2404 ..snapshot.clip_point_utf16(end, Bias::Right);
2405
2406 // Expand empty ranges by one codepoint
2407 if range.start == range.end {
2408 // This will be go to the next boundary when being clipped
2409 range.end.column += 1;
2410 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2411 if range.start == range.end && range.end.column > 0 {
2412 range.start.column -= 1;
2413 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2414 }
2415 }
2416
2417 sanitized_diagnostics.push(DiagnosticEntry {
2418 range,
2419 diagnostic: entry.diagnostic,
2420 });
2421 }
2422 drop(edits_since_save);
2423
2424 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2425 buffer.update(cx, |buffer, cx| {
2426 if let Some(registration_id) = registration_id {
2427 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2428 self.buffer_pull_diagnostics_result_ids
2429 .entry(server_id)
2430 .or_default()
2431 .entry(registration_id)
2432 .or_default()
2433 .insert(abs_path, result_id);
2434 }
2435 }
2436
2437 buffer.update_diagnostics(server_id, set, cx)
2438 });
2439
2440 Ok(())
2441 }
2442
2443 fn register_language_server_for_invisible_worktree(
2444 &mut self,
2445 worktree: &Entity<Worktree>,
2446 language_server_id: LanguageServerId,
2447 cx: &mut App,
2448 ) {
2449 let worktree = worktree.read(cx);
2450 let worktree_id = worktree.id();
2451 debug_assert!(!worktree.is_visible());
2452 let Some(mut origin_seed) = self
2453 .language_server_ids
2454 .iter()
2455 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2456 else {
2457 return;
2458 };
2459 origin_seed.worktree_id = worktree_id;
2460 self.language_server_ids
2461 .entry(origin_seed)
2462 .or_insert_with(|| UnifiedLanguageServer {
2463 id: language_server_id,
2464 project_roots: Default::default(),
2465 });
2466 }
2467
2468 fn register_buffer_with_language_servers(
2469 &mut self,
2470 buffer_handle: &Entity<Buffer>,
2471 only_register_servers: HashSet<LanguageServerSelector>,
2472 cx: &mut Context<LspStore>,
2473 ) {
2474 let buffer = buffer_handle.read(cx);
2475 let buffer_id = buffer.remote_id();
2476
2477 let Some(file) = File::from_dyn(buffer.file()) else {
2478 return;
2479 };
2480 if !file.is_local() {
2481 return;
2482 }
2483
2484 let abs_path = file.abs_path(cx);
2485 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2486 return;
2487 };
2488 let initial_snapshot = buffer.text_snapshot();
2489 let worktree_id = file.worktree_id(cx);
2490
2491 let Some(language) = buffer.language().cloned() else {
2492 return;
2493 };
2494 let path: Arc<RelPath> = file
2495 .path()
2496 .parent()
2497 .map(Arc::from)
2498 .unwrap_or_else(|| file.path().clone());
2499 let Some(worktree) = self
2500 .worktree_store
2501 .read(cx)
2502 .worktree_for_id(worktree_id, cx)
2503 else {
2504 return;
2505 };
2506 let language_name = language.name();
2507 let (reused, delegate, servers) = self
2508 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2509 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2510 .unwrap_or_else(|| {
2511 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2512 let delegate: Arc<dyn ManifestDelegate> =
2513 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2514
2515 let servers = self
2516 .lsp_tree
2517 .walk(
2518 ProjectPath { worktree_id, path },
2519 language.name(),
2520 language.manifest(),
2521 &delegate,
2522 cx,
2523 )
2524 .collect::<Vec<_>>();
2525 (false, lsp_delegate, servers)
2526 });
2527 let servers_and_adapters = servers
2528 .into_iter()
2529 .filter_map(|server_node| {
2530 if reused && server_node.server_id().is_none() {
2531 return None;
2532 }
2533 if !only_register_servers.is_empty() {
2534 if let Some(server_id) = server_node.server_id()
2535 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2536 {
2537 return None;
2538 }
2539 if let Some(name) = server_node.name()
2540 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2541 {
2542 return None;
2543 }
2544 }
2545
2546 let server_id = server_node.server_id_or_init(|disposition| {
2547 let path = &disposition.path;
2548
2549 {
2550 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2551
2552 let server_id = self.get_or_insert_language_server(
2553 &worktree,
2554 delegate.clone(),
2555 disposition,
2556 &language_name,
2557 cx,
2558 );
2559
2560 if let Some(state) = self.language_servers.get(&server_id)
2561 && let Ok(uri) = uri
2562 {
2563 state.add_workspace_folder(uri);
2564 };
2565 server_id
2566 }
2567 })?;
2568 let server_state = self.language_servers.get(&server_id)?;
2569 if let LanguageServerState::Running {
2570 server, adapter, ..
2571 } = server_state
2572 {
2573 Some((server.clone(), adapter.clone()))
2574 } else {
2575 None
2576 }
2577 })
2578 .collect::<Vec<_>>();
2579 for (server, adapter) in servers_and_adapters {
2580 buffer_handle.update(cx, |buffer, cx| {
2581 buffer.set_completion_triggers(
2582 server.server_id(),
2583 server
2584 .capabilities()
2585 .completion_provider
2586 .as_ref()
2587 .and_then(|provider| {
2588 provider
2589 .trigger_characters
2590 .as_ref()
2591 .map(|characters| characters.iter().cloned().collect())
2592 })
2593 .unwrap_or_default(),
2594 cx,
2595 );
2596 });
2597
2598 let snapshot = LspBufferSnapshot {
2599 version: 0,
2600 snapshot: initial_snapshot.clone(),
2601 };
2602
2603 let mut registered = false;
2604 self.buffer_snapshots
2605 .entry(buffer_id)
2606 .or_default()
2607 .entry(server.server_id())
2608 .or_insert_with(|| {
2609 registered = true;
2610 server.register_buffer(
2611 uri.clone(),
2612 adapter.language_id(&language.name()),
2613 0,
2614 initial_snapshot.text(),
2615 );
2616
2617 vec![snapshot]
2618 });
2619
2620 self.buffers_opened_in_servers
2621 .entry(buffer_id)
2622 .or_default()
2623 .insert(server.server_id());
2624 if registered {
2625 cx.emit(LspStoreEvent::LanguageServerUpdate {
2626 language_server_id: server.server_id(),
2627 name: None,
2628 message: proto::update_language_server::Variant::RegisteredForBuffer(
2629 proto::RegisteredForBuffer {
2630 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2631 buffer_id: buffer_id.to_proto(),
2632 },
2633 ),
2634 });
2635 }
2636 }
2637 }
2638
2639 fn reuse_existing_language_server<'lang_name>(
2640 &self,
2641 server_tree: &LanguageServerTree,
2642 worktree: &Entity<Worktree>,
2643 language_name: &'lang_name LanguageName,
2644 cx: &mut App,
2645 ) -> Option<(
2646 Arc<LocalLspAdapterDelegate>,
2647 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2648 )> {
2649 if worktree.read(cx).is_visible() {
2650 return None;
2651 }
2652
2653 let worktree_store = self.worktree_store.read(cx);
2654 let servers = server_tree
2655 .instances
2656 .iter()
2657 .filter(|(worktree_id, _)| {
2658 worktree_store
2659 .worktree_for_id(**worktree_id, cx)
2660 .is_some_and(|worktree| worktree.read(cx).is_visible())
2661 })
2662 .flat_map(|(worktree_id, servers)| {
2663 servers
2664 .roots
2665 .iter()
2666 .flat_map(|(_, language_servers)| language_servers)
2667 .map(move |(_, (server_node, server_languages))| {
2668 (worktree_id, server_node, server_languages)
2669 })
2670 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2671 .map(|(worktree_id, server_node, _)| {
2672 (
2673 *worktree_id,
2674 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2675 )
2676 })
2677 })
2678 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2679 acc.entry(worktree_id)
2680 .or_insert_with(Vec::new)
2681 .push(server_node);
2682 acc
2683 })
2684 .into_values()
2685 .max_by_key(|servers| servers.len())?;
2686
2687 let worktree_id = worktree.read(cx).id();
2688 let apply = move |tree: &mut LanguageServerTree| {
2689 for server_node in &servers {
2690 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2691 }
2692 servers
2693 };
2694
2695 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2696 Some((delegate, apply))
2697 }
2698
2699 pub(crate) fn unregister_old_buffer_from_language_servers(
2700 &mut self,
2701 buffer: &Entity<Buffer>,
2702 old_file: &File,
2703 cx: &mut App,
2704 ) {
2705 let old_path = match old_file.as_local() {
2706 Some(local) => local.abs_path(cx),
2707 None => return,
2708 };
2709
2710 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2711 debug_panic!("{old_path:?} is not parseable as an URI");
2712 return;
2713 };
2714 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2715 }
2716
2717 pub(crate) fn unregister_buffer_from_language_servers(
2718 &mut self,
2719 buffer: &Entity<Buffer>,
2720 file_url: &lsp::Uri,
2721 cx: &mut App,
2722 ) {
2723 buffer.update(cx, |buffer, cx| {
2724 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2725
2726 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2727 if snapshots
2728 .as_mut()
2729 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2730 {
2731 language_server.unregister_buffer(file_url.clone());
2732 }
2733 }
2734 });
2735 }
2736
2737 fn buffer_snapshot_for_lsp_version(
2738 &mut self,
2739 buffer: &Entity<Buffer>,
2740 server_id: LanguageServerId,
2741 version: Option<i32>,
2742 cx: &App,
2743 ) -> Result<TextBufferSnapshot> {
2744 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2745
2746 if let Some(version) = version {
2747 let buffer_id = buffer.read(cx).remote_id();
2748 let snapshots = if let Some(snapshots) = self
2749 .buffer_snapshots
2750 .get_mut(&buffer_id)
2751 .and_then(|m| m.get_mut(&server_id))
2752 {
2753 snapshots
2754 } else if version == 0 {
2755 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2756 // We detect this case and treat it as if the version was `None`.
2757 return Ok(buffer.read(cx).text_snapshot());
2758 } else {
2759 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2760 };
2761
2762 let found_snapshot = snapshots
2763 .binary_search_by_key(&version, |e| e.version)
2764 .map(|ix| snapshots[ix].snapshot.clone())
2765 .map_err(|_| {
2766 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2767 })?;
2768
2769 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2770 Ok(found_snapshot)
2771 } else {
2772 Ok((buffer.read(cx)).text_snapshot())
2773 }
2774 }
2775
2776 async fn get_server_code_actions_from_action_kinds(
2777 lsp_store: &WeakEntity<LspStore>,
2778 language_server_id: LanguageServerId,
2779 code_action_kinds: Vec<lsp::CodeActionKind>,
2780 buffer: &Entity<Buffer>,
2781 cx: &mut AsyncApp,
2782 ) -> Result<Vec<CodeAction>> {
2783 let actions = lsp_store
2784 .update(cx, move |this, cx| {
2785 let request = GetCodeActions {
2786 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2787 kinds: Some(code_action_kinds),
2788 };
2789 let server = LanguageServerToQuery::Other(language_server_id);
2790 this.request_lsp(buffer.clone(), server, request, cx)
2791 })?
2792 .await?;
2793 Ok(actions)
2794 }
2795
2796 pub async fn execute_code_actions_on_server(
2797 lsp_store: &WeakEntity<LspStore>,
2798 language_server: &Arc<LanguageServer>,
2799
2800 actions: Vec<CodeAction>,
2801 push_to_history: bool,
2802 project_transaction: &mut ProjectTransaction,
2803 cx: &mut AsyncApp,
2804 ) -> anyhow::Result<()> {
2805 for mut action in actions {
2806 Self::try_resolve_code_action(language_server, &mut action)
2807 .await
2808 .context("resolving a formatting code action")?;
2809
2810 if let Some(edit) = action.lsp_action.edit() {
2811 if edit.changes.is_none() && edit.document_changes.is_none() {
2812 continue;
2813 }
2814
2815 let new = Self::deserialize_workspace_edit(
2816 lsp_store.upgrade().context("project dropped")?,
2817 edit.clone(),
2818 push_to_history,
2819 language_server.clone(),
2820 cx,
2821 )
2822 .await?;
2823 project_transaction.0.extend(new.0);
2824 }
2825
2826 if let Some(command) = action.lsp_action.command() {
2827 let server_capabilities = language_server.capabilities();
2828 let available_commands = server_capabilities
2829 .execute_command_provider
2830 .as_ref()
2831 .map(|options| options.commands.as_slice())
2832 .unwrap_or_default();
2833 if available_commands.contains(&command.command) {
2834 lsp_store.update(cx, |lsp_store, _| {
2835 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2836 mode.last_workspace_edits_by_language_server
2837 .remove(&language_server.server_id());
2838 }
2839 })?;
2840
2841 language_server
2842 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2843 command: command.command.clone(),
2844 arguments: command.arguments.clone().unwrap_or_default(),
2845 ..Default::default()
2846 })
2847 .await
2848 .into_response()
2849 .context("execute command")?;
2850
2851 lsp_store.update(cx, |this, _| {
2852 if let LspStoreMode::Local(mode) = &mut this.mode {
2853 project_transaction.0.extend(
2854 mode.last_workspace_edits_by_language_server
2855 .remove(&language_server.server_id())
2856 .unwrap_or_default()
2857 .0,
2858 )
2859 }
2860 })?;
2861 } else {
2862 log::warn!(
2863 "Cannot execute a command {} not listed in the language server capabilities",
2864 command.command
2865 )
2866 }
2867 }
2868 }
2869 Ok(())
2870 }
2871
2872 pub async fn deserialize_text_edits(
2873 this: Entity<LspStore>,
2874 buffer_to_edit: Entity<Buffer>,
2875 edits: Vec<lsp::TextEdit>,
2876 push_to_history: bool,
2877 _: Arc<CachedLspAdapter>,
2878 language_server: Arc<LanguageServer>,
2879 cx: &mut AsyncApp,
2880 ) -> Result<Option<Transaction>> {
2881 let edits = this
2882 .update(cx, |this, cx| {
2883 this.as_local_mut().unwrap().edits_from_lsp(
2884 &buffer_to_edit,
2885 edits,
2886 language_server.server_id(),
2887 None,
2888 cx,
2889 )
2890 })?
2891 .await?;
2892
2893 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2894 buffer.finalize_last_transaction();
2895 buffer.start_transaction();
2896 for (range, text) in edits {
2897 buffer.edit([(range, text)], None, cx);
2898 }
2899
2900 if buffer.end_transaction(cx).is_some() {
2901 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2902 if !push_to_history {
2903 buffer.forget_transaction(transaction.id);
2904 }
2905 Some(transaction)
2906 } else {
2907 None
2908 }
2909 })?;
2910
2911 Ok(transaction)
2912 }
2913
2914 #[allow(clippy::type_complexity)]
2915 pub(crate) fn edits_from_lsp(
2916 &mut self,
2917 buffer: &Entity<Buffer>,
2918 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2919 server_id: LanguageServerId,
2920 version: Option<i32>,
2921 cx: &mut Context<LspStore>,
2922 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2923 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2924 cx.background_spawn(async move {
2925 let snapshot = snapshot?;
2926 let mut lsp_edits = lsp_edits
2927 .into_iter()
2928 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2929 .collect::<Vec<_>>();
2930
2931 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2932
2933 let mut lsp_edits = lsp_edits.into_iter().peekable();
2934 let mut edits = Vec::new();
2935 while let Some((range, mut new_text)) = lsp_edits.next() {
2936 // Clip invalid ranges provided by the language server.
2937 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2938 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2939
2940 // Combine any LSP edits that are adjacent.
2941 //
2942 // Also, combine LSP edits that are separated from each other by only
2943 // a newline. This is important because for some code actions,
2944 // Rust-analyzer rewrites the entire buffer via a series of edits that
2945 // are separated by unchanged newline characters.
2946 //
2947 // In order for the diffing logic below to work properly, any edits that
2948 // cancel each other out must be combined into one.
2949 while let Some((next_range, next_text)) = lsp_edits.peek() {
2950 if next_range.start.0 > range.end {
2951 if next_range.start.0.row > range.end.row + 1
2952 || next_range.start.0.column > 0
2953 || snapshot.clip_point_utf16(
2954 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2955 Bias::Left,
2956 ) > range.end
2957 {
2958 break;
2959 }
2960 new_text.push('\n');
2961 }
2962 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2963 new_text.push_str(next_text);
2964 lsp_edits.next();
2965 }
2966
2967 // For multiline edits, perform a diff of the old and new text so that
2968 // we can identify the changes more precisely, preserving the locations
2969 // of any anchors positioned in the unchanged regions.
2970 if range.end.row > range.start.row {
2971 let offset = range.start.to_offset(&snapshot);
2972 let old_text = snapshot.text_for_range(range).collect::<String>();
2973 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2974 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2975 (
2976 snapshot.anchor_after(offset + range.start)
2977 ..snapshot.anchor_before(offset + range.end),
2978 replacement,
2979 )
2980 }));
2981 } else if range.end == range.start {
2982 let anchor = snapshot.anchor_after(range.start);
2983 edits.push((anchor..anchor, new_text.into()));
2984 } else {
2985 let edit_start = snapshot.anchor_after(range.start);
2986 let edit_end = snapshot.anchor_before(range.end);
2987 edits.push((edit_start..edit_end, new_text.into()));
2988 }
2989 }
2990
2991 Ok(edits)
2992 })
2993 }
2994
2995 pub(crate) async fn deserialize_workspace_edit(
2996 this: Entity<LspStore>,
2997 edit: lsp::WorkspaceEdit,
2998 push_to_history: bool,
2999 language_server: Arc<LanguageServer>,
3000 cx: &mut AsyncApp,
3001 ) -> Result<ProjectTransaction> {
3002 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3003
3004 let mut operations = Vec::new();
3005 if let Some(document_changes) = edit.document_changes {
3006 match document_changes {
3007 lsp::DocumentChanges::Edits(edits) => {
3008 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3009 }
3010 lsp::DocumentChanges::Operations(ops) => operations = ops,
3011 }
3012 } else if let Some(changes) = edit.changes {
3013 operations.extend(changes.into_iter().map(|(uri, edits)| {
3014 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3015 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3016 uri,
3017 version: None,
3018 },
3019 edits: edits.into_iter().map(Edit::Plain).collect(),
3020 })
3021 }));
3022 }
3023
3024 let mut project_transaction = ProjectTransaction::default();
3025 for operation in operations {
3026 match operation {
3027 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3028 let abs_path = op
3029 .uri
3030 .to_file_path()
3031 .map_err(|()| anyhow!("can't convert URI to path"))?;
3032
3033 if let Some(parent_path) = abs_path.parent() {
3034 fs.create_dir(parent_path).await?;
3035 }
3036 if abs_path.ends_with("/") {
3037 fs.create_dir(&abs_path).await?;
3038 } else {
3039 fs.create_file(
3040 &abs_path,
3041 op.options
3042 .map(|options| fs::CreateOptions {
3043 overwrite: options.overwrite.unwrap_or(false),
3044 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3045 })
3046 .unwrap_or_default(),
3047 )
3048 .await?;
3049 }
3050 }
3051
3052 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3053 let source_abs_path = op
3054 .old_uri
3055 .to_file_path()
3056 .map_err(|()| anyhow!("can't convert URI to path"))?;
3057 let target_abs_path = op
3058 .new_uri
3059 .to_file_path()
3060 .map_err(|()| anyhow!("can't convert URI to path"))?;
3061
3062 let options = fs::RenameOptions {
3063 overwrite: op
3064 .options
3065 .as_ref()
3066 .and_then(|options| options.overwrite)
3067 .unwrap_or(false),
3068 ignore_if_exists: op
3069 .options
3070 .as_ref()
3071 .and_then(|options| options.ignore_if_exists)
3072 .unwrap_or(false),
3073 create_parents: true,
3074 };
3075
3076 fs.rename(&source_abs_path, &target_abs_path, options)
3077 .await?;
3078 }
3079
3080 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3081 let abs_path = op
3082 .uri
3083 .to_file_path()
3084 .map_err(|()| anyhow!("can't convert URI to path"))?;
3085 let options = op
3086 .options
3087 .map(|options| fs::RemoveOptions {
3088 recursive: options.recursive.unwrap_or(false),
3089 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3090 })
3091 .unwrap_or_default();
3092 if abs_path.ends_with("/") {
3093 fs.remove_dir(&abs_path, options).await?;
3094 } else {
3095 fs.remove_file(&abs_path, options).await?;
3096 }
3097 }
3098
3099 lsp::DocumentChangeOperation::Edit(op) => {
3100 let buffer_to_edit = this
3101 .update(cx, |this, cx| {
3102 this.open_local_buffer_via_lsp(
3103 op.text_document.uri.clone(),
3104 language_server.server_id(),
3105 cx,
3106 )
3107 })?
3108 .await?;
3109
3110 let edits = this
3111 .update(cx, |this, cx| {
3112 let path = buffer_to_edit.read(cx).project_path(cx);
3113 let active_entry = this.active_entry;
3114 let is_active_entry = path.is_some_and(|project_path| {
3115 this.worktree_store
3116 .read(cx)
3117 .entry_for_path(&project_path, cx)
3118 .is_some_and(|entry| Some(entry.id) == active_entry)
3119 });
3120 let local = this.as_local_mut().unwrap();
3121
3122 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3123 for edit in op.edits {
3124 match edit {
3125 Edit::Plain(edit) => {
3126 if !edits.contains(&edit) {
3127 edits.push(edit)
3128 }
3129 }
3130 Edit::Annotated(edit) => {
3131 if !edits.contains(&edit.text_edit) {
3132 edits.push(edit.text_edit)
3133 }
3134 }
3135 Edit::Snippet(edit) => {
3136 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3137 else {
3138 continue;
3139 };
3140
3141 if is_active_entry {
3142 snippet_edits.push((edit.range, snippet));
3143 } else {
3144 // Since this buffer is not focused, apply a normal edit.
3145 let new_edit = TextEdit {
3146 range: edit.range,
3147 new_text: snippet.text,
3148 };
3149 if !edits.contains(&new_edit) {
3150 edits.push(new_edit);
3151 }
3152 }
3153 }
3154 }
3155 }
3156 if !snippet_edits.is_empty() {
3157 let buffer_id = buffer_to_edit.read(cx).remote_id();
3158 let version = if let Some(buffer_version) = op.text_document.version
3159 {
3160 local
3161 .buffer_snapshot_for_lsp_version(
3162 &buffer_to_edit,
3163 language_server.server_id(),
3164 Some(buffer_version),
3165 cx,
3166 )
3167 .ok()
3168 .map(|snapshot| snapshot.version)
3169 } else {
3170 Some(buffer_to_edit.read(cx).saved_version().clone())
3171 };
3172
3173 let most_recent_edit =
3174 version.and_then(|version| version.most_recent());
3175 // Check if the edit that triggered that edit has been made by this participant.
3176
3177 if let Some(most_recent_edit) = most_recent_edit {
3178 cx.emit(LspStoreEvent::SnippetEdit {
3179 buffer_id,
3180 edits: snippet_edits,
3181 most_recent_edit,
3182 });
3183 }
3184 }
3185
3186 local.edits_from_lsp(
3187 &buffer_to_edit,
3188 edits,
3189 language_server.server_id(),
3190 op.text_document.version,
3191 cx,
3192 )
3193 })?
3194 .await?;
3195
3196 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3197 buffer.finalize_last_transaction();
3198 buffer.start_transaction();
3199 for (range, text) in edits {
3200 buffer.edit([(range, text)], None, cx);
3201 }
3202
3203 buffer.end_transaction(cx).and_then(|transaction_id| {
3204 if push_to_history {
3205 buffer.finalize_last_transaction();
3206 buffer.get_transaction(transaction_id).cloned()
3207 } else {
3208 buffer.forget_transaction(transaction_id)
3209 }
3210 })
3211 })?;
3212 if let Some(transaction) = transaction {
3213 project_transaction.0.insert(buffer_to_edit, transaction);
3214 }
3215 }
3216 }
3217 }
3218
3219 Ok(project_transaction)
3220 }
3221
3222 async fn on_lsp_workspace_edit(
3223 this: WeakEntity<LspStore>,
3224 params: lsp::ApplyWorkspaceEditParams,
3225 server_id: LanguageServerId,
3226 cx: &mut AsyncApp,
3227 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3228 let this = this.upgrade().context("project project closed")?;
3229 let language_server = this
3230 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3231 .context("language server not found")?;
3232 let transaction = Self::deserialize_workspace_edit(
3233 this.clone(),
3234 params.edit,
3235 true,
3236 language_server.clone(),
3237 cx,
3238 )
3239 .await
3240 .log_err();
3241 this.update(cx, |this, _| {
3242 if let Some(transaction) = transaction {
3243 this.as_local_mut()
3244 .unwrap()
3245 .last_workspace_edits_by_language_server
3246 .insert(server_id, transaction);
3247 }
3248 })?;
3249 Ok(lsp::ApplyWorkspaceEditResponse {
3250 applied: true,
3251 failed_change: None,
3252 failure_reason: None,
3253 })
3254 }
3255
3256 fn remove_worktree(
3257 &mut self,
3258 id_to_remove: WorktreeId,
3259 cx: &mut Context<LspStore>,
3260 ) -> Vec<LanguageServerId> {
3261 self.diagnostics.remove(&id_to_remove);
3262 self.prettier_store.update(cx, |prettier_store, cx| {
3263 prettier_store.remove_worktree(id_to_remove, cx);
3264 });
3265
3266 let mut servers_to_remove = BTreeSet::default();
3267 let mut servers_to_preserve = HashSet::default();
3268 for (seed, state) in &self.language_server_ids {
3269 if seed.worktree_id == id_to_remove {
3270 servers_to_remove.insert(state.id);
3271 } else {
3272 servers_to_preserve.insert(state.id);
3273 }
3274 }
3275 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3276 self.language_server_ids
3277 .retain(|_, state| !servers_to_remove.contains(&state.id));
3278 for server_id_to_remove in &servers_to_remove {
3279 self.language_server_watched_paths
3280 .remove(server_id_to_remove);
3281 self.language_server_paths_watched_for_rename
3282 .remove(server_id_to_remove);
3283 self.last_workspace_edits_by_language_server
3284 .remove(server_id_to_remove);
3285 self.language_servers.remove(server_id_to_remove);
3286 self.buffer_pull_diagnostics_result_ids
3287 .remove(server_id_to_remove);
3288 self.workspace_pull_diagnostics_result_ids
3289 .remove(server_id_to_remove);
3290 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3291 buffer_servers.remove(server_id_to_remove);
3292 }
3293 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3294 }
3295 servers_to_remove.into_iter().collect()
3296 }
3297
3298 fn rebuild_watched_paths_inner<'a>(
3299 &'a self,
3300 language_server_id: LanguageServerId,
3301 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3302 cx: &mut Context<LspStore>,
3303 ) -> LanguageServerWatchedPathsBuilder {
3304 let worktrees = self
3305 .worktree_store
3306 .read(cx)
3307 .worktrees()
3308 .filter_map(|worktree| {
3309 self.language_servers_for_worktree(worktree.read(cx).id())
3310 .find(|server| server.server_id() == language_server_id)
3311 .map(|_| worktree)
3312 })
3313 .collect::<Vec<_>>();
3314
3315 let mut worktree_globs = HashMap::default();
3316 let mut abs_globs = HashMap::default();
3317 log::trace!(
3318 "Processing new watcher paths for language server with id {}",
3319 language_server_id
3320 );
3321
3322 for watcher in watchers {
3323 if let Some((worktree, literal_prefix, pattern)) =
3324 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3325 {
3326 worktree.update(cx, |worktree, _| {
3327 if let Some((tree, glob)) =
3328 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3329 {
3330 tree.add_path_prefix_to_scan(literal_prefix);
3331 worktree_globs
3332 .entry(tree.id())
3333 .or_insert_with(GlobSetBuilder::new)
3334 .add(glob);
3335 }
3336 });
3337 } else {
3338 let (path, pattern) = match &watcher.glob_pattern {
3339 lsp::GlobPattern::String(s) => {
3340 let watcher_path = SanitizedPath::new(s);
3341 let path = glob_literal_prefix(watcher_path.as_path());
3342 let pattern = watcher_path
3343 .as_path()
3344 .strip_prefix(&path)
3345 .map(|p| p.to_string_lossy().into_owned())
3346 .unwrap_or_else(|e| {
3347 debug_panic!(
3348 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3349 s,
3350 path.display(),
3351 e
3352 );
3353 watcher_path.as_path().to_string_lossy().into_owned()
3354 });
3355 (path, pattern)
3356 }
3357 lsp::GlobPattern::Relative(rp) => {
3358 let Ok(mut base_uri) = match &rp.base_uri {
3359 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3360 lsp::OneOf::Right(base_uri) => base_uri,
3361 }
3362 .to_file_path() else {
3363 continue;
3364 };
3365
3366 let path = glob_literal_prefix(Path::new(&rp.pattern));
3367 let pattern = Path::new(&rp.pattern)
3368 .strip_prefix(&path)
3369 .map(|p| p.to_string_lossy().into_owned())
3370 .unwrap_or_else(|e| {
3371 debug_panic!(
3372 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3373 rp.pattern,
3374 path.display(),
3375 e
3376 );
3377 rp.pattern.clone()
3378 });
3379 base_uri.push(path);
3380 (base_uri, pattern)
3381 }
3382 };
3383
3384 if let Some(glob) = Glob::new(&pattern).log_err() {
3385 if !path
3386 .components()
3387 .any(|c| matches!(c, path::Component::Normal(_)))
3388 {
3389 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3390 // rather than adding a new watcher for `/`.
3391 for worktree in &worktrees {
3392 worktree_globs
3393 .entry(worktree.read(cx).id())
3394 .or_insert_with(GlobSetBuilder::new)
3395 .add(glob.clone());
3396 }
3397 } else {
3398 abs_globs
3399 .entry(path.into())
3400 .or_insert_with(GlobSetBuilder::new)
3401 .add(glob);
3402 }
3403 }
3404 }
3405 }
3406
3407 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3408 for (worktree_id, builder) in worktree_globs {
3409 if let Ok(globset) = builder.build() {
3410 watch_builder.watch_worktree(worktree_id, globset);
3411 }
3412 }
3413 for (abs_path, builder) in abs_globs {
3414 if let Ok(globset) = builder.build() {
3415 watch_builder.watch_abs_path(abs_path, globset);
3416 }
3417 }
3418 watch_builder
3419 }
3420
3421 fn worktree_and_path_for_file_watcher(
3422 worktrees: &[Entity<Worktree>],
3423 watcher: &FileSystemWatcher,
3424 cx: &App,
3425 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3426 worktrees.iter().find_map(|worktree| {
3427 let tree = worktree.read(cx);
3428 let worktree_root_path = tree.abs_path();
3429 let path_style = tree.path_style();
3430 match &watcher.glob_pattern {
3431 lsp::GlobPattern::String(s) => {
3432 let watcher_path = SanitizedPath::new(s);
3433 let relative = watcher_path
3434 .as_path()
3435 .strip_prefix(&worktree_root_path)
3436 .ok()?;
3437 let literal_prefix = glob_literal_prefix(relative);
3438 Some((
3439 worktree.clone(),
3440 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3441 relative.to_string_lossy().into_owned(),
3442 ))
3443 }
3444 lsp::GlobPattern::Relative(rp) => {
3445 let base_uri = match &rp.base_uri {
3446 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3447 lsp::OneOf::Right(base_uri) => base_uri,
3448 }
3449 .to_file_path()
3450 .ok()?;
3451 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3452 let mut literal_prefix = relative.to_owned();
3453 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3454 Some((
3455 worktree.clone(),
3456 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3457 rp.pattern.clone(),
3458 ))
3459 }
3460 }
3461 })
3462 }
3463
3464 fn rebuild_watched_paths(
3465 &mut self,
3466 language_server_id: LanguageServerId,
3467 cx: &mut Context<LspStore>,
3468 ) {
3469 let Some(registrations) = self
3470 .language_server_dynamic_registrations
3471 .get(&language_server_id)
3472 else {
3473 return;
3474 };
3475
3476 let watch_builder = self.rebuild_watched_paths_inner(
3477 language_server_id,
3478 registrations.did_change_watched_files.values().flatten(),
3479 cx,
3480 );
3481 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3482 self.language_server_watched_paths
3483 .insert(language_server_id, watcher);
3484
3485 cx.notify();
3486 }
3487
3488 fn on_lsp_did_change_watched_files(
3489 &mut self,
3490 language_server_id: LanguageServerId,
3491 registration_id: &str,
3492 params: DidChangeWatchedFilesRegistrationOptions,
3493 cx: &mut Context<LspStore>,
3494 ) {
3495 let registrations = self
3496 .language_server_dynamic_registrations
3497 .entry(language_server_id)
3498 .or_default();
3499
3500 registrations
3501 .did_change_watched_files
3502 .insert(registration_id.to_string(), params.watchers);
3503
3504 self.rebuild_watched_paths(language_server_id, cx);
3505 }
3506
3507 fn on_lsp_unregister_did_change_watched_files(
3508 &mut self,
3509 language_server_id: LanguageServerId,
3510 registration_id: &str,
3511 cx: &mut Context<LspStore>,
3512 ) {
3513 let registrations = self
3514 .language_server_dynamic_registrations
3515 .entry(language_server_id)
3516 .or_default();
3517
3518 if registrations
3519 .did_change_watched_files
3520 .remove(registration_id)
3521 .is_some()
3522 {
3523 log::info!(
3524 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3525 language_server_id,
3526 registration_id
3527 );
3528 } else {
3529 log::warn!(
3530 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3531 language_server_id,
3532 registration_id
3533 );
3534 }
3535
3536 self.rebuild_watched_paths(language_server_id, cx);
3537 }
3538
3539 async fn initialization_options_for_adapter(
3540 adapter: Arc<dyn LspAdapter>,
3541 delegate: &Arc<dyn LspAdapterDelegate>,
3542 ) -> Result<Option<serde_json::Value>> {
3543 let Some(mut initialization_config) =
3544 adapter.clone().initialization_options(delegate).await?
3545 else {
3546 return Ok(None);
3547 };
3548
3549 for other_adapter in delegate.registered_lsp_adapters() {
3550 if other_adapter.name() == adapter.name() {
3551 continue;
3552 }
3553 if let Ok(Some(target_config)) = other_adapter
3554 .clone()
3555 .additional_initialization_options(adapter.name(), delegate)
3556 .await
3557 {
3558 merge_json_value_into(target_config.clone(), &mut initialization_config);
3559 }
3560 }
3561
3562 Ok(Some(initialization_config))
3563 }
3564
3565 async fn workspace_configuration_for_adapter(
3566 adapter: Arc<dyn LspAdapter>,
3567 delegate: &Arc<dyn LspAdapterDelegate>,
3568 toolchain: Option<Toolchain>,
3569 requested_uri: Option<Uri>,
3570 cx: &mut AsyncApp,
3571 ) -> Result<serde_json::Value> {
3572 let mut workspace_config = adapter
3573 .clone()
3574 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3575 .await?;
3576
3577 for other_adapter in delegate.registered_lsp_adapters() {
3578 if other_adapter.name() == adapter.name() {
3579 continue;
3580 }
3581 if let Ok(Some(target_config)) = other_adapter
3582 .clone()
3583 .additional_workspace_configuration(adapter.name(), delegate, cx)
3584 .await
3585 {
3586 merge_json_value_into(target_config.clone(), &mut workspace_config);
3587 }
3588 }
3589
3590 Ok(workspace_config)
3591 }
3592
3593 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3594 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3595 Some(server.clone())
3596 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3597 Some(Arc::clone(server))
3598 } else {
3599 None
3600 }
3601 }
3602}
3603
3604fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3605 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3606 cx.emit(LspStoreEvent::LanguageServerUpdate {
3607 language_server_id: server.server_id(),
3608 name: Some(server.name()),
3609 message: proto::update_language_server::Variant::MetadataUpdated(
3610 proto::ServerMetadataUpdated {
3611 capabilities: Some(capabilities),
3612 binary: Some(proto::LanguageServerBinaryInfo {
3613 path: server.binary().path.to_string_lossy().into_owned(),
3614 arguments: server
3615 .binary()
3616 .arguments
3617 .iter()
3618 .map(|arg| arg.to_string_lossy().into_owned())
3619 .collect(),
3620 }),
3621 configuration: serde_json::to_string(server.configuration()).ok(),
3622 workspace_folders: server
3623 .workspace_folders()
3624 .iter()
3625 .map(|uri| uri.to_string())
3626 .collect(),
3627 },
3628 ),
3629 });
3630 }
3631}
3632
3633#[derive(Debug)]
3634pub struct FormattableBuffer {
3635 handle: Entity<Buffer>,
3636 abs_path: Option<PathBuf>,
3637 env: Option<HashMap<String, String>>,
3638 ranges: Option<Vec<Range<Anchor>>>,
3639}
3640
3641pub struct RemoteLspStore {
3642 upstream_client: Option<AnyProtoClient>,
3643 upstream_project_id: u64,
3644}
3645
3646pub(crate) enum LspStoreMode {
3647 Local(LocalLspStore), // ssh host and collab host
3648 Remote(RemoteLspStore), // collab guest
3649}
3650
3651impl LspStoreMode {
3652 fn is_local(&self) -> bool {
3653 matches!(self, LspStoreMode::Local(_))
3654 }
3655}
3656
3657pub struct LspStore {
3658 mode: LspStoreMode,
3659 last_formatting_failure: Option<String>,
3660 downstream_client: Option<(AnyProtoClient, u64)>,
3661 nonce: u128,
3662 buffer_store: Entity<BufferStore>,
3663 worktree_store: Entity<WorktreeStore>,
3664 pub languages: Arc<LanguageRegistry>,
3665 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3666 active_entry: Option<ProjectEntryId>,
3667 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3668 _maintain_buffer_languages: Task<()>,
3669 diagnostic_summaries:
3670 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3671 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3672 lsp_data: HashMap<BufferId, BufferLspData>,
3673 next_hint_id: Arc<AtomicUsize>,
3674}
3675
3676#[derive(Debug)]
3677pub struct BufferLspData {
3678 buffer_version: Global,
3679 document_colors: Option<DocumentColorData>,
3680 code_lens: Option<CodeLensData>,
3681 inlay_hints: BufferInlayHints,
3682 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3683 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3684}
3685
3686#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3687struct LspKey {
3688 request_type: TypeId,
3689 server_queried: Option<LanguageServerId>,
3690}
3691
3692impl BufferLspData {
3693 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3694 Self {
3695 buffer_version: buffer.read(cx).version(),
3696 document_colors: None,
3697 code_lens: None,
3698 inlay_hints: BufferInlayHints::new(buffer, cx),
3699 lsp_requests: HashMap::default(),
3700 chunk_lsp_requests: HashMap::default(),
3701 }
3702 }
3703
3704 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3705 if let Some(document_colors) = &mut self.document_colors {
3706 document_colors.colors.remove(&for_server);
3707 document_colors.cache_version += 1;
3708 }
3709
3710 if let Some(code_lens) = &mut self.code_lens {
3711 code_lens.lens.remove(&for_server);
3712 }
3713
3714 self.inlay_hints.remove_server_data(for_server);
3715 }
3716
3717 #[cfg(any(test, feature = "test-support"))]
3718 pub fn inlay_hints(&self) -> &BufferInlayHints {
3719 &self.inlay_hints
3720 }
3721}
3722
3723#[derive(Debug, Default, Clone)]
3724pub struct DocumentColors {
3725 pub colors: HashSet<DocumentColor>,
3726 pub cache_version: Option<usize>,
3727}
3728
3729type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3730type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3731
3732#[derive(Debug, Default)]
3733struct DocumentColorData {
3734 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3735 cache_version: usize,
3736 colors_update: Option<(Global, DocumentColorTask)>,
3737}
3738
3739#[derive(Debug, Default)]
3740struct CodeLensData {
3741 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3742 update: Option<(Global, CodeLensTask)>,
3743}
3744
3745#[derive(Debug)]
3746pub enum LspStoreEvent {
3747 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3748 LanguageServerRemoved(LanguageServerId),
3749 LanguageServerUpdate {
3750 language_server_id: LanguageServerId,
3751 name: Option<LanguageServerName>,
3752 message: proto::update_language_server::Variant,
3753 },
3754 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3755 LanguageServerPrompt(LanguageServerPromptRequest),
3756 LanguageDetected {
3757 buffer: Entity<Buffer>,
3758 new_language: Option<Arc<Language>>,
3759 },
3760 Notification(String),
3761 RefreshInlayHints {
3762 server_id: LanguageServerId,
3763 request_id: Option<usize>,
3764 },
3765 RefreshCodeLens,
3766 DiagnosticsUpdated {
3767 server_id: LanguageServerId,
3768 paths: Vec<ProjectPath>,
3769 },
3770 DiskBasedDiagnosticsStarted {
3771 language_server_id: LanguageServerId,
3772 },
3773 DiskBasedDiagnosticsFinished {
3774 language_server_id: LanguageServerId,
3775 },
3776 SnippetEdit {
3777 buffer_id: BufferId,
3778 edits: Vec<(lsp::Range, Snippet)>,
3779 most_recent_edit: clock::Lamport,
3780 },
3781}
3782
3783#[derive(Clone, Debug, Serialize)]
3784pub struct LanguageServerStatus {
3785 pub name: LanguageServerName,
3786 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3787 pub has_pending_diagnostic_updates: bool,
3788 pub progress_tokens: HashSet<ProgressToken>,
3789 pub worktree: Option<WorktreeId>,
3790 pub binary: Option<LanguageServerBinary>,
3791 pub configuration: Option<Value>,
3792 pub workspace_folders: BTreeSet<Uri>,
3793}
3794
3795#[derive(Clone, Debug)]
3796struct CoreSymbol {
3797 pub language_server_name: LanguageServerName,
3798 pub source_worktree_id: WorktreeId,
3799 pub source_language_server_id: LanguageServerId,
3800 pub path: SymbolLocation,
3801 pub name: String,
3802 pub kind: lsp::SymbolKind,
3803 pub range: Range<Unclipped<PointUtf16>>,
3804}
3805
3806#[derive(Clone, Debug, PartialEq, Eq)]
3807pub enum SymbolLocation {
3808 InProject(ProjectPath),
3809 OutsideProject {
3810 abs_path: Arc<Path>,
3811 signature: [u8; 32],
3812 },
3813}
3814
3815impl SymbolLocation {
3816 fn file_name(&self) -> Option<&str> {
3817 match self {
3818 Self::InProject(path) => path.path.file_name(),
3819 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3820 }
3821 }
3822}
3823
3824impl LspStore {
3825 pub fn init(client: &AnyProtoClient) {
3826 client.add_entity_request_handler(Self::handle_lsp_query);
3827 client.add_entity_message_handler(Self::handle_lsp_query_response);
3828 client.add_entity_request_handler(Self::handle_restart_language_servers);
3829 client.add_entity_request_handler(Self::handle_stop_language_servers);
3830 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3831 client.add_entity_message_handler(Self::handle_start_language_server);
3832 client.add_entity_message_handler(Self::handle_update_language_server);
3833 client.add_entity_message_handler(Self::handle_language_server_log);
3834 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3835 client.add_entity_request_handler(Self::handle_format_buffers);
3836 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3837 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3838 client.add_entity_request_handler(Self::handle_apply_code_action);
3839 client.add_entity_request_handler(Self::handle_get_project_symbols);
3840 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3841 client.add_entity_request_handler(Self::handle_get_color_presentation);
3842 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3843 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3844 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3845 client.add_entity_request_handler(Self::handle_on_type_formatting);
3846 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3847 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3848 client.add_entity_request_handler(Self::handle_rename_project_entry);
3849 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3850 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3851 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3852 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3853 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3854 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3855 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3856
3857 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3858 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3859 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3860 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3861 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3862 client.add_entity_request_handler(
3863 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3864 );
3865 client.add_entity_request_handler(
3866 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3867 );
3868 client.add_entity_request_handler(
3869 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3870 );
3871 }
3872
3873 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3874 match &self.mode {
3875 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3876 _ => None,
3877 }
3878 }
3879
3880 pub fn as_local(&self) -> Option<&LocalLspStore> {
3881 match &self.mode {
3882 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3883 _ => None,
3884 }
3885 }
3886
3887 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3888 match &mut self.mode {
3889 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3890 _ => None,
3891 }
3892 }
3893
3894 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3895 match &self.mode {
3896 LspStoreMode::Remote(RemoteLspStore {
3897 upstream_client: Some(upstream_client),
3898 upstream_project_id,
3899 ..
3900 }) => Some((upstream_client.clone(), *upstream_project_id)),
3901
3902 LspStoreMode::Remote(RemoteLspStore {
3903 upstream_client: None,
3904 ..
3905 }) => None,
3906 LspStoreMode::Local(_) => None,
3907 }
3908 }
3909
3910 pub fn new_local(
3911 buffer_store: Entity<BufferStore>,
3912 worktree_store: Entity<WorktreeStore>,
3913 prettier_store: Entity<PrettierStore>,
3914 toolchain_store: Entity<LocalToolchainStore>,
3915 environment: Entity<ProjectEnvironment>,
3916 manifest_tree: Entity<ManifestTree>,
3917 languages: Arc<LanguageRegistry>,
3918 http_client: Arc<dyn HttpClient>,
3919 fs: Arc<dyn Fs>,
3920 cx: &mut Context<Self>,
3921 ) -> Self {
3922 let yarn = YarnPathStore::new(fs.clone(), cx);
3923 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3924 .detach();
3925 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3926 .detach();
3927 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3928 .detach();
3929 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3930 .detach();
3931 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3932 .detach();
3933 subscribe_to_binary_statuses(&languages, cx).detach();
3934
3935 let _maintain_workspace_config = {
3936 let (sender, receiver) = watch::channel();
3937 (Self::maintain_workspace_config(receiver, cx), sender)
3938 };
3939
3940 Self {
3941 mode: LspStoreMode::Local(LocalLspStore {
3942 weak: cx.weak_entity(),
3943 worktree_store: worktree_store.clone(),
3944
3945 supplementary_language_servers: Default::default(),
3946 languages: languages.clone(),
3947 language_server_ids: Default::default(),
3948 language_servers: Default::default(),
3949 last_workspace_edits_by_language_server: Default::default(),
3950 language_server_watched_paths: Default::default(),
3951 language_server_paths_watched_for_rename: Default::default(),
3952 language_server_dynamic_registrations: Default::default(),
3953 buffers_being_formatted: Default::default(),
3954 buffer_snapshots: Default::default(),
3955 prettier_store,
3956 environment,
3957 http_client,
3958 fs,
3959 yarn,
3960 next_diagnostic_group_id: Default::default(),
3961 diagnostics: Default::default(),
3962 _subscription: cx.on_app_quit(|this, cx| {
3963 this.as_local_mut()
3964 .unwrap()
3965 .shutdown_language_servers_on_quit(cx)
3966 }),
3967 lsp_tree: LanguageServerTree::new(
3968 manifest_tree,
3969 languages.clone(),
3970 toolchain_store.clone(),
3971 ),
3972 toolchain_store,
3973 registered_buffers: HashMap::default(),
3974 buffers_opened_in_servers: HashMap::default(),
3975 buffer_pull_diagnostics_result_ids: HashMap::default(),
3976 workspace_pull_diagnostics_result_ids: HashMap::default(),
3977 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3978 .manifest_file_names(),
3979 }),
3980 last_formatting_failure: None,
3981 downstream_client: None,
3982 buffer_store,
3983 worktree_store,
3984 languages: languages.clone(),
3985 language_server_statuses: Default::default(),
3986 nonce: StdRng::from_os_rng().random(),
3987 diagnostic_summaries: HashMap::default(),
3988 lsp_server_capabilities: HashMap::default(),
3989 lsp_data: HashMap::default(),
3990 next_hint_id: Arc::default(),
3991 active_entry: None,
3992 _maintain_workspace_config,
3993 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3994 }
3995 }
3996
3997 fn send_lsp_proto_request<R: LspCommand>(
3998 &self,
3999 buffer: Entity<Buffer>,
4000 client: AnyProtoClient,
4001 upstream_project_id: u64,
4002 request: R,
4003 cx: &mut Context<LspStore>,
4004 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4005 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4006 return Task::ready(Ok(R::Response::default()));
4007 }
4008 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4009 cx.spawn(async move |this, cx| {
4010 let response = client.request(message).await?;
4011 let this = this.upgrade().context("project dropped")?;
4012 request
4013 .response_from_proto(response, this, buffer, cx.clone())
4014 .await
4015 })
4016 }
4017
4018 pub(super) fn new_remote(
4019 buffer_store: Entity<BufferStore>,
4020 worktree_store: Entity<WorktreeStore>,
4021 languages: Arc<LanguageRegistry>,
4022 upstream_client: AnyProtoClient,
4023 project_id: u64,
4024 cx: &mut Context<Self>,
4025 ) -> Self {
4026 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4027 .detach();
4028 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4029 .detach();
4030 subscribe_to_binary_statuses(&languages, cx).detach();
4031 let _maintain_workspace_config = {
4032 let (sender, receiver) = watch::channel();
4033 (Self::maintain_workspace_config(receiver, cx), sender)
4034 };
4035 Self {
4036 mode: LspStoreMode::Remote(RemoteLspStore {
4037 upstream_client: Some(upstream_client),
4038 upstream_project_id: project_id,
4039 }),
4040 downstream_client: None,
4041 last_formatting_failure: None,
4042 buffer_store,
4043 worktree_store,
4044 languages: languages.clone(),
4045 language_server_statuses: Default::default(),
4046 nonce: StdRng::from_os_rng().random(),
4047 diagnostic_summaries: HashMap::default(),
4048 lsp_server_capabilities: HashMap::default(),
4049 next_hint_id: Arc::default(),
4050 lsp_data: HashMap::default(),
4051 active_entry: None,
4052
4053 _maintain_workspace_config,
4054 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4055 }
4056 }
4057
4058 fn on_buffer_store_event(
4059 &mut self,
4060 _: Entity<BufferStore>,
4061 event: &BufferStoreEvent,
4062 cx: &mut Context<Self>,
4063 ) {
4064 match event {
4065 BufferStoreEvent::BufferAdded(buffer) => {
4066 self.on_buffer_added(buffer, cx).log_err();
4067 }
4068 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4069 let buffer_id = buffer.read(cx).remote_id();
4070 if let Some(local) = self.as_local_mut()
4071 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4072 {
4073 local.reset_buffer(buffer, old_file, cx);
4074
4075 if local.registered_buffers.contains_key(&buffer_id) {
4076 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4077 }
4078 }
4079
4080 self.detect_language_for_buffer(buffer, cx);
4081 if let Some(local) = self.as_local_mut() {
4082 local.initialize_buffer(buffer, cx);
4083 if local.registered_buffers.contains_key(&buffer_id) {
4084 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4085 }
4086 }
4087 }
4088 _ => {}
4089 }
4090 }
4091
4092 fn on_worktree_store_event(
4093 &mut self,
4094 _: Entity<WorktreeStore>,
4095 event: &WorktreeStoreEvent,
4096 cx: &mut Context<Self>,
4097 ) {
4098 match event {
4099 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4100 if !worktree.read(cx).is_local() {
4101 return;
4102 }
4103 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4104 worktree::Event::UpdatedEntries(changes) => {
4105 this.update_local_worktree_language_servers(&worktree, changes, cx);
4106 }
4107 worktree::Event::UpdatedGitRepositories(_)
4108 | worktree::Event::DeletedEntry(_) => {}
4109 })
4110 .detach()
4111 }
4112 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4113 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4114 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4115 }
4116 WorktreeStoreEvent::WorktreeReleased(..)
4117 | WorktreeStoreEvent::WorktreeOrderChanged
4118 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4119 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4120 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4121 }
4122 }
4123
4124 fn on_prettier_store_event(
4125 &mut self,
4126 _: Entity<PrettierStore>,
4127 event: &PrettierStoreEvent,
4128 cx: &mut Context<Self>,
4129 ) {
4130 match event {
4131 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4132 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4133 }
4134 PrettierStoreEvent::LanguageServerAdded {
4135 new_server_id,
4136 name,
4137 prettier_server,
4138 } => {
4139 self.register_supplementary_language_server(
4140 *new_server_id,
4141 name.clone(),
4142 prettier_server.clone(),
4143 cx,
4144 );
4145 }
4146 }
4147 }
4148
4149 fn on_toolchain_store_event(
4150 &mut self,
4151 _: Entity<LocalToolchainStore>,
4152 event: &ToolchainStoreEvent,
4153 _: &mut Context<Self>,
4154 ) {
4155 if let ToolchainStoreEvent::ToolchainActivated = event {
4156 self.request_workspace_config_refresh()
4157 }
4158 }
4159
4160 fn request_workspace_config_refresh(&mut self) {
4161 *self._maintain_workspace_config.1.borrow_mut() = ();
4162 }
4163
4164 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4165 self.as_local().map(|local| local.prettier_store.clone())
4166 }
4167
4168 fn on_buffer_event(
4169 &mut self,
4170 buffer: Entity<Buffer>,
4171 event: &language::BufferEvent,
4172 cx: &mut Context<Self>,
4173 ) {
4174 match event {
4175 language::BufferEvent::Edited => {
4176 self.on_buffer_edited(buffer, cx);
4177 }
4178
4179 language::BufferEvent::Saved => {
4180 self.on_buffer_saved(buffer, cx);
4181 }
4182
4183 _ => {}
4184 }
4185 }
4186
4187 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4188 buffer
4189 .read(cx)
4190 .set_language_registry(self.languages.clone());
4191
4192 cx.subscribe(buffer, |this, buffer, event, cx| {
4193 this.on_buffer_event(buffer, event, cx);
4194 })
4195 .detach();
4196
4197 self.detect_language_for_buffer(buffer, cx);
4198 if let Some(local) = self.as_local_mut() {
4199 local.initialize_buffer(buffer, cx);
4200 }
4201
4202 Ok(())
4203 }
4204
4205 pub(crate) fn register_buffer_with_language_servers(
4206 &mut self,
4207 buffer: &Entity<Buffer>,
4208 only_register_servers: HashSet<LanguageServerSelector>,
4209 ignore_refcounts: bool,
4210 cx: &mut Context<Self>,
4211 ) -> OpenLspBufferHandle {
4212 let buffer_id = buffer.read(cx).remote_id();
4213 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4214 if let Some(local) = self.as_local_mut() {
4215 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4216 if !ignore_refcounts {
4217 *refcount += 1;
4218 }
4219
4220 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4221 // 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
4222 // 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
4223 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4224 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4225 return handle;
4226 };
4227 if !file.is_local() {
4228 return handle;
4229 }
4230
4231 if ignore_refcounts || *refcount == 1 {
4232 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4233 }
4234 if !ignore_refcounts {
4235 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4236 let refcount = {
4237 let local = lsp_store.as_local_mut().unwrap();
4238 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4239 debug_panic!("bad refcounting");
4240 return;
4241 };
4242
4243 *refcount -= 1;
4244 *refcount
4245 };
4246 if refcount == 0 {
4247 lsp_store.lsp_data.remove(&buffer_id);
4248 let local = lsp_store.as_local_mut().unwrap();
4249 local.registered_buffers.remove(&buffer_id);
4250
4251 local.buffers_opened_in_servers.remove(&buffer_id);
4252 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4253 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4254
4255 let buffer_abs_path = file.abs_path(cx);
4256 for (_, buffer_pull_diagnostics_result_ids) in
4257 &mut local.buffer_pull_diagnostics_result_ids
4258 {
4259 buffer_pull_diagnostics_result_ids.retain(
4260 |_, buffer_result_ids| {
4261 buffer_result_ids.remove(&buffer_abs_path);
4262 !buffer_result_ids.is_empty()
4263 },
4264 );
4265 }
4266
4267 let diagnostic_updates = local
4268 .language_servers
4269 .keys()
4270 .cloned()
4271 .map(|server_id| DocumentDiagnosticsUpdate {
4272 diagnostics: DocumentDiagnostics {
4273 document_abs_path: buffer_abs_path.clone(),
4274 version: None,
4275 diagnostics: Vec::new(),
4276 },
4277 result_id: None,
4278 registration_id: None,
4279 server_id: server_id,
4280 disk_based_sources: Cow::Borrowed(&[]),
4281 })
4282 .collect::<Vec<_>>();
4283
4284 lsp_store
4285 .merge_diagnostic_entries(
4286 diagnostic_updates,
4287 |_, diagnostic, _| {
4288 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4289 },
4290 cx,
4291 )
4292 .context("Clearing diagnostics for the closed buffer")
4293 .log_err();
4294 }
4295 }
4296 })
4297 .detach();
4298 }
4299 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4300 let buffer_id = buffer.read(cx).remote_id().to_proto();
4301 cx.background_spawn(async move {
4302 upstream_client
4303 .request(proto::RegisterBufferWithLanguageServers {
4304 project_id: upstream_project_id,
4305 buffer_id,
4306 only_servers: only_register_servers
4307 .into_iter()
4308 .map(|selector| {
4309 let selector = match selector {
4310 LanguageServerSelector::Id(language_server_id) => {
4311 proto::language_server_selector::Selector::ServerId(
4312 language_server_id.to_proto(),
4313 )
4314 }
4315 LanguageServerSelector::Name(language_server_name) => {
4316 proto::language_server_selector::Selector::Name(
4317 language_server_name.to_string(),
4318 )
4319 }
4320 };
4321 proto::LanguageServerSelector {
4322 selector: Some(selector),
4323 }
4324 })
4325 .collect(),
4326 })
4327 .await
4328 })
4329 .detach();
4330 } else {
4331 // Our remote connection got closed
4332 }
4333 handle
4334 }
4335
4336 fn maintain_buffer_languages(
4337 languages: Arc<LanguageRegistry>,
4338 cx: &mut Context<Self>,
4339 ) -> Task<()> {
4340 let mut subscription = languages.subscribe();
4341 let mut prev_reload_count = languages.reload_count();
4342 cx.spawn(async move |this, cx| {
4343 while let Some(()) = subscription.next().await {
4344 if let Some(this) = this.upgrade() {
4345 // If the language registry has been reloaded, then remove and
4346 // re-assign the languages on all open buffers.
4347 let reload_count = languages.reload_count();
4348 if reload_count > prev_reload_count {
4349 prev_reload_count = reload_count;
4350 this.update(cx, |this, cx| {
4351 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4352 for buffer in buffer_store.buffers() {
4353 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4354 {
4355 buffer.update(cx, |buffer, cx| {
4356 buffer.set_language_async(None, cx)
4357 });
4358 if let Some(local) = this.as_local_mut() {
4359 local.reset_buffer(&buffer, &f, cx);
4360
4361 if local
4362 .registered_buffers
4363 .contains_key(&buffer.read(cx).remote_id())
4364 && let Some(file_url) =
4365 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4366 {
4367 local.unregister_buffer_from_language_servers(
4368 &buffer, &file_url, cx,
4369 );
4370 }
4371 }
4372 }
4373 }
4374 });
4375 })
4376 .ok();
4377 }
4378
4379 this.update(cx, |this, cx| {
4380 let mut plain_text_buffers = Vec::new();
4381 let mut buffers_with_unknown_injections = Vec::new();
4382 for handle in this.buffer_store.read(cx).buffers() {
4383 let buffer = handle.read(cx);
4384 if buffer.language().is_none()
4385 || buffer.language() == Some(&*language::PLAIN_TEXT)
4386 {
4387 plain_text_buffers.push(handle);
4388 } else if buffer.contains_unknown_injections() {
4389 buffers_with_unknown_injections.push(handle);
4390 }
4391 }
4392
4393 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4394 // and reused later in the invisible worktrees.
4395 plain_text_buffers.sort_by_key(|buffer| {
4396 Reverse(
4397 File::from_dyn(buffer.read(cx).file())
4398 .map(|file| file.worktree.read(cx).is_visible()),
4399 )
4400 });
4401
4402 for buffer in plain_text_buffers {
4403 this.detect_language_for_buffer(&buffer, cx);
4404 if let Some(local) = this.as_local_mut() {
4405 local.initialize_buffer(&buffer, cx);
4406 if local
4407 .registered_buffers
4408 .contains_key(&buffer.read(cx).remote_id())
4409 {
4410 local.register_buffer_with_language_servers(
4411 &buffer,
4412 HashSet::default(),
4413 cx,
4414 );
4415 }
4416 }
4417 }
4418
4419 for buffer in buffers_with_unknown_injections {
4420 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4421 }
4422 })
4423 .ok();
4424 }
4425 }
4426 })
4427 }
4428
4429 fn detect_language_for_buffer(
4430 &mut self,
4431 buffer_handle: &Entity<Buffer>,
4432 cx: &mut Context<Self>,
4433 ) -> Option<language::AvailableLanguage> {
4434 // If the buffer has a language, set it and start the language server if we haven't already.
4435 let buffer = buffer_handle.read(cx);
4436 let file = buffer.file()?;
4437
4438 let content = buffer.as_rope();
4439 let available_language = self.languages.language_for_file(file, Some(content), cx);
4440 if let Some(available_language) = &available_language {
4441 if let Some(Ok(Ok(new_language))) = self
4442 .languages
4443 .load_language(available_language)
4444 .now_or_never()
4445 {
4446 self.set_language_for_buffer(buffer_handle, new_language, cx);
4447 }
4448 } else {
4449 cx.emit(LspStoreEvent::LanguageDetected {
4450 buffer: buffer_handle.clone(),
4451 new_language: None,
4452 });
4453 }
4454
4455 available_language
4456 }
4457
4458 pub(crate) fn set_language_for_buffer(
4459 &mut self,
4460 buffer_entity: &Entity<Buffer>,
4461 new_language: Arc<Language>,
4462 cx: &mut Context<Self>,
4463 ) {
4464 let buffer = buffer_entity.read(cx);
4465 let buffer_file = buffer.file().cloned();
4466 let buffer_id = buffer.remote_id();
4467 if let Some(local_store) = self.as_local_mut()
4468 && local_store.registered_buffers.contains_key(&buffer_id)
4469 && let Some(abs_path) =
4470 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4471 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4472 {
4473 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4474 }
4475 buffer_entity.update(cx, |buffer, cx| {
4476 if buffer
4477 .language()
4478 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4479 {
4480 buffer.set_language_async(Some(new_language.clone()), cx);
4481 }
4482 });
4483
4484 let settings =
4485 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4486 let buffer_file = File::from_dyn(buffer_file.as_ref());
4487
4488 let worktree_id = if let Some(file) = buffer_file {
4489 let worktree = file.worktree.clone();
4490
4491 if let Some(local) = self.as_local_mut()
4492 && local.registered_buffers.contains_key(&buffer_id)
4493 {
4494 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4495 }
4496 Some(worktree.read(cx).id())
4497 } else {
4498 None
4499 };
4500
4501 if settings.prettier.allowed
4502 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4503 {
4504 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4505 if let Some(prettier_store) = prettier_store {
4506 prettier_store.update(cx, |prettier_store, cx| {
4507 prettier_store.install_default_prettier(
4508 worktree_id,
4509 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4510 cx,
4511 )
4512 })
4513 }
4514 }
4515
4516 cx.emit(LspStoreEvent::LanguageDetected {
4517 buffer: buffer_entity.clone(),
4518 new_language: Some(new_language),
4519 })
4520 }
4521
4522 pub fn buffer_store(&self) -> Entity<BufferStore> {
4523 self.buffer_store.clone()
4524 }
4525
4526 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4527 self.active_entry = active_entry;
4528 }
4529
4530 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4531 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4532 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4533 {
4534 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4535 summaries
4536 .iter()
4537 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4538 });
4539 if let Some(summary) = summaries.next() {
4540 client
4541 .send(proto::UpdateDiagnosticSummary {
4542 project_id: downstream_project_id,
4543 worktree_id: worktree.id().to_proto(),
4544 summary: Some(summary),
4545 more_summaries: summaries.collect(),
4546 })
4547 .log_err();
4548 }
4549 }
4550 }
4551
4552 fn is_capable_for_proto_request<R>(
4553 &self,
4554 buffer: &Entity<Buffer>,
4555 request: &R,
4556 cx: &App,
4557 ) -> bool
4558 where
4559 R: LspCommand,
4560 {
4561 self.check_if_capable_for_proto_request(
4562 buffer,
4563 |capabilities| {
4564 request.check_capabilities(AdapterServerCapabilities {
4565 server_capabilities: capabilities.clone(),
4566 code_action_kinds: None,
4567 })
4568 },
4569 cx,
4570 )
4571 }
4572
4573 fn check_if_capable_for_proto_request<F>(
4574 &self,
4575 buffer: &Entity<Buffer>,
4576 check: F,
4577 cx: &App,
4578 ) -> bool
4579 where
4580 F: FnMut(&lsp::ServerCapabilities) -> bool,
4581 {
4582 let Some(language) = buffer.read(cx).language().cloned() else {
4583 return false;
4584 };
4585 let relevant_language_servers = self
4586 .languages
4587 .lsp_adapters(&language.name())
4588 .into_iter()
4589 .map(|lsp_adapter| lsp_adapter.name())
4590 .collect::<HashSet<_>>();
4591 self.language_server_statuses
4592 .iter()
4593 .filter_map(|(server_id, server_status)| {
4594 relevant_language_servers
4595 .contains(&server_status.name)
4596 .then_some(server_id)
4597 })
4598 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4599 .any(check)
4600 }
4601
4602 fn all_capable_for_proto_request<F>(
4603 &self,
4604 buffer: &Entity<Buffer>,
4605 mut check: F,
4606 cx: &App,
4607 ) -> Vec<lsp::LanguageServerId>
4608 where
4609 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4610 {
4611 let Some(language) = buffer.read(cx).language().cloned() else {
4612 return Vec::default();
4613 };
4614 let relevant_language_servers = self
4615 .languages
4616 .lsp_adapters(&language.name())
4617 .into_iter()
4618 .map(|lsp_adapter| lsp_adapter.name())
4619 .collect::<HashSet<_>>();
4620 self.language_server_statuses
4621 .iter()
4622 .filter_map(|(server_id, server_status)| {
4623 relevant_language_servers
4624 .contains(&server_status.name)
4625 .then_some((server_id, &server_status.name))
4626 })
4627 .filter_map(|(server_id, server_name)| {
4628 self.lsp_server_capabilities
4629 .get(server_id)
4630 .map(|c| (server_id, server_name, c))
4631 })
4632 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4633 .map(|(server_id, _, _)| *server_id)
4634 .collect()
4635 }
4636
4637 pub fn request_lsp<R>(
4638 &mut self,
4639 buffer: Entity<Buffer>,
4640 server: LanguageServerToQuery,
4641 request: R,
4642 cx: &mut Context<Self>,
4643 ) -> Task<Result<R::Response>>
4644 where
4645 R: LspCommand,
4646 <R::LspRequest as lsp::request::Request>::Result: Send,
4647 <R::LspRequest as lsp::request::Request>::Params: Send,
4648 {
4649 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4650 return self.send_lsp_proto_request(
4651 buffer,
4652 upstream_client,
4653 upstream_project_id,
4654 request,
4655 cx,
4656 );
4657 }
4658
4659 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4660 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4661 local
4662 .language_servers_for_buffer(buffer, cx)
4663 .find(|(_, server)| {
4664 request.check_capabilities(server.adapter_server_capabilities())
4665 })
4666 .map(|(_, server)| server.clone())
4667 }),
4668 LanguageServerToQuery::Other(id) => self
4669 .language_server_for_local_buffer(buffer, id, cx)
4670 .and_then(|(_, server)| {
4671 request
4672 .check_capabilities(server.adapter_server_capabilities())
4673 .then(|| Arc::clone(server))
4674 }),
4675 }) else {
4676 return Task::ready(Ok(Default::default()));
4677 };
4678
4679 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4680
4681 let Some(file) = file else {
4682 return Task::ready(Ok(Default::default()));
4683 };
4684
4685 let lsp_params = match request.to_lsp_params_or_response(
4686 &file.abs_path(cx),
4687 buffer.read(cx),
4688 &language_server,
4689 cx,
4690 ) {
4691 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4692 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4693 Err(err) => {
4694 let message = format!(
4695 "{} via {} failed: {}",
4696 request.display_name(),
4697 language_server.name(),
4698 err
4699 );
4700 // rust-analyzer likes to error with this when its still loading up
4701 if !message.ends_with("content modified") {
4702 log::warn!("{message}");
4703 }
4704 return Task::ready(Err(anyhow!(message)));
4705 }
4706 };
4707
4708 let status = request.status();
4709 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4710 return Task::ready(Ok(Default::default()));
4711 }
4712 cx.spawn(async move |this, cx| {
4713 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4714
4715 let id = lsp_request.id();
4716 let _cleanup = if status.is_some() {
4717 cx.update(|cx| {
4718 this.update(cx, |this, cx| {
4719 this.on_lsp_work_start(
4720 language_server.server_id(),
4721 ProgressToken::Number(id),
4722 LanguageServerProgress {
4723 is_disk_based_diagnostics_progress: false,
4724 is_cancellable: false,
4725 title: None,
4726 message: status.clone(),
4727 percentage: None,
4728 last_update_at: cx.background_executor().now(),
4729 },
4730 cx,
4731 );
4732 })
4733 })
4734 .log_err();
4735
4736 Some(defer(|| {
4737 cx.update(|cx| {
4738 this.update(cx, |this, cx| {
4739 this.on_lsp_work_end(
4740 language_server.server_id(),
4741 ProgressToken::Number(id),
4742 cx,
4743 );
4744 })
4745 })
4746 .log_err();
4747 }))
4748 } else {
4749 None
4750 };
4751
4752 let result = lsp_request.await.into_response();
4753
4754 let response = result.map_err(|err| {
4755 let message = format!(
4756 "{} via {} failed: {}",
4757 request.display_name(),
4758 language_server.name(),
4759 err
4760 );
4761 // rust-analyzer likes to error with this when its still loading up
4762 if !message.ends_with("content modified") {
4763 log::warn!("{message}");
4764 }
4765 anyhow::anyhow!(message)
4766 })?;
4767
4768 request
4769 .response_from_lsp(
4770 response,
4771 this.upgrade().context("no app context")?,
4772 buffer,
4773 language_server.server_id(),
4774 cx.clone(),
4775 )
4776 .await
4777 })
4778 }
4779
4780 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4781 let mut language_formatters_to_check = Vec::new();
4782 for buffer in self.buffer_store.read(cx).buffers() {
4783 let buffer = buffer.read(cx);
4784 let buffer_file = File::from_dyn(buffer.file());
4785 let buffer_language = buffer.language();
4786 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4787 if buffer_language.is_some() {
4788 language_formatters_to_check.push((
4789 buffer_file.map(|f| f.worktree_id(cx)),
4790 settings.into_owned(),
4791 ));
4792 }
4793 }
4794
4795 self.request_workspace_config_refresh();
4796
4797 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4798 prettier_store.update(cx, |prettier_store, cx| {
4799 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4800 })
4801 }
4802
4803 cx.notify();
4804 }
4805
4806 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4807 let buffer_store = self.buffer_store.clone();
4808 let Some(local) = self.as_local_mut() else {
4809 return;
4810 };
4811 let mut adapters = BTreeMap::default();
4812 let get_adapter = {
4813 let languages = local.languages.clone();
4814 let environment = local.environment.clone();
4815 let weak = local.weak.clone();
4816 let worktree_store = local.worktree_store.clone();
4817 let http_client = local.http_client.clone();
4818 let fs = local.fs.clone();
4819 move |worktree_id, cx: &mut App| {
4820 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4821 Some(LocalLspAdapterDelegate::new(
4822 languages.clone(),
4823 &environment,
4824 weak.clone(),
4825 &worktree,
4826 http_client.clone(),
4827 fs.clone(),
4828 cx,
4829 ))
4830 }
4831 };
4832
4833 let mut messages_to_report = Vec::new();
4834 let (new_tree, to_stop) = {
4835 let mut rebase = local.lsp_tree.rebase();
4836 let buffers = buffer_store
4837 .read(cx)
4838 .buffers()
4839 .filter_map(|buffer| {
4840 let raw_buffer = buffer.read(cx);
4841 if !local
4842 .registered_buffers
4843 .contains_key(&raw_buffer.remote_id())
4844 {
4845 return None;
4846 }
4847 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4848 let language = raw_buffer.language().cloned()?;
4849 Some((file, language, raw_buffer.remote_id()))
4850 })
4851 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4852 for (file, language, buffer_id) in buffers {
4853 let worktree_id = file.worktree_id(cx);
4854 let Some(worktree) = local
4855 .worktree_store
4856 .read(cx)
4857 .worktree_for_id(worktree_id, cx)
4858 else {
4859 continue;
4860 };
4861
4862 if let Some((_, apply)) = local.reuse_existing_language_server(
4863 rebase.server_tree(),
4864 &worktree,
4865 &language.name(),
4866 cx,
4867 ) {
4868 (apply)(rebase.server_tree());
4869 } else if let Some(lsp_delegate) = adapters
4870 .entry(worktree_id)
4871 .or_insert_with(|| get_adapter(worktree_id, cx))
4872 .clone()
4873 {
4874 let delegate =
4875 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4876 let path = file
4877 .path()
4878 .parent()
4879 .map(Arc::from)
4880 .unwrap_or_else(|| file.path().clone());
4881 let worktree_path = ProjectPath { worktree_id, path };
4882 let abs_path = file.abs_path(cx);
4883 let nodes = rebase
4884 .walk(
4885 worktree_path,
4886 language.name(),
4887 language.manifest(),
4888 delegate.clone(),
4889 cx,
4890 )
4891 .collect::<Vec<_>>();
4892 for node in nodes {
4893 let server_id = node.server_id_or_init(|disposition| {
4894 let path = &disposition.path;
4895 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4896 let key = LanguageServerSeed {
4897 worktree_id,
4898 name: disposition.server_name.clone(),
4899 settings: disposition.settings.clone(),
4900 toolchain: local.toolchain_store.read(cx).active_toolchain(
4901 path.worktree_id,
4902 &path.path,
4903 language.name(),
4904 ),
4905 };
4906 local.language_server_ids.remove(&key);
4907
4908 let server_id = local.get_or_insert_language_server(
4909 &worktree,
4910 lsp_delegate.clone(),
4911 disposition,
4912 &language.name(),
4913 cx,
4914 );
4915 if let Some(state) = local.language_servers.get(&server_id)
4916 && let Ok(uri) = uri
4917 {
4918 state.add_workspace_folder(uri);
4919 };
4920 server_id
4921 });
4922
4923 if let Some(language_server_id) = server_id {
4924 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4925 language_server_id,
4926 name: node.name(),
4927 message:
4928 proto::update_language_server::Variant::RegisteredForBuffer(
4929 proto::RegisteredForBuffer {
4930 buffer_abs_path: abs_path
4931 .to_string_lossy()
4932 .into_owned(),
4933 buffer_id: buffer_id.to_proto(),
4934 },
4935 ),
4936 });
4937 }
4938 }
4939 } else {
4940 continue;
4941 }
4942 }
4943 rebase.finish()
4944 };
4945 for message in messages_to_report {
4946 cx.emit(message);
4947 }
4948 local.lsp_tree = new_tree;
4949 for (id, _) in to_stop {
4950 self.stop_local_language_server(id, cx).detach();
4951 }
4952 }
4953
4954 pub fn apply_code_action(
4955 &self,
4956 buffer_handle: Entity<Buffer>,
4957 mut action: CodeAction,
4958 push_to_history: bool,
4959 cx: &mut Context<Self>,
4960 ) -> Task<Result<ProjectTransaction>> {
4961 if let Some((upstream_client, project_id)) = self.upstream_client() {
4962 let request = proto::ApplyCodeAction {
4963 project_id,
4964 buffer_id: buffer_handle.read(cx).remote_id().into(),
4965 action: Some(Self::serialize_code_action(&action)),
4966 };
4967 let buffer_store = self.buffer_store();
4968 cx.spawn(async move |_, cx| {
4969 let response = upstream_client
4970 .request(request)
4971 .await?
4972 .transaction
4973 .context("missing transaction")?;
4974
4975 buffer_store
4976 .update(cx, |buffer_store, cx| {
4977 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4978 })?
4979 .await
4980 })
4981 } else if self.mode.is_local() {
4982 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4983 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4984 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4985 }) else {
4986 return Task::ready(Ok(ProjectTransaction::default()));
4987 };
4988 cx.spawn(async move |this, cx| {
4989 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4990 .await
4991 .context("resolving a code action")?;
4992 if let Some(edit) = action.lsp_action.edit()
4993 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4994 return LocalLspStore::deserialize_workspace_edit(
4995 this.upgrade().context("no app present")?,
4996 edit.clone(),
4997 push_to_history,
4998
4999 lang_server.clone(),
5000 cx,
5001 )
5002 .await;
5003 }
5004
5005 if let Some(command) = action.lsp_action.command() {
5006 let server_capabilities = lang_server.capabilities();
5007 let available_commands = server_capabilities
5008 .execute_command_provider
5009 .as_ref()
5010 .map(|options| options.commands.as_slice())
5011 .unwrap_or_default();
5012 if available_commands.contains(&command.command) {
5013 this.update(cx, |this, _| {
5014 this.as_local_mut()
5015 .unwrap()
5016 .last_workspace_edits_by_language_server
5017 .remove(&lang_server.server_id());
5018 })?;
5019
5020 let _result = lang_server
5021 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5022 command: command.command.clone(),
5023 arguments: command.arguments.clone().unwrap_or_default(),
5024 ..lsp::ExecuteCommandParams::default()
5025 })
5026 .await.into_response()
5027 .context("execute command")?;
5028
5029 return this.update(cx, |this, _| {
5030 this.as_local_mut()
5031 .unwrap()
5032 .last_workspace_edits_by_language_server
5033 .remove(&lang_server.server_id())
5034 .unwrap_or_default()
5035 });
5036 } else {
5037 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5038 }
5039 }
5040
5041 Ok(ProjectTransaction::default())
5042 })
5043 } else {
5044 Task::ready(Err(anyhow!("no upstream client and not local")))
5045 }
5046 }
5047
5048 pub fn apply_code_action_kind(
5049 &mut self,
5050 buffers: HashSet<Entity<Buffer>>,
5051 kind: CodeActionKind,
5052 push_to_history: bool,
5053 cx: &mut Context<Self>,
5054 ) -> Task<anyhow::Result<ProjectTransaction>> {
5055 if self.as_local().is_some() {
5056 cx.spawn(async move |lsp_store, cx| {
5057 let buffers = buffers.into_iter().collect::<Vec<_>>();
5058 let result = LocalLspStore::execute_code_action_kind_locally(
5059 lsp_store.clone(),
5060 buffers,
5061 kind,
5062 push_to_history,
5063 cx,
5064 )
5065 .await;
5066 lsp_store.update(cx, |lsp_store, _| {
5067 lsp_store.update_last_formatting_failure(&result);
5068 })?;
5069 result
5070 })
5071 } else if let Some((client, project_id)) = self.upstream_client() {
5072 let buffer_store = self.buffer_store();
5073 cx.spawn(async move |lsp_store, cx| {
5074 let result = client
5075 .request(proto::ApplyCodeActionKind {
5076 project_id,
5077 kind: kind.as_str().to_owned(),
5078 buffer_ids: buffers
5079 .iter()
5080 .map(|buffer| {
5081 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5082 })
5083 .collect::<Result<_>>()?,
5084 })
5085 .await
5086 .and_then(|result| result.transaction.context("missing transaction"));
5087 lsp_store.update(cx, |lsp_store, _| {
5088 lsp_store.update_last_formatting_failure(&result);
5089 })?;
5090
5091 let transaction_response = result?;
5092 buffer_store
5093 .update(cx, |buffer_store, cx| {
5094 buffer_store.deserialize_project_transaction(
5095 transaction_response,
5096 push_to_history,
5097 cx,
5098 )
5099 })?
5100 .await
5101 })
5102 } else {
5103 Task::ready(Ok(ProjectTransaction::default()))
5104 }
5105 }
5106
5107 pub fn resolved_hint(
5108 &mut self,
5109 buffer_id: BufferId,
5110 id: InlayId,
5111 cx: &mut Context<Self>,
5112 ) -> Option<ResolvedHint> {
5113 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5114
5115 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5116 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5117 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5118 let (server_id, resolve_data) = match &hint.resolve_state {
5119 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5120 ResolveState::Resolving => {
5121 return Some(ResolvedHint::Resolving(
5122 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5123 ));
5124 }
5125 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5126 };
5127
5128 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5129 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5130 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5131 id,
5132 cx.spawn(async move |lsp_store, cx| {
5133 let resolved_hint = resolve_task.await;
5134 lsp_store
5135 .update(cx, |lsp_store, _| {
5136 if let Some(old_inlay_hint) = lsp_store
5137 .lsp_data
5138 .get_mut(&buffer_id)
5139 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5140 {
5141 match resolved_hint {
5142 Ok(resolved_hint) => {
5143 *old_inlay_hint = resolved_hint;
5144 }
5145 Err(e) => {
5146 old_inlay_hint.resolve_state =
5147 ResolveState::CanResolve(server_id, resolve_data);
5148 log::error!("Inlay hint resolve failed: {e:#}");
5149 }
5150 }
5151 }
5152 })
5153 .ok();
5154 })
5155 .shared(),
5156 );
5157 debug_assert!(
5158 previous_task.is_none(),
5159 "Did not change hint's resolve state after spawning its resolve"
5160 );
5161 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5162 None
5163 }
5164
5165 fn resolve_inlay_hint(
5166 &self,
5167 mut hint: InlayHint,
5168 buffer: Entity<Buffer>,
5169 server_id: LanguageServerId,
5170 cx: &mut Context<Self>,
5171 ) -> Task<anyhow::Result<InlayHint>> {
5172 if let Some((upstream_client, project_id)) = self.upstream_client() {
5173 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5174 {
5175 hint.resolve_state = ResolveState::Resolved;
5176 return Task::ready(Ok(hint));
5177 }
5178 let request = proto::ResolveInlayHint {
5179 project_id,
5180 buffer_id: buffer.read(cx).remote_id().into(),
5181 language_server_id: server_id.0 as u64,
5182 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5183 };
5184 cx.background_spawn(async move {
5185 let response = upstream_client
5186 .request(request)
5187 .await
5188 .context("inlay hints proto request")?;
5189 match response.hint {
5190 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5191 .context("inlay hints proto resolve response conversion"),
5192 None => Ok(hint),
5193 }
5194 })
5195 } else {
5196 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5197 self.language_server_for_local_buffer(buffer, server_id, cx)
5198 .map(|(_, server)| server.clone())
5199 }) else {
5200 return Task::ready(Ok(hint));
5201 };
5202 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5203 return Task::ready(Ok(hint));
5204 }
5205 let buffer_snapshot = buffer.read(cx).snapshot();
5206 cx.spawn(async move |_, cx| {
5207 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5208 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5209 );
5210 let resolved_hint = resolve_task
5211 .await
5212 .into_response()
5213 .context("inlay hint resolve LSP request")?;
5214 let resolved_hint = InlayHints::lsp_to_project_hint(
5215 resolved_hint,
5216 &buffer,
5217 server_id,
5218 ResolveState::Resolved,
5219 false,
5220 cx,
5221 )
5222 .await?;
5223 Ok(resolved_hint)
5224 })
5225 }
5226 }
5227
5228 pub fn resolve_color_presentation(
5229 &mut self,
5230 mut color: DocumentColor,
5231 buffer: Entity<Buffer>,
5232 server_id: LanguageServerId,
5233 cx: &mut Context<Self>,
5234 ) -> Task<Result<DocumentColor>> {
5235 if color.resolved {
5236 return Task::ready(Ok(color));
5237 }
5238
5239 if let Some((upstream_client, project_id)) = self.upstream_client() {
5240 let start = color.lsp_range.start;
5241 let end = color.lsp_range.end;
5242 let request = proto::GetColorPresentation {
5243 project_id,
5244 server_id: server_id.to_proto(),
5245 buffer_id: buffer.read(cx).remote_id().into(),
5246 color: Some(proto::ColorInformation {
5247 red: color.color.red,
5248 green: color.color.green,
5249 blue: color.color.blue,
5250 alpha: color.color.alpha,
5251 lsp_range_start: Some(proto::PointUtf16 {
5252 row: start.line,
5253 column: start.character,
5254 }),
5255 lsp_range_end: Some(proto::PointUtf16 {
5256 row: end.line,
5257 column: end.character,
5258 }),
5259 }),
5260 };
5261 cx.background_spawn(async move {
5262 let response = upstream_client
5263 .request(request)
5264 .await
5265 .context("color presentation proto request")?;
5266 color.resolved = true;
5267 color.color_presentations = response
5268 .presentations
5269 .into_iter()
5270 .map(|presentation| ColorPresentation {
5271 label: SharedString::from(presentation.label),
5272 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5273 additional_text_edits: presentation
5274 .additional_text_edits
5275 .into_iter()
5276 .filter_map(deserialize_lsp_edit)
5277 .collect(),
5278 })
5279 .collect();
5280 Ok(color)
5281 })
5282 } else {
5283 let path = match buffer
5284 .update(cx, |buffer, cx| {
5285 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5286 })
5287 .context("buffer with the missing path")
5288 {
5289 Ok(path) => path,
5290 Err(e) => return Task::ready(Err(e)),
5291 };
5292 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5293 self.language_server_for_local_buffer(buffer, server_id, cx)
5294 .map(|(_, server)| server.clone())
5295 }) else {
5296 return Task::ready(Ok(color));
5297 };
5298 cx.background_spawn(async move {
5299 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5300 lsp::ColorPresentationParams {
5301 text_document: make_text_document_identifier(&path)?,
5302 color: color.color,
5303 range: color.lsp_range,
5304 work_done_progress_params: Default::default(),
5305 partial_result_params: Default::default(),
5306 },
5307 );
5308 color.color_presentations = resolve_task
5309 .await
5310 .into_response()
5311 .context("color presentation resolve LSP request")?
5312 .into_iter()
5313 .map(|presentation| ColorPresentation {
5314 label: SharedString::from(presentation.label),
5315 text_edit: presentation.text_edit,
5316 additional_text_edits: presentation
5317 .additional_text_edits
5318 .unwrap_or_default(),
5319 })
5320 .collect();
5321 color.resolved = true;
5322 Ok(color)
5323 })
5324 }
5325 }
5326
5327 pub(crate) fn linked_edits(
5328 &mut self,
5329 buffer: &Entity<Buffer>,
5330 position: Anchor,
5331 cx: &mut Context<Self>,
5332 ) -> Task<Result<Vec<Range<Anchor>>>> {
5333 let snapshot = buffer.read(cx).snapshot();
5334 let scope = snapshot.language_scope_at(position);
5335 let Some(server_id) = self
5336 .as_local()
5337 .and_then(|local| {
5338 buffer.update(cx, |buffer, cx| {
5339 local
5340 .language_servers_for_buffer(buffer, cx)
5341 .filter(|(_, server)| {
5342 LinkedEditingRange::check_server_capabilities(server.capabilities())
5343 })
5344 .filter(|(adapter, _)| {
5345 scope
5346 .as_ref()
5347 .map(|scope| scope.language_allowed(&adapter.name))
5348 .unwrap_or(true)
5349 })
5350 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5351 .next()
5352 })
5353 })
5354 .or_else(|| {
5355 self.upstream_client()
5356 .is_some()
5357 .then_some(LanguageServerToQuery::FirstCapable)
5358 })
5359 .filter(|_| {
5360 maybe!({
5361 let language = buffer.read(cx).language_at(position)?;
5362 Some(
5363 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5364 .linked_edits,
5365 )
5366 }) == Some(true)
5367 })
5368 else {
5369 return Task::ready(Ok(Vec::new()));
5370 };
5371
5372 self.request_lsp(
5373 buffer.clone(),
5374 server_id,
5375 LinkedEditingRange { position },
5376 cx,
5377 )
5378 }
5379
5380 fn apply_on_type_formatting(
5381 &mut self,
5382 buffer: Entity<Buffer>,
5383 position: Anchor,
5384 trigger: String,
5385 cx: &mut Context<Self>,
5386 ) -> Task<Result<Option<Transaction>>> {
5387 if let Some((client, project_id)) = self.upstream_client() {
5388 if !self.check_if_capable_for_proto_request(
5389 &buffer,
5390 |capabilities| {
5391 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5392 },
5393 cx,
5394 ) {
5395 return Task::ready(Ok(None));
5396 }
5397 let request = proto::OnTypeFormatting {
5398 project_id,
5399 buffer_id: buffer.read(cx).remote_id().into(),
5400 position: Some(serialize_anchor(&position)),
5401 trigger,
5402 version: serialize_version(&buffer.read(cx).version()),
5403 };
5404 cx.background_spawn(async move {
5405 client
5406 .request(request)
5407 .await?
5408 .transaction
5409 .map(language::proto::deserialize_transaction)
5410 .transpose()
5411 })
5412 } else if let Some(local) = self.as_local_mut() {
5413 let buffer_id = buffer.read(cx).remote_id();
5414 local.buffers_being_formatted.insert(buffer_id);
5415 cx.spawn(async move |this, cx| {
5416 let _cleanup = defer({
5417 let this = this.clone();
5418 let mut cx = cx.clone();
5419 move || {
5420 this.update(&mut cx, |this, _| {
5421 if let Some(local) = this.as_local_mut() {
5422 local.buffers_being_formatted.remove(&buffer_id);
5423 }
5424 })
5425 .ok();
5426 }
5427 });
5428
5429 buffer
5430 .update(cx, |buffer, _| {
5431 buffer.wait_for_edits(Some(position.timestamp))
5432 })?
5433 .await?;
5434 this.update(cx, |this, cx| {
5435 let position = position.to_point_utf16(buffer.read(cx));
5436 this.on_type_format(buffer, position, trigger, false, cx)
5437 })?
5438 .await
5439 })
5440 } else {
5441 Task::ready(Err(anyhow!("No upstream client or local language server")))
5442 }
5443 }
5444
5445 pub fn on_type_format<T: ToPointUtf16>(
5446 &mut self,
5447 buffer: Entity<Buffer>,
5448 position: T,
5449 trigger: String,
5450 push_to_history: bool,
5451 cx: &mut Context<Self>,
5452 ) -> Task<Result<Option<Transaction>>> {
5453 let position = position.to_point_utf16(buffer.read(cx));
5454 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5455 }
5456
5457 fn on_type_format_impl(
5458 &mut self,
5459 buffer: Entity<Buffer>,
5460 position: PointUtf16,
5461 trigger: String,
5462 push_to_history: bool,
5463 cx: &mut Context<Self>,
5464 ) -> Task<Result<Option<Transaction>>> {
5465 let options = buffer.update(cx, |buffer, cx| {
5466 lsp_command::lsp_formatting_options(
5467 language_settings(
5468 buffer.language_at(position).map(|l| l.name()),
5469 buffer.file(),
5470 cx,
5471 )
5472 .as_ref(),
5473 )
5474 });
5475
5476 cx.spawn(async move |this, cx| {
5477 if let Some(waiter) =
5478 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5479 {
5480 waiter.await?;
5481 }
5482 cx.update(|cx| {
5483 this.update(cx, |this, cx| {
5484 this.request_lsp(
5485 buffer.clone(),
5486 LanguageServerToQuery::FirstCapable,
5487 OnTypeFormatting {
5488 position,
5489 trigger,
5490 options,
5491 push_to_history,
5492 },
5493 cx,
5494 )
5495 })
5496 })??
5497 .await
5498 })
5499 }
5500
5501 pub fn definitions(
5502 &mut self,
5503 buffer: &Entity<Buffer>,
5504 position: PointUtf16,
5505 cx: &mut Context<Self>,
5506 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5507 if let Some((upstream_client, project_id)) = self.upstream_client() {
5508 let request = GetDefinitions { position };
5509 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5510 return Task::ready(Ok(None));
5511 }
5512 let request_task = upstream_client.request_lsp(
5513 project_id,
5514 None,
5515 LSP_REQUEST_TIMEOUT,
5516 cx.background_executor().clone(),
5517 request.to_proto(project_id, buffer.read(cx)),
5518 );
5519 let buffer = buffer.clone();
5520 cx.spawn(async move |weak_lsp_store, cx| {
5521 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5522 return Ok(None);
5523 };
5524 let Some(responses) = request_task.await? else {
5525 return Ok(None);
5526 };
5527 let actions = join_all(responses.payload.into_iter().map(|response| {
5528 GetDefinitions { position }.response_from_proto(
5529 response.response,
5530 lsp_store.clone(),
5531 buffer.clone(),
5532 cx.clone(),
5533 )
5534 }))
5535 .await;
5536
5537 Ok(Some(
5538 actions
5539 .into_iter()
5540 .collect::<Result<Vec<Vec<_>>>>()?
5541 .into_iter()
5542 .flatten()
5543 .dedup()
5544 .collect(),
5545 ))
5546 })
5547 } else {
5548 let definitions_task = self.request_multiple_lsp_locally(
5549 buffer,
5550 Some(position),
5551 GetDefinitions { position },
5552 cx,
5553 );
5554 cx.background_spawn(async move {
5555 Ok(Some(
5556 definitions_task
5557 .await
5558 .into_iter()
5559 .flat_map(|(_, definitions)| definitions)
5560 .dedup()
5561 .collect(),
5562 ))
5563 })
5564 }
5565 }
5566
5567 pub fn declarations(
5568 &mut self,
5569 buffer: &Entity<Buffer>,
5570 position: PointUtf16,
5571 cx: &mut Context<Self>,
5572 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5573 if let Some((upstream_client, project_id)) = self.upstream_client() {
5574 let request = GetDeclarations { position };
5575 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5576 return Task::ready(Ok(None));
5577 }
5578 let request_task = upstream_client.request_lsp(
5579 project_id,
5580 None,
5581 LSP_REQUEST_TIMEOUT,
5582 cx.background_executor().clone(),
5583 request.to_proto(project_id, buffer.read(cx)),
5584 );
5585 let buffer = buffer.clone();
5586 cx.spawn(async move |weak_lsp_store, cx| {
5587 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5588 return Ok(None);
5589 };
5590 let Some(responses) = request_task.await? else {
5591 return Ok(None);
5592 };
5593 let actions = join_all(responses.payload.into_iter().map(|response| {
5594 GetDeclarations { position }.response_from_proto(
5595 response.response,
5596 lsp_store.clone(),
5597 buffer.clone(),
5598 cx.clone(),
5599 )
5600 }))
5601 .await;
5602
5603 Ok(Some(
5604 actions
5605 .into_iter()
5606 .collect::<Result<Vec<Vec<_>>>>()?
5607 .into_iter()
5608 .flatten()
5609 .dedup()
5610 .collect(),
5611 ))
5612 })
5613 } else {
5614 let declarations_task = self.request_multiple_lsp_locally(
5615 buffer,
5616 Some(position),
5617 GetDeclarations { position },
5618 cx,
5619 );
5620 cx.background_spawn(async move {
5621 Ok(Some(
5622 declarations_task
5623 .await
5624 .into_iter()
5625 .flat_map(|(_, declarations)| declarations)
5626 .dedup()
5627 .collect(),
5628 ))
5629 })
5630 }
5631 }
5632
5633 pub fn type_definitions(
5634 &mut self,
5635 buffer: &Entity<Buffer>,
5636 position: PointUtf16,
5637 cx: &mut Context<Self>,
5638 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5639 if let Some((upstream_client, project_id)) = self.upstream_client() {
5640 let request = GetTypeDefinitions { position };
5641 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5642 return Task::ready(Ok(None));
5643 }
5644 let request_task = upstream_client.request_lsp(
5645 project_id,
5646 None,
5647 LSP_REQUEST_TIMEOUT,
5648 cx.background_executor().clone(),
5649 request.to_proto(project_id, buffer.read(cx)),
5650 );
5651 let buffer = buffer.clone();
5652 cx.spawn(async move |weak_lsp_store, cx| {
5653 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5654 return Ok(None);
5655 };
5656 let Some(responses) = request_task.await? else {
5657 return Ok(None);
5658 };
5659 let actions = join_all(responses.payload.into_iter().map(|response| {
5660 GetTypeDefinitions { position }.response_from_proto(
5661 response.response,
5662 lsp_store.clone(),
5663 buffer.clone(),
5664 cx.clone(),
5665 )
5666 }))
5667 .await;
5668
5669 Ok(Some(
5670 actions
5671 .into_iter()
5672 .collect::<Result<Vec<Vec<_>>>>()?
5673 .into_iter()
5674 .flatten()
5675 .dedup()
5676 .collect(),
5677 ))
5678 })
5679 } else {
5680 let type_definitions_task = self.request_multiple_lsp_locally(
5681 buffer,
5682 Some(position),
5683 GetTypeDefinitions { position },
5684 cx,
5685 );
5686 cx.background_spawn(async move {
5687 Ok(Some(
5688 type_definitions_task
5689 .await
5690 .into_iter()
5691 .flat_map(|(_, type_definitions)| type_definitions)
5692 .dedup()
5693 .collect(),
5694 ))
5695 })
5696 }
5697 }
5698
5699 pub fn implementations(
5700 &mut self,
5701 buffer: &Entity<Buffer>,
5702 position: PointUtf16,
5703 cx: &mut Context<Self>,
5704 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5705 if let Some((upstream_client, project_id)) = self.upstream_client() {
5706 let request = GetImplementations { position };
5707 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5708 return Task::ready(Ok(None));
5709 }
5710 let request_task = upstream_client.request_lsp(
5711 project_id,
5712 None,
5713 LSP_REQUEST_TIMEOUT,
5714 cx.background_executor().clone(),
5715 request.to_proto(project_id, buffer.read(cx)),
5716 );
5717 let buffer = buffer.clone();
5718 cx.spawn(async move |weak_lsp_store, cx| {
5719 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5720 return Ok(None);
5721 };
5722 let Some(responses) = request_task.await? else {
5723 return Ok(None);
5724 };
5725 let actions = join_all(responses.payload.into_iter().map(|response| {
5726 GetImplementations { position }.response_from_proto(
5727 response.response,
5728 lsp_store.clone(),
5729 buffer.clone(),
5730 cx.clone(),
5731 )
5732 }))
5733 .await;
5734
5735 Ok(Some(
5736 actions
5737 .into_iter()
5738 .collect::<Result<Vec<Vec<_>>>>()?
5739 .into_iter()
5740 .flatten()
5741 .dedup()
5742 .collect(),
5743 ))
5744 })
5745 } else {
5746 let implementations_task = self.request_multiple_lsp_locally(
5747 buffer,
5748 Some(position),
5749 GetImplementations { position },
5750 cx,
5751 );
5752 cx.background_spawn(async move {
5753 Ok(Some(
5754 implementations_task
5755 .await
5756 .into_iter()
5757 .flat_map(|(_, implementations)| implementations)
5758 .dedup()
5759 .collect(),
5760 ))
5761 })
5762 }
5763 }
5764
5765 pub fn references(
5766 &mut self,
5767 buffer: &Entity<Buffer>,
5768 position: PointUtf16,
5769 cx: &mut Context<Self>,
5770 ) -> Task<Result<Option<Vec<Location>>>> {
5771 if let Some((upstream_client, project_id)) = self.upstream_client() {
5772 let request = GetReferences { position };
5773 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5774 return Task::ready(Ok(None));
5775 }
5776
5777 let request_task = upstream_client.request_lsp(
5778 project_id,
5779 None,
5780 LSP_REQUEST_TIMEOUT,
5781 cx.background_executor().clone(),
5782 request.to_proto(project_id, buffer.read(cx)),
5783 );
5784 let buffer = buffer.clone();
5785 cx.spawn(async move |weak_lsp_store, cx| {
5786 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5787 return Ok(None);
5788 };
5789 let Some(responses) = request_task.await? else {
5790 return Ok(None);
5791 };
5792
5793 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5794 GetReferences { position }.response_from_proto(
5795 lsp_response.response,
5796 lsp_store.clone(),
5797 buffer.clone(),
5798 cx.clone(),
5799 )
5800 }))
5801 .await
5802 .into_iter()
5803 .collect::<Result<Vec<Vec<_>>>>()?
5804 .into_iter()
5805 .flatten()
5806 .dedup()
5807 .collect();
5808 Ok(Some(locations))
5809 })
5810 } else {
5811 let references_task = self.request_multiple_lsp_locally(
5812 buffer,
5813 Some(position),
5814 GetReferences { position },
5815 cx,
5816 );
5817 cx.background_spawn(async move {
5818 Ok(Some(
5819 references_task
5820 .await
5821 .into_iter()
5822 .flat_map(|(_, references)| references)
5823 .dedup()
5824 .collect(),
5825 ))
5826 })
5827 }
5828 }
5829
5830 pub fn code_actions(
5831 &mut self,
5832 buffer: &Entity<Buffer>,
5833 range: Range<Anchor>,
5834 kinds: Option<Vec<CodeActionKind>>,
5835 cx: &mut Context<Self>,
5836 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5837 if let Some((upstream_client, project_id)) = self.upstream_client() {
5838 let request = GetCodeActions {
5839 range: range.clone(),
5840 kinds: kinds.clone(),
5841 };
5842 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5843 return Task::ready(Ok(None));
5844 }
5845 let request_task = upstream_client.request_lsp(
5846 project_id,
5847 None,
5848 LSP_REQUEST_TIMEOUT,
5849 cx.background_executor().clone(),
5850 request.to_proto(project_id, buffer.read(cx)),
5851 );
5852 let buffer = buffer.clone();
5853 cx.spawn(async move |weak_lsp_store, cx| {
5854 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5855 return Ok(None);
5856 };
5857 let Some(responses) = request_task.await? else {
5858 return Ok(None);
5859 };
5860 let actions = join_all(responses.payload.into_iter().map(|response| {
5861 GetCodeActions {
5862 range: range.clone(),
5863 kinds: kinds.clone(),
5864 }
5865 .response_from_proto(
5866 response.response,
5867 lsp_store.clone(),
5868 buffer.clone(),
5869 cx.clone(),
5870 )
5871 }))
5872 .await;
5873
5874 Ok(Some(
5875 actions
5876 .into_iter()
5877 .collect::<Result<Vec<Vec<_>>>>()?
5878 .into_iter()
5879 .flatten()
5880 .collect(),
5881 ))
5882 })
5883 } else {
5884 let all_actions_task = self.request_multiple_lsp_locally(
5885 buffer,
5886 Some(range.start),
5887 GetCodeActions { range, kinds },
5888 cx,
5889 );
5890 cx.background_spawn(async move {
5891 Ok(Some(
5892 all_actions_task
5893 .await
5894 .into_iter()
5895 .flat_map(|(_, actions)| actions)
5896 .collect(),
5897 ))
5898 })
5899 }
5900 }
5901
5902 pub fn code_lens_actions(
5903 &mut self,
5904 buffer: &Entity<Buffer>,
5905 cx: &mut Context<Self>,
5906 ) -> CodeLensTask {
5907 let version_queried_for = buffer.read(cx).version();
5908 let buffer_id = buffer.read(cx).remote_id();
5909 let existing_servers = self.as_local().map(|local| {
5910 local
5911 .buffers_opened_in_servers
5912 .get(&buffer_id)
5913 .cloned()
5914 .unwrap_or_default()
5915 });
5916
5917 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5918 if let Some(cached_lens) = &lsp_data.code_lens {
5919 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5920 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5921 existing_servers != cached_lens.lens.keys().copied().collect()
5922 });
5923 if !has_different_servers {
5924 return Task::ready(Ok(Some(
5925 cached_lens.lens.values().flatten().cloned().collect(),
5926 )))
5927 .shared();
5928 }
5929 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5930 if !version_queried_for.changed_since(updating_for) {
5931 return running_update.clone();
5932 }
5933 }
5934 }
5935 }
5936
5937 let lens_lsp_data = self
5938 .latest_lsp_data(buffer, cx)
5939 .code_lens
5940 .get_or_insert_default();
5941 let buffer = buffer.clone();
5942 let query_version_queried_for = version_queried_for.clone();
5943 let new_task = cx
5944 .spawn(async move |lsp_store, cx| {
5945 cx.background_executor()
5946 .timer(Duration::from_millis(30))
5947 .await;
5948 let fetched_lens = lsp_store
5949 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5950 .map_err(Arc::new)?
5951 .await
5952 .context("fetching code lens")
5953 .map_err(Arc::new);
5954 let fetched_lens = match fetched_lens {
5955 Ok(fetched_lens) => fetched_lens,
5956 Err(e) => {
5957 lsp_store
5958 .update(cx, |lsp_store, _| {
5959 if let Some(lens_lsp_data) = lsp_store
5960 .lsp_data
5961 .get_mut(&buffer_id)
5962 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5963 {
5964 lens_lsp_data.update = None;
5965 }
5966 })
5967 .ok();
5968 return Err(e);
5969 }
5970 };
5971
5972 lsp_store
5973 .update(cx, |lsp_store, _| {
5974 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5975 let code_lens = lsp_data.code_lens.as_mut()?;
5976 if let Some(fetched_lens) = fetched_lens {
5977 if lsp_data.buffer_version == query_version_queried_for {
5978 code_lens.lens.extend(fetched_lens);
5979 } else if !lsp_data
5980 .buffer_version
5981 .changed_since(&query_version_queried_for)
5982 {
5983 lsp_data.buffer_version = query_version_queried_for;
5984 code_lens.lens = fetched_lens;
5985 }
5986 }
5987 code_lens.update = None;
5988 Some(code_lens.lens.values().flatten().cloned().collect())
5989 })
5990 .map_err(Arc::new)
5991 })
5992 .shared();
5993 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5994 new_task
5995 }
5996
5997 fn fetch_code_lens(
5998 &mut self,
5999 buffer: &Entity<Buffer>,
6000 cx: &mut Context<Self>,
6001 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6002 if let Some((upstream_client, project_id)) = self.upstream_client() {
6003 let request = GetCodeLens;
6004 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6005 return Task::ready(Ok(None));
6006 }
6007 let request_task = upstream_client.request_lsp(
6008 project_id,
6009 None,
6010 LSP_REQUEST_TIMEOUT,
6011 cx.background_executor().clone(),
6012 request.to_proto(project_id, buffer.read(cx)),
6013 );
6014 let buffer = buffer.clone();
6015 cx.spawn(async move |weak_lsp_store, cx| {
6016 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6017 return Ok(None);
6018 };
6019 let Some(responses) = request_task.await? else {
6020 return Ok(None);
6021 };
6022
6023 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6024 let lsp_store = lsp_store.clone();
6025 let buffer = buffer.clone();
6026 let cx = cx.clone();
6027 async move {
6028 (
6029 LanguageServerId::from_proto(response.server_id),
6030 GetCodeLens
6031 .response_from_proto(response.response, lsp_store, buffer, cx)
6032 .await,
6033 )
6034 }
6035 }))
6036 .await;
6037
6038 let mut has_errors = false;
6039 let code_lens_actions = code_lens_actions
6040 .into_iter()
6041 .filter_map(|(server_id, code_lens)| match code_lens {
6042 Ok(code_lens) => Some((server_id, code_lens)),
6043 Err(e) => {
6044 has_errors = true;
6045 log::error!("{e:#}");
6046 None
6047 }
6048 })
6049 .collect::<HashMap<_, _>>();
6050 anyhow::ensure!(
6051 !has_errors || !code_lens_actions.is_empty(),
6052 "Failed to fetch code lens"
6053 );
6054 Ok(Some(code_lens_actions))
6055 })
6056 } else {
6057 let code_lens_actions_task =
6058 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6059 cx.background_spawn(async move {
6060 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6061 })
6062 }
6063 }
6064
6065 #[inline(never)]
6066 pub fn completions(
6067 &self,
6068 buffer: &Entity<Buffer>,
6069 position: PointUtf16,
6070 context: CompletionContext,
6071 cx: &mut Context<Self>,
6072 ) -> Task<Result<Vec<CompletionResponse>>> {
6073 let language_registry = self.languages.clone();
6074
6075 if let Some((upstream_client, project_id)) = self.upstream_client() {
6076 let snapshot = buffer.read(cx).snapshot();
6077 let offset = position.to_offset(&snapshot);
6078 let scope = snapshot.language_scope_at(offset);
6079 let capable_lsps = self.all_capable_for_proto_request(
6080 buffer,
6081 |server_name, capabilities| {
6082 capabilities.completion_provider.is_some()
6083 && scope
6084 .as_ref()
6085 .map(|scope| scope.language_allowed(server_name))
6086 .unwrap_or(true)
6087 },
6088 cx,
6089 );
6090 if capable_lsps.is_empty() {
6091 return Task::ready(Ok(Vec::new()));
6092 }
6093
6094 let language = buffer.read(cx).language().cloned();
6095
6096 // In the future, we should provide project guests with the names of LSP adapters,
6097 // so that they can use the correct LSP adapter when computing labels. For now,
6098 // guests just use the first LSP adapter associated with the buffer's language.
6099 let lsp_adapter = language.as_ref().and_then(|language| {
6100 language_registry
6101 .lsp_adapters(&language.name())
6102 .first()
6103 .cloned()
6104 });
6105
6106 let buffer = buffer.clone();
6107
6108 cx.spawn(async move |this, cx| {
6109 let requests = join_all(
6110 capable_lsps
6111 .into_iter()
6112 .map(|id| {
6113 let request = GetCompletions {
6114 position,
6115 context: context.clone(),
6116 server_id: Some(id),
6117 };
6118 let buffer = buffer.clone();
6119 let language = language.clone();
6120 let lsp_adapter = lsp_adapter.clone();
6121 let upstream_client = upstream_client.clone();
6122 let response = this
6123 .update(cx, |this, cx| {
6124 this.send_lsp_proto_request(
6125 buffer,
6126 upstream_client,
6127 project_id,
6128 request,
6129 cx,
6130 )
6131 })
6132 .log_err();
6133 async move {
6134 let response = response?.await.log_err()?;
6135
6136 let completions = populate_labels_for_completions(
6137 response.completions,
6138 language,
6139 lsp_adapter,
6140 )
6141 .await;
6142
6143 Some(CompletionResponse {
6144 completions,
6145 display_options: CompletionDisplayOptions::default(),
6146 is_incomplete: response.is_incomplete,
6147 })
6148 }
6149 })
6150 .collect::<Vec<_>>(),
6151 );
6152 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6153 })
6154 } else if let Some(local) = self.as_local() {
6155 let snapshot = buffer.read(cx).snapshot();
6156 let offset = position.to_offset(&snapshot);
6157 let scope = snapshot.language_scope_at(offset);
6158 let language = snapshot.language().cloned();
6159 let completion_settings = language_settings(
6160 language.as_ref().map(|language| language.name()),
6161 buffer.read(cx).file(),
6162 cx,
6163 )
6164 .completions
6165 .clone();
6166 if !completion_settings.lsp {
6167 return Task::ready(Ok(Vec::new()));
6168 }
6169
6170 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6171 local
6172 .language_servers_for_buffer(buffer, cx)
6173 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6174 .filter(|(adapter, _)| {
6175 scope
6176 .as_ref()
6177 .map(|scope| scope.language_allowed(&adapter.name))
6178 .unwrap_or(true)
6179 })
6180 .map(|(_, server)| server.server_id())
6181 .collect()
6182 });
6183
6184 let buffer = buffer.clone();
6185 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6186 let lsp_timeout = if lsp_timeout > 0 {
6187 Some(Duration::from_millis(lsp_timeout))
6188 } else {
6189 None
6190 };
6191 cx.spawn(async move |this, cx| {
6192 let mut tasks = Vec::with_capacity(server_ids.len());
6193 this.update(cx, |lsp_store, cx| {
6194 for server_id in server_ids {
6195 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6196 let lsp_timeout = lsp_timeout
6197 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6198 let mut timeout = cx.background_spawn(async move {
6199 match lsp_timeout {
6200 Some(lsp_timeout) => {
6201 lsp_timeout.await;
6202 true
6203 },
6204 None => false,
6205 }
6206 }).fuse();
6207 let mut lsp_request = lsp_store.request_lsp(
6208 buffer.clone(),
6209 LanguageServerToQuery::Other(server_id),
6210 GetCompletions {
6211 position,
6212 context: context.clone(),
6213 server_id: Some(server_id),
6214 },
6215 cx,
6216 ).fuse();
6217 let new_task = cx.background_spawn(async move {
6218 select_biased! {
6219 response = lsp_request => anyhow::Ok(Some(response?)),
6220 timeout_happened = timeout => {
6221 if timeout_happened {
6222 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6223 Ok(None)
6224 } else {
6225 let completions = lsp_request.await?;
6226 Ok(Some(completions))
6227 }
6228 },
6229 }
6230 });
6231 tasks.push((lsp_adapter, new_task));
6232 }
6233 })?;
6234
6235 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6236 let completion_response = task.await.ok()??;
6237 let completions = populate_labels_for_completions(
6238 completion_response.completions,
6239 language.clone(),
6240 lsp_adapter,
6241 )
6242 .await;
6243 Some(CompletionResponse {
6244 completions,
6245 display_options: CompletionDisplayOptions::default(),
6246 is_incomplete: completion_response.is_incomplete,
6247 })
6248 });
6249
6250 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6251
6252 Ok(responses.into_iter().flatten().collect())
6253 })
6254 } else {
6255 Task::ready(Err(anyhow!("No upstream client or local language server")))
6256 }
6257 }
6258
6259 pub fn resolve_completions(
6260 &self,
6261 buffer: Entity<Buffer>,
6262 completion_indices: Vec<usize>,
6263 completions: Rc<RefCell<Box<[Completion]>>>,
6264 cx: &mut Context<Self>,
6265 ) -> Task<Result<bool>> {
6266 let client = self.upstream_client();
6267 let buffer_id = buffer.read(cx).remote_id();
6268 let buffer_snapshot = buffer.read(cx).snapshot();
6269
6270 if !self.check_if_capable_for_proto_request(
6271 &buffer,
6272 GetCompletions::can_resolve_completions,
6273 cx,
6274 ) {
6275 return Task::ready(Ok(false));
6276 }
6277 cx.spawn(async move |lsp_store, cx| {
6278 let mut did_resolve = false;
6279 if let Some((client, project_id)) = client {
6280 for completion_index in completion_indices {
6281 let server_id = {
6282 let completion = &completions.borrow()[completion_index];
6283 completion.source.server_id()
6284 };
6285 if let Some(server_id) = server_id {
6286 if Self::resolve_completion_remote(
6287 project_id,
6288 server_id,
6289 buffer_id,
6290 completions.clone(),
6291 completion_index,
6292 client.clone(),
6293 )
6294 .await
6295 .log_err()
6296 .is_some()
6297 {
6298 did_resolve = true;
6299 }
6300 } else {
6301 resolve_word_completion(
6302 &buffer_snapshot,
6303 &mut completions.borrow_mut()[completion_index],
6304 );
6305 }
6306 }
6307 } else {
6308 for completion_index in completion_indices {
6309 let server_id = {
6310 let completion = &completions.borrow()[completion_index];
6311 completion.source.server_id()
6312 };
6313 if let Some(server_id) = server_id {
6314 let server_and_adapter = lsp_store
6315 .read_with(cx, |lsp_store, _| {
6316 let server = lsp_store.language_server_for_id(server_id)?;
6317 let adapter =
6318 lsp_store.language_server_adapter_for_id(server.server_id())?;
6319 Some((server, adapter))
6320 })
6321 .ok()
6322 .flatten();
6323 let Some((server, adapter)) = server_and_adapter else {
6324 continue;
6325 };
6326
6327 let resolved = Self::resolve_completion_local(
6328 server,
6329 completions.clone(),
6330 completion_index,
6331 )
6332 .await
6333 .log_err()
6334 .is_some();
6335 if resolved {
6336 Self::regenerate_completion_labels(
6337 adapter,
6338 &buffer_snapshot,
6339 completions.clone(),
6340 completion_index,
6341 )
6342 .await
6343 .log_err();
6344 did_resolve = true;
6345 }
6346 } else {
6347 resolve_word_completion(
6348 &buffer_snapshot,
6349 &mut completions.borrow_mut()[completion_index],
6350 );
6351 }
6352 }
6353 }
6354
6355 Ok(did_resolve)
6356 })
6357 }
6358
6359 async fn resolve_completion_local(
6360 server: Arc<lsp::LanguageServer>,
6361 completions: Rc<RefCell<Box<[Completion]>>>,
6362 completion_index: usize,
6363 ) -> Result<()> {
6364 let server_id = server.server_id();
6365 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6366 return Ok(());
6367 }
6368
6369 let request = {
6370 let completion = &completions.borrow()[completion_index];
6371 match &completion.source {
6372 CompletionSource::Lsp {
6373 lsp_completion,
6374 resolved,
6375 server_id: completion_server_id,
6376 ..
6377 } => {
6378 if *resolved {
6379 return Ok(());
6380 }
6381 anyhow::ensure!(
6382 server_id == *completion_server_id,
6383 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6384 );
6385 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6386 }
6387 CompletionSource::BufferWord { .. }
6388 | CompletionSource::Dap { .. }
6389 | CompletionSource::Custom => {
6390 return Ok(());
6391 }
6392 }
6393 };
6394 let resolved_completion = request
6395 .await
6396 .into_response()
6397 .context("resolve completion")?;
6398
6399 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6400 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6401
6402 let mut completions = completions.borrow_mut();
6403 let completion = &mut completions[completion_index];
6404 if let CompletionSource::Lsp {
6405 lsp_completion,
6406 resolved,
6407 server_id: completion_server_id,
6408 ..
6409 } = &mut completion.source
6410 {
6411 if *resolved {
6412 return Ok(());
6413 }
6414 anyhow::ensure!(
6415 server_id == *completion_server_id,
6416 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6417 );
6418 *lsp_completion = Box::new(resolved_completion);
6419 *resolved = true;
6420 }
6421 Ok(())
6422 }
6423
6424 async fn regenerate_completion_labels(
6425 adapter: Arc<CachedLspAdapter>,
6426 snapshot: &BufferSnapshot,
6427 completions: Rc<RefCell<Box<[Completion]>>>,
6428 completion_index: usize,
6429 ) -> Result<()> {
6430 let completion_item = completions.borrow()[completion_index]
6431 .source
6432 .lsp_completion(true)
6433 .map(Cow::into_owned);
6434 if let Some(lsp_documentation) = completion_item
6435 .as_ref()
6436 .and_then(|completion_item| completion_item.documentation.clone())
6437 {
6438 let mut completions = completions.borrow_mut();
6439 let completion = &mut completions[completion_index];
6440 completion.documentation = Some(lsp_documentation.into());
6441 } else {
6442 let mut completions = completions.borrow_mut();
6443 let completion = &mut completions[completion_index];
6444 completion.documentation = Some(CompletionDocumentation::Undocumented);
6445 }
6446
6447 let mut new_label = match completion_item {
6448 Some(completion_item) => {
6449 // 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
6450 // So we have to update the label here anyway...
6451 let language = snapshot.language();
6452 match language {
6453 Some(language) => {
6454 adapter
6455 .labels_for_completions(
6456 std::slice::from_ref(&completion_item),
6457 language,
6458 )
6459 .await?
6460 }
6461 None => Vec::new(),
6462 }
6463 .pop()
6464 .flatten()
6465 .unwrap_or_else(|| {
6466 CodeLabel::fallback_for_completion(
6467 &completion_item,
6468 language.map(|language| language.as_ref()),
6469 )
6470 })
6471 }
6472 None => CodeLabel::plain(
6473 completions.borrow()[completion_index].new_text.clone(),
6474 None,
6475 ),
6476 };
6477 ensure_uniform_list_compatible_label(&mut new_label);
6478
6479 let mut completions = completions.borrow_mut();
6480 let completion = &mut completions[completion_index];
6481 if completion.label.filter_text() == new_label.filter_text() {
6482 completion.label = new_label;
6483 } else {
6484 log::error!(
6485 "Resolved completion changed display label from {} to {}. \
6486 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6487 completion.label.text(),
6488 new_label.text(),
6489 completion.label.filter_text(),
6490 new_label.filter_text()
6491 );
6492 }
6493
6494 Ok(())
6495 }
6496
6497 async fn resolve_completion_remote(
6498 project_id: u64,
6499 server_id: LanguageServerId,
6500 buffer_id: BufferId,
6501 completions: Rc<RefCell<Box<[Completion]>>>,
6502 completion_index: usize,
6503 client: AnyProtoClient,
6504 ) -> Result<()> {
6505 let lsp_completion = {
6506 let completion = &completions.borrow()[completion_index];
6507 match &completion.source {
6508 CompletionSource::Lsp {
6509 lsp_completion,
6510 resolved,
6511 server_id: completion_server_id,
6512 ..
6513 } => {
6514 anyhow::ensure!(
6515 server_id == *completion_server_id,
6516 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6517 );
6518 if *resolved {
6519 return Ok(());
6520 }
6521 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6522 }
6523 CompletionSource::Custom
6524 | CompletionSource::Dap { .. }
6525 | CompletionSource::BufferWord { .. } => {
6526 return Ok(());
6527 }
6528 }
6529 };
6530 let request = proto::ResolveCompletionDocumentation {
6531 project_id,
6532 language_server_id: server_id.0 as u64,
6533 lsp_completion,
6534 buffer_id: buffer_id.into(),
6535 };
6536
6537 let response = client
6538 .request(request)
6539 .await
6540 .context("completion documentation resolve proto request")?;
6541 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6542
6543 let documentation = if response.documentation.is_empty() {
6544 CompletionDocumentation::Undocumented
6545 } else if response.documentation_is_markdown {
6546 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6547 } else if response.documentation.lines().count() <= 1 {
6548 CompletionDocumentation::SingleLine(response.documentation.into())
6549 } else {
6550 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6551 };
6552
6553 let mut completions = completions.borrow_mut();
6554 let completion = &mut completions[completion_index];
6555 completion.documentation = Some(documentation);
6556 if let CompletionSource::Lsp {
6557 insert_range,
6558 lsp_completion,
6559 resolved,
6560 server_id: completion_server_id,
6561 lsp_defaults: _,
6562 } = &mut completion.source
6563 {
6564 let completion_insert_range = response
6565 .old_insert_start
6566 .and_then(deserialize_anchor)
6567 .zip(response.old_insert_end.and_then(deserialize_anchor));
6568 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6569
6570 if *resolved {
6571 return Ok(());
6572 }
6573 anyhow::ensure!(
6574 server_id == *completion_server_id,
6575 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6576 );
6577 *lsp_completion = Box::new(resolved_lsp_completion);
6578 *resolved = true;
6579 }
6580
6581 let replace_range = response
6582 .old_replace_start
6583 .and_then(deserialize_anchor)
6584 .zip(response.old_replace_end.and_then(deserialize_anchor));
6585 if let Some((old_replace_start, old_replace_end)) = replace_range
6586 && !response.new_text.is_empty()
6587 {
6588 completion.new_text = response.new_text;
6589 completion.replace_range = old_replace_start..old_replace_end;
6590 }
6591
6592 Ok(())
6593 }
6594
6595 pub fn apply_additional_edits_for_completion(
6596 &self,
6597 buffer_handle: Entity<Buffer>,
6598 completions: Rc<RefCell<Box<[Completion]>>>,
6599 completion_index: usize,
6600 push_to_history: bool,
6601 cx: &mut Context<Self>,
6602 ) -> Task<Result<Option<Transaction>>> {
6603 if let Some((client, project_id)) = self.upstream_client() {
6604 let buffer = buffer_handle.read(cx);
6605 let buffer_id = buffer.remote_id();
6606 cx.spawn(async move |_, cx| {
6607 let request = {
6608 let completion = completions.borrow()[completion_index].clone();
6609 proto::ApplyCompletionAdditionalEdits {
6610 project_id,
6611 buffer_id: buffer_id.into(),
6612 completion: Some(Self::serialize_completion(&CoreCompletion {
6613 replace_range: completion.replace_range,
6614 new_text: completion.new_text,
6615 source: completion.source,
6616 })),
6617 }
6618 };
6619
6620 if let Some(transaction) = client.request(request).await?.transaction {
6621 let transaction = language::proto::deserialize_transaction(transaction)?;
6622 buffer_handle
6623 .update(cx, |buffer, _| {
6624 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6625 })?
6626 .await?;
6627 if push_to_history {
6628 buffer_handle.update(cx, |buffer, _| {
6629 buffer.push_transaction(transaction.clone(), Instant::now());
6630 buffer.finalize_last_transaction();
6631 })?;
6632 }
6633 Ok(Some(transaction))
6634 } else {
6635 Ok(None)
6636 }
6637 })
6638 } else {
6639 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6640 let completion = &completions.borrow()[completion_index];
6641 let server_id = completion.source.server_id()?;
6642 Some(
6643 self.language_server_for_local_buffer(buffer, server_id, cx)?
6644 .1
6645 .clone(),
6646 )
6647 }) else {
6648 return Task::ready(Ok(None));
6649 };
6650
6651 cx.spawn(async move |this, cx| {
6652 Self::resolve_completion_local(
6653 server.clone(),
6654 completions.clone(),
6655 completion_index,
6656 )
6657 .await
6658 .context("resolving completion")?;
6659 let completion = completions.borrow()[completion_index].clone();
6660 let additional_text_edits = completion
6661 .source
6662 .lsp_completion(true)
6663 .as_ref()
6664 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6665 if let Some(edits) = additional_text_edits {
6666 let edits = this
6667 .update(cx, |this, cx| {
6668 this.as_local_mut().unwrap().edits_from_lsp(
6669 &buffer_handle,
6670 edits,
6671 server.server_id(),
6672 None,
6673 cx,
6674 )
6675 })?
6676 .await?;
6677
6678 buffer_handle.update(cx, |buffer, cx| {
6679 buffer.finalize_last_transaction();
6680 buffer.start_transaction();
6681
6682 for (range, text) in edits {
6683 let primary = &completion.replace_range;
6684
6685 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6686 // and the primary completion is just an insertion (empty range), then this is likely
6687 // an auto-import scenario and should not be considered overlapping
6688 // https://github.com/zed-industries/zed/issues/26136
6689 let is_file_start_auto_import = {
6690 let snapshot = buffer.snapshot();
6691 let primary_start_point = primary.start.to_point(&snapshot);
6692 let range_start_point = range.start.to_point(&snapshot);
6693
6694 let result = primary_start_point.row == 0
6695 && primary_start_point.column == 0
6696 && range_start_point.row == 0
6697 && range_start_point.column == 0;
6698
6699 result
6700 };
6701
6702 let has_overlap = if is_file_start_auto_import {
6703 false
6704 } else {
6705 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6706 && primary.end.cmp(&range.start, buffer).is_ge();
6707 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6708 && range.end.cmp(&primary.end, buffer).is_ge();
6709 let result = start_within || end_within;
6710 result
6711 };
6712
6713 //Skip additional edits which overlap with the primary completion edit
6714 //https://github.com/zed-industries/zed/pull/1871
6715 if !has_overlap {
6716 buffer.edit([(range, text)], None, cx);
6717 }
6718 }
6719
6720 let transaction = if buffer.end_transaction(cx).is_some() {
6721 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6722 if !push_to_history {
6723 buffer.forget_transaction(transaction.id);
6724 }
6725 Some(transaction)
6726 } else {
6727 None
6728 };
6729 Ok(transaction)
6730 })?
6731 } else {
6732 Ok(None)
6733 }
6734 })
6735 }
6736 }
6737
6738 pub fn pull_diagnostics(
6739 &mut self,
6740 buffer: Entity<Buffer>,
6741 cx: &mut Context<Self>,
6742 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6743 let buffer_id = buffer.read(cx).remote_id();
6744
6745 if let Some((client, upstream_project_id)) = self.upstream_client() {
6746 let mut suitable_capabilities = None;
6747 // Are we capable for proto request?
6748 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6749 &buffer,
6750 |capabilities| {
6751 if let Some(caps) = &capabilities.diagnostic_provider {
6752 suitable_capabilities = Some(caps.clone());
6753 true
6754 } else {
6755 false
6756 }
6757 },
6758 cx,
6759 );
6760 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6761 let Some(dynamic_caps) = suitable_capabilities else {
6762 return Task::ready(Ok(None));
6763 };
6764 assert!(any_server_has_diagnostics_provider);
6765
6766 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6767 let request = GetDocumentDiagnostics {
6768 previous_result_id: None,
6769 identifier,
6770 registration_id: None,
6771 };
6772 let request_task = client.request_lsp(
6773 upstream_project_id,
6774 None,
6775 LSP_REQUEST_TIMEOUT,
6776 cx.background_executor().clone(),
6777 request.to_proto(upstream_project_id, buffer.read(cx)),
6778 );
6779 cx.background_spawn(async move {
6780 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6781 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6782 // Do not attempt to further process the dummy responses here.
6783 let _response = request_task.await?;
6784 Ok(None)
6785 })
6786 } else {
6787 let servers = buffer.update(cx, |buffer, cx| {
6788 self.running_language_servers_for_local_buffer(buffer, cx)
6789 .map(|(_, server)| server.clone())
6790 .collect::<Vec<_>>()
6791 });
6792
6793 let pull_diagnostics = servers
6794 .into_iter()
6795 .flat_map(|server| {
6796 let result = maybe!({
6797 let local = self.as_local()?;
6798 let server_id = server.server_id();
6799 let providers_with_identifiers = local
6800 .language_server_dynamic_registrations
6801 .get(&server_id)
6802 .into_iter()
6803 .flat_map(|registrations| registrations.diagnostics.clone())
6804 .collect::<Vec<_>>();
6805 Some(
6806 providers_with_identifiers
6807 .into_iter()
6808 .map(|(registration_id, dynamic_caps)| {
6809 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6810 let registration_id = registration_id.map(SharedString::from);
6811 let result_id = self.result_id_for_buffer_pull(
6812 server_id,
6813 buffer_id,
6814 ®istration_id,
6815 cx,
6816 );
6817 self.request_lsp(
6818 buffer.clone(),
6819 LanguageServerToQuery::Other(server_id),
6820 GetDocumentDiagnostics {
6821 previous_result_id: result_id,
6822 registration_id,
6823 identifier,
6824 },
6825 cx,
6826 )
6827 })
6828 .collect::<Vec<_>>(),
6829 )
6830 });
6831
6832 result.unwrap_or_default()
6833 })
6834 .collect::<Vec<_>>();
6835
6836 cx.background_spawn(async move {
6837 let mut responses = Vec::new();
6838 for diagnostics in join_all(pull_diagnostics).await {
6839 responses.extend(diagnostics?);
6840 }
6841 Ok(Some(responses))
6842 })
6843 }
6844 }
6845
6846 pub fn applicable_inlay_chunks(
6847 &mut self,
6848 buffer: &Entity<Buffer>,
6849 ranges: &[Range<text::Anchor>],
6850 cx: &mut Context<Self>,
6851 ) -> Vec<Range<BufferRow>> {
6852 let buffer_snapshot = buffer.read(cx).snapshot();
6853 let ranges = ranges
6854 .iter()
6855 .map(|range| range.to_point(&buffer_snapshot))
6856 .collect::<Vec<_>>();
6857
6858 self.latest_lsp_data(buffer, cx)
6859 .inlay_hints
6860 .applicable_chunks(ranges.as_slice())
6861 .map(|chunk| chunk.row_range())
6862 .collect()
6863 }
6864
6865 pub fn invalidate_inlay_hints<'a>(
6866 &'a mut self,
6867 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6868 ) {
6869 for buffer_id in for_buffers {
6870 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6871 lsp_data.inlay_hints.clear();
6872 }
6873 }
6874 }
6875
6876 pub fn inlay_hints(
6877 &mut self,
6878 invalidate: InvalidationStrategy,
6879 buffer: Entity<Buffer>,
6880 ranges: Vec<Range<text::Anchor>>,
6881 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6882 cx: &mut Context<Self>,
6883 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6884 let next_hint_id = self.next_hint_id.clone();
6885 let lsp_data = self.latest_lsp_data(&buffer, cx);
6886 let query_version = lsp_data.buffer_version.clone();
6887 let mut lsp_refresh_requested = false;
6888 let for_server = if let InvalidationStrategy::RefreshRequested {
6889 server_id,
6890 request_id,
6891 } = invalidate
6892 {
6893 let invalidated = lsp_data
6894 .inlay_hints
6895 .invalidate_for_server_refresh(server_id, request_id);
6896 lsp_refresh_requested = invalidated;
6897 Some(server_id)
6898 } else {
6899 None
6900 };
6901 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6902 let known_chunks = known_chunks
6903 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6904 .map(|(_, known_chunks)| known_chunks)
6905 .unwrap_or_default();
6906
6907 let buffer_snapshot = buffer.read(cx).snapshot();
6908 let ranges = ranges
6909 .iter()
6910 .map(|range| range.to_point(&buffer_snapshot))
6911 .collect::<Vec<_>>();
6912
6913 let mut hint_fetch_tasks = Vec::new();
6914 let mut cached_inlay_hints = None;
6915 let mut ranges_to_query = None;
6916 let applicable_chunks = existing_inlay_hints
6917 .applicable_chunks(ranges.as_slice())
6918 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6919 .collect::<Vec<_>>();
6920 if applicable_chunks.is_empty() {
6921 return HashMap::default();
6922 }
6923
6924 for row_chunk in applicable_chunks {
6925 match (
6926 existing_inlay_hints
6927 .cached_hints(&row_chunk)
6928 .filter(|_| !lsp_refresh_requested)
6929 .cloned(),
6930 existing_inlay_hints
6931 .fetched_hints(&row_chunk)
6932 .as_ref()
6933 .filter(|_| !lsp_refresh_requested)
6934 .cloned(),
6935 ) {
6936 (None, None) => {
6937 let chunk_range = row_chunk.anchor_range();
6938 ranges_to_query
6939 .get_or_insert_with(Vec::new)
6940 .push((row_chunk, chunk_range));
6941 }
6942 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6943 (Some(cached_hints), None) => {
6944 for (server_id, cached_hints) in cached_hints {
6945 if for_server.is_none_or(|for_server| for_server == server_id) {
6946 cached_inlay_hints
6947 .get_or_insert_with(HashMap::default)
6948 .entry(row_chunk.row_range())
6949 .or_insert_with(HashMap::default)
6950 .entry(server_id)
6951 .or_insert_with(Vec::new)
6952 .extend(cached_hints);
6953 }
6954 }
6955 }
6956 (Some(cached_hints), Some(fetched_hints)) => {
6957 hint_fetch_tasks.push((row_chunk, fetched_hints));
6958 for (server_id, cached_hints) in cached_hints {
6959 if for_server.is_none_or(|for_server| for_server == server_id) {
6960 cached_inlay_hints
6961 .get_or_insert_with(HashMap::default)
6962 .entry(row_chunk.row_range())
6963 .or_insert_with(HashMap::default)
6964 .entry(server_id)
6965 .or_insert_with(Vec::new)
6966 .extend(cached_hints);
6967 }
6968 }
6969 }
6970 }
6971 }
6972
6973 if hint_fetch_tasks.is_empty()
6974 && ranges_to_query
6975 .as_ref()
6976 .is_none_or(|ranges| ranges.is_empty())
6977 && let Some(cached_inlay_hints) = cached_inlay_hints
6978 {
6979 cached_inlay_hints
6980 .into_iter()
6981 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6982 .collect()
6983 } else {
6984 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6985 let next_hint_id = next_hint_id.clone();
6986 let buffer = buffer.clone();
6987 let query_version = query_version.clone();
6988 let new_inlay_hints = cx
6989 .spawn(async move |lsp_store, cx| {
6990 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6991 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6992 })?;
6993 new_fetch_task
6994 .await
6995 .and_then(|new_hints_by_server| {
6996 lsp_store.update(cx, |lsp_store, cx| {
6997 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6998 let update_cache = lsp_data.buffer_version == query_version;
6999 if new_hints_by_server.is_empty() {
7000 if update_cache {
7001 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7002 }
7003 HashMap::default()
7004 } else {
7005 new_hints_by_server
7006 .into_iter()
7007 .map(|(server_id, new_hints)| {
7008 let new_hints = new_hints
7009 .into_iter()
7010 .map(|new_hint| {
7011 (
7012 InlayId::Hint(next_hint_id.fetch_add(
7013 1,
7014 atomic::Ordering::AcqRel,
7015 )),
7016 new_hint,
7017 )
7018 })
7019 .collect::<Vec<_>>();
7020 if update_cache {
7021 lsp_data.inlay_hints.insert_new_hints(
7022 chunk,
7023 server_id,
7024 new_hints.clone(),
7025 );
7026 }
7027 (server_id, new_hints)
7028 })
7029 .collect()
7030 }
7031 })
7032 })
7033 .map_err(Arc::new)
7034 })
7035 .shared();
7036
7037 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7038 *fetch_task = Some(new_inlay_hints.clone());
7039 hint_fetch_tasks.push((chunk, new_inlay_hints));
7040 }
7041
7042 cached_inlay_hints
7043 .unwrap_or_default()
7044 .into_iter()
7045 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7046 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7047 (
7048 chunk.row_range(),
7049 cx.spawn(async move |_, _| {
7050 hints_fetch.await.map_err(|e| {
7051 if e.error_code() != ErrorCode::Internal {
7052 anyhow!(e.error_code())
7053 } else {
7054 anyhow!("{e:#}")
7055 }
7056 })
7057 }),
7058 )
7059 }))
7060 .collect()
7061 }
7062 }
7063
7064 fn fetch_inlay_hints(
7065 &mut self,
7066 for_server: Option<LanguageServerId>,
7067 buffer: &Entity<Buffer>,
7068 range: Range<Anchor>,
7069 cx: &mut Context<Self>,
7070 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7071 let request = InlayHints {
7072 range: range.clone(),
7073 };
7074 if let Some((upstream_client, project_id)) = self.upstream_client() {
7075 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7076 return Task::ready(Ok(HashMap::default()));
7077 }
7078 let request_task = upstream_client.request_lsp(
7079 project_id,
7080 for_server.map(|id| id.to_proto()),
7081 LSP_REQUEST_TIMEOUT,
7082 cx.background_executor().clone(),
7083 request.to_proto(project_id, buffer.read(cx)),
7084 );
7085 let buffer = buffer.clone();
7086 cx.spawn(async move |weak_lsp_store, cx| {
7087 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7088 return Ok(HashMap::default());
7089 };
7090 let Some(responses) = request_task.await? else {
7091 return Ok(HashMap::default());
7092 };
7093
7094 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7095 let lsp_store = lsp_store.clone();
7096 let buffer = buffer.clone();
7097 let cx = cx.clone();
7098 let request = request.clone();
7099 async move {
7100 (
7101 LanguageServerId::from_proto(response.server_id),
7102 request
7103 .response_from_proto(response.response, lsp_store, buffer, cx)
7104 .await,
7105 )
7106 }
7107 }))
7108 .await;
7109
7110 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7111 let mut has_errors = false;
7112 let inlay_hints = inlay_hints
7113 .into_iter()
7114 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7115 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7116 Err(e) => {
7117 has_errors = true;
7118 log::error!("{e:#}");
7119 None
7120 }
7121 })
7122 .map(|(server_id, mut new_hints)| {
7123 new_hints.retain(|hint| {
7124 hint.position.is_valid(&buffer_snapshot)
7125 && range.start.is_valid(&buffer_snapshot)
7126 && range.end.is_valid(&buffer_snapshot)
7127 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7128 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7129 });
7130 (server_id, new_hints)
7131 })
7132 .collect::<HashMap<_, _>>();
7133 anyhow::ensure!(
7134 !has_errors || !inlay_hints.is_empty(),
7135 "Failed to fetch inlay hints"
7136 );
7137 Ok(inlay_hints)
7138 })
7139 } else {
7140 let inlay_hints_task = match for_server {
7141 Some(server_id) => {
7142 let server_task = self.request_lsp(
7143 buffer.clone(),
7144 LanguageServerToQuery::Other(server_id),
7145 request,
7146 cx,
7147 );
7148 cx.background_spawn(async move {
7149 let mut responses = Vec::new();
7150 match server_task.await {
7151 Ok(response) => responses.push((server_id, response)),
7152 // rust-analyzer likes to error with this when its still loading up
7153 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7154 Err(e) => log::error!(
7155 "Error handling response for inlay hints request: {e:#}"
7156 ),
7157 }
7158 responses
7159 })
7160 }
7161 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7162 };
7163 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7164 cx.background_spawn(async move {
7165 Ok(inlay_hints_task
7166 .await
7167 .into_iter()
7168 .map(|(server_id, mut new_hints)| {
7169 new_hints.retain(|hint| {
7170 hint.position.is_valid(&buffer_snapshot)
7171 && range.start.is_valid(&buffer_snapshot)
7172 && range.end.is_valid(&buffer_snapshot)
7173 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7174 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7175 });
7176 (server_id, new_hints)
7177 })
7178 .collect())
7179 })
7180 }
7181 }
7182
7183 pub fn pull_diagnostics_for_buffer(
7184 &mut self,
7185 buffer: Entity<Buffer>,
7186 cx: &mut Context<Self>,
7187 ) -> Task<anyhow::Result<()>> {
7188 let diagnostics = self.pull_diagnostics(buffer, cx);
7189 cx.spawn(async move |lsp_store, cx| {
7190 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7191 return Ok(());
7192 };
7193 lsp_store.update(cx, |lsp_store, cx| {
7194 if lsp_store.as_local().is_none() {
7195 return;
7196 }
7197
7198 let mut unchanged_buffers = HashMap::default();
7199 let server_diagnostics_updates = diagnostics
7200 .into_iter()
7201 .filter_map(|diagnostics_set| match diagnostics_set {
7202 LspPullDiagnostics::Response {
7203 server_id,
7204 uri,
7205 diagnostics,
7206 registration_id,
7207 } => Some((server_id, uri, diagnostics, registration_id)),
7208 LspPullDiagnostics::Default => None,
7209 })
7210 .fold(
7211 HashMap::default(),
7212 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7213 let (result_id, diagnostics) = match diagnostics {
7214 PulledDiagnostics::Unchanged { result_id } => {
7215 unchanged_buffers
7216 .entry(new_registration_id.clone())
7217 .or_insert_with(HashSet::default)
7218 .insert(uri.clone());
7219 (Some(result_id), Vec::new())
7220 }
7221 PulledDiagnostics::Changed {
7222 result_id,
7223 diagnostics,
7224 } => (result_id, diagnostics),
7225 };
7226 let disk_based_sources = Cow::Owned(
7227 lsp_store
7228 .language_server_adapter_for_id(server_id)
7229 .as_ref()
7230 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7231 .unwrap_or(&[])
7232 .to_vec(),
7233 );
7234 acc.entry(server_id)
7235 .or_insert_with(HashMap::default)
7236 .entry(new_registration_id.clone())
7237 .or_insert_with(Vec::new)
7238 .push(DocumentDiagnosticsUpdate {
7239 server_id,
7240 diagnostics: lsp::PublishDiagnosticsParams {
7241 uri,
7242 diagnostics,
7243 version: None,
7244 },
7245 result_id,
7246 disk_based_sources,
7247 registration_id: new_registration_id,
7248 });
7249 acc
7250 },
7251 );
7252
7253 for diagnostic_updates in server_diagnostics_updates.into_values() {
7254 for (registration_id, diagnostic_updates) in diagnostic_updates {
7255 lsp_store
7256 .merge_lsp_diagnostics(
7257 DiagnosticSourceKind::Pulled,
7258 diagnostic_updates,
7259 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7260 DiagnosticSourceKind::Pulled => {
7261 old_diagnostic.registration_id != registration_id
7262 || unchanged_buffers
7263 .get(&old_diagnostic.registration_id)
7264 .is_some_and(|unchanged_buffers| {
7265 unchanged_buffers.contains(&document_uri)
7266 })
7267 }
7268 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7269 true
7270 }
7271 },
7272 cx,
7273 )
7274 .log_err();
7275 }
7276 }
7277 })
7278 })
7279 }
7280
7281 pub fn document_colors(
7282 &mut self,
7283 known_cache_version: Option<usize>,
7284 buffer: Entity<Buffer>,
7285 cx: &mut Context<Self>,
7286 ) -> Option<DocumentColorTask> {
7287 let version_queried_for = buffer.read(cx).version();
7288 let buffer_id = buffer.read(cx).remote_id();
7289
7290 let current_language_servers = self.as_local().map(|local| {
7291 local
7292 .buffers_opened_in_servers
7293 .get(&buffer_id)
7294 .cloned()
7295 .unwrap_or_default()
7296 });
7297
7298 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7299 if let Some(cached_colors) = &lsp_data.document_colors {
7300 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7301 let has_different_servers =
7302 current_language_servers.is_some_and(|current_language_servers| {
7303 current_language_servers
7304 != cached_colors.colors.keys().copied().collect()
7305 });
7306 if !has_different_servers {
7307 let cache_version = cached_colors.cache_version;
7308 if Some(cache_version) == known_cache_version {
7309 return None;
7310 } else {
7311 return Some(
7312 Task::ready(Ok(DocumentColors {
7313 colors: cached_colors
7314 .colors
7315 .values()
7316 .flatten()
7317 .cloned()
7318 .collect(),
7319 cache_version: Some(cache_version),
7320 }))
7321 .shared(),
7322 );
7323 }
7324 }
7325 }
7326 }
7327 }
7328
7329 let color_lsp_data = self
7330 .latest_lsp_data(&buffer, cx)
7331 .document_colors
7332 .get_or_insert_default();
7333 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7334 && !version_queried_for.changed_since(updating_for)
7335 {
7336 return Some(running_update.clone());
7337 }
7338 let buffer_version_queried_for = version_queried_for.clone();
7339 let new_task = cx
7340 .spawn(async move |lsp_store, cx| {
7341 cx.background_executor()
7342 .timer(Duration::from_millis(30))
7343 .await;
7344 let fetched_colors = lsp_store
7345 .update(cx, |lsp_store, cx| {
7346 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7347 })?
7348 .await
7349 .context("fetching document colors")
7350 .map_err(Arc::new);
7351 let fetched_colors = match fetched_colors {
7352 Ok(fetched_colors) => {
7353 if Some(true)
7354 == buffer
7355 .update(cx, |buffer, _| {
7356 buffer.version() != buffer_version_queried_for
7357 })
7358 .ok()
7359 {
7360 return Ok(DocumentColors::default());
7361 }
7362 fetched_colors
7363 }
7364 Err(e) => {
7365 lsp_store
7366 .update(cx, |lsp_store, _| {
7367 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7368 if let Some(document_colors) = &mut lsp_data.document_colors {
7369 document_colors.colors_update = None;
7370 }
7371 }
7372 })
7373 .ok();
7374 return Err(e);
7375 }
7376 };
7377
7378 lsp_store
7379 .update(cx, |lsp_store, cx| {
7380 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7381 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7382
7383 if let Some(fetched_colors) = fetched_colors {
7384 if lsp_data.buffer_version == buffer_version_queried_for {
7385 lsp_colors.colors.extend(fetched_colors);
7386 lsp_colors.cache_version += 1;
7387 } else if !lsp_data
7388 .buffer_version
7389 .changed_since(&buffer_version_queried_for)
7390 {
7391 lsp_data.buffer_version = buffer_version_queried_for;
7392 lsp_colors.colors = fetched_colors;
7393 lsp_colors.cache_version += 1;
7394 }
7395 }
7396 lsp_colors.colors_update = None;
7397 let colors = lsp_colors
7398 .colors
7399 .values()
7400 .flatten()
7401 .cloned()
7402 .collect::<HashSet<_>>();
7403 DocumentColors {
7404 colors,
7405 cache_version: Some(lsp_colors.cache_version),
7406 }
7407 })
7408 .map_err(Arc::new)
7409 })
7410 .shared();
7411 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7412 Some(new_task)
7413 }
7414
7415 fn fetch_document_colors_for_buffer(
7416 &mut self,
7417 buffer: &Entity<Buffer>,
7418 cx: &mut Context<Self>,
7419 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7420 if let Some((client, project_id)) = self.upstream_client() {
7421 let request = GetDocumentColor {};
7422 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7423 return Task::ready(Ok(None));
7424 }
7425
7426 let request_task = client.request_lsp(
7427 project_id,
7428 None,
7429 LSP_REQUEST_TIMEOUT,
7430 cx.background_executor().clone(),
7431 request.to_proto(project_id, buffer.read(cx)),
7432 );
7433 let buffer = buffer.clone();
7434 cx.spawn(async move |lsp_store, cx| {
7435 let Some(lsp_store) = lsp_store.upgrade() else {
7436 return Ok(None);
7437 };
7438 let colors = join_all(
7439 request_task
7440 .await
7441 .log_err()
7442 .flatten()
7443 .map(|response| response.payload)
7444 .unwrap_or_default()
7445 .into_iter()
7446 .map(|color_response| {
7447 let response = request.response_from_proto(
7448 color_response.response,
7449 lsp_store.clone(),
7450 buffer.clone(),
7451 cx.clone(),
7452 );
7453 async move {
7454 (
7455 LanguageServerId::from_proto(color_response.server_id),
7456 response.await.log_err().unwrap_or_default(),
7457 )
7458 }
7459 }),
7460 )
7461 .await
7462 .into_iter()
7463 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7464 acc.entry(server_id)
7465 .or_insert_with(HashSet::default)
7466 .extend(colors);
7467 acc
7468 });
7469 Ok(Some(colors))
7470 })
7471 } else {
7472 let document_colors_task =
7473 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7474 cx.background_spawn(async move {
7475 Ok(Some(
7476 document_colors_task
7477 .await
7478 .into_iter()
7479 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7480 acc.entry(server_id)
7481 .or_insert_with(HashSet::default)
7482 .extend(colors);
7483 acc
7484 })
7485 .into_iter()
7486 .collect(),
7487 ))
7488 })
7489 }
7490 }
7491
7492 pub fn signature_help<T: ToPointUtf16>(
7493 &mut self,
7494 buffer: &Entity<Buffer>,
7495 position: T,
7496 cx: &mut Context<Self>,
7497 ) -> Task<Option<Vec<SignatureHelp>>> {
7498 let position = position.to_point_utf16(buffer.read(cx));
7499
7500 if let Some((client, upstream_project_id)) = self.upstream_client() {
7501 let request = GetSignatureHelp { position };
7502 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7503 return Task::ready(None);
7504 }
7505 let request_task = client.request_lsp(
7506 upstream_project_id,
7507 None,
7508 LSP_REQUEST_TIMEOUT,
7509 cx.background_executor().clone(),
7510 request.to_proto(upstream_project_id, buffer.read(cx)),
7511 );
7512 let buffer = buffer.clone();
7513 cx.spawn(async move |weak_lsp_store, cx| {
7514 let lsp_store = weak_lsp_store.upgrade()?;
7515 let signatures = join_all(
7516 request_task
7517 .await
7518 .log_err()
7519 .flatten()
7520 .map(|response| response.payload)
7521 .unwrap_or_default()
7522 .into_iter()
7523 .map(|response| {
7524 let response = GetSignatureHelp { position }.response_from_proto(
7525 response.response,
7526 lsp_store.clone(),
7527 buffer.clone(),
7528 cx.clone(),
7529 );
7530 async move { response.await.log_err().flatten() }
7531 }),
7532 )
7533 .await
7534 .into_iter()
7535 .flatten()
7536 .collect();
7537 Some(signatures)
7538 })
7539 } else {
7540 let all_actions_task = self.request_multiple_lsp_locally(
7541 buffer,
7542 Some(position),
7543 GetSignatureHelp { position },
7544 cx,
7545 );
7546 cx.background_spawn(async move {
7547 Some(
7548 all_actions_task
7549 .await
7550 .into_iter()
7551 .flat_map(|(_, actions)| actions)
7552 .collect::<Vec<_>>(),
7553 )
7554 })
7555 }
7556 }
7557
7558 pub fn hover(
7559 &mut self,
7560 buffer: &Entity<Buffer>,
7561 position: PointUtf16,
7562 cx: &mut Context<Self>,
7563 ) -> Task<Option<Vec<Hover>>> {
7564 if let Some((client, upstream_project_id)) = self.upstream_client() {
7565 let request = GetHover { position };
7566 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7567 return Task::ready(None);
7568 }
7569 let request_task = client.request_lsp(
7570 upstream_project_id,
7571 None,
7572 LSP_REQUEST_TIMEOUT,
7573 cx.background_executor().clone(),
7574 request.to_proto(upstream_project_id, buffer.read(cx)),
7575 );
7576 let buffer = buffer.clone();
7577 cx.spawn(async move |weak_lsp_store, cx| {
7578 let lsp_store = weak_lsp_store.upgrade()?;
7579 let hovers = join_all(
7580 request_task
7581 .await
7582 .log_err()
7583 .flatten()
7584 .map(|response| response.payload)
7585 .unwrap_or_default()
7586 .into_iter()
7587 .map(|response| {
7588 let response = GetHover { position }.response_from_proto(
7589 response.response,
7590 lsp_store.clone(),
7591 buffer.clone(),
7592 cx.clone(),
7593 );
7594 async move {
7595 response
7596 .await
7597 .log_err()
7598 .flatten()
7599 .and_then(remove_empty_hover_blocks)
7600 }
7601 }),
7602 )
7603 .await
7604 .into_iter()
7605 .flatten()
7606 .collect();
7607 Some(hovers)
7608 })
7609 } else {
7610 let all_actions_task = self.request_multiple_lsp_locally(
7611 buffer,
7612 Some(position),
7613 GetHover { position },
7614 cx,
7615 );
7616 cx.background_spawn(async move {
7617 Some(
7618 all_actions_task
7619 .await
7620 .into_iter()
7621 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7622 .collect::<Vec<Hover>>(),
7623 )
7624 })
7625 }
7626 }
7627
7628 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7629 let language_registry = self.languages.clone();
7630
7631 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7632 let request = upstream_client.request(proto::GetProjectSymbols {
7633 project_id: *project_id,
7634 query: query.to_string(),
7635 });
7636 cx.foreground_executor().spawn(async move {
7637 let response = request.await?;
7638 let mut symbols = Vec::new();
7639 let core_symbols = response
7640 .symbols
7641 .into_iter()
7642 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7643 .collect::<Vec<_>>();
7644 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7645 .await;
7646 Ok(symbols)
7647 })
7648 } else if let Some(local) = self.as_local() {
7649 struct WorkspaceSymbolsResult {
7650 server_id: LanguageServerId,
7651 lsp_adapter: Arc<CachedLspAdapter>,
7652 worktree: WeakEntity<Worktree>,
7653 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7654 }
7655
7656 let mut requests = Vec::new();
7657 let mut requested_servers = BTreeSet::new();
7658 for (seed, state) in local.language_server_ids.iter() {
7659 let Some(worktree_handle) = self
7660 .worktree_store
7661 .read(cx)
7662 .worktree_for_id(seed.worktree_id, cx)
7663 else {
7664 continue;
7665 };
7666 let worktree = worktree_handle.read(cx);
7667 if !worktree.is_visible() {
7668 continue;
7669 }
7670
7671 if !requested_servers.insert(state.id) {
7672 continue;
7673 }
7674
7675 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7676 Some(LanguageServerState::Running {
7677 adapter, server, ..
7678 }) => (adapter.clone(), server),
7679
7680 _ => continue,
7681 };
7682 let supports_workspace_symbol_request =
7683 match server.capabilities().workspace_symbol_provider {
7684 Some(OneOf::Left(supported)) => supported,
7685 Some(OneOf::Right(_)) => true,
7686 None => false,
7687 };
7688 if !supports_workspace_symbol_request {
7689 continue;
7690 }
7691 let worktree_handle = worktree_handle.clone();
7692 let server_id = server.server_id();
7693 requests.push(
7694 server
7695 .request::<lsp::request::WorkspaceSymbolRequest>(
7696 lsp::WorkspaceSymbolParams {
7697 query: query.to_string(),
7698 ..Default::default()
7699 },
7700 )
7701 .map(move |response| {
7702 let lsp_symbols = response.into_response()
7703 .context("workspace symbols request")
7704 .log_err()
7705 .flatten()
7706 .map(|symbol_response| match symbol_response {
7707 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7708 flat_responses.into_iter().map(|lsp_symbol| {
7709 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7710 }).collect::<Vec<_>>()
7711 }
7712 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7713 nested_responses.into_iter().filter_map(|lsp_symbol| {
7714 let location = match lsp_symbol.location {
7715 OneOf::Left(location) => location,
7716 OneOf::Right(_) => {
7717 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7718 return None
7719 }
7720 };
7721 Some((lsp_symbol.name, lsp_symbol.kind, location))
7722 }).collect::<Vec<_>>()
7723 }
7724 }).unwrap_or_default();
7725
7726 WorkspaceSymbolsResult {
7727 server_id,
7728 lsp_adapter,
7729 worktree: worktree_handle.downgrade(),
7730 lsp_symbols,
7731 }
7732 }),
7733 );
7734 }
7735
7736 cx.spawn(async move |this, cx| {
7737 let responses = futures::future::join_all(requests).await;
7738 let this = match this.upgrade() {
7739 Some(this) => this,
7740 None => return Ok(Vec::new()),
7741 };
7742
7743 let mut symbols = Vec::new();
7744 for result in responses {
7745 let core_symbols = this.update(cx, |this, cx| {
7746 result
7747 .lsp_symbols
7748 .into_iter()
7749 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7750 let abs_path = symbol_location.uri.to_file_path().ok()?;
7751 let source_worktree = result.worktree.upgrade()?;
7752 let source_worktree_id = source_worktree.read(cx).id();
7753
7754 let path = if let Some((tree, rel_path)) =
7755 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7756 {
7757 let worktree_id = tree.read(cx).id();
7758 SymbolLocation::InProject(ProjectPath {
7759 worktree_id,
7760 path: rel_path,
7761 })
7762 } else {
7763 SymbolLocation::OutsideProject {
7764 signature: this.symbol_signature(&abs_path),
7765 abs_path: abs_path.into(),
7766 }
7767 };
7768
7769 Some(CoreSymbol {
7770 source_language_server_id: result.server_id,
7771 language_server_name: result.lsp_adapter.name.clone(),
7772 source_worktree_id,
7773 path,
7774 kind: symbol_kind,
7775 name: symbol_name,
7776 range: range_from_lsp(symbol_location.range),
7777 })
7778 })
7779 .collect()
7780 })?;
7781
7782 populate_labels_for_symbols(
7783 core_symbols,
7784 &language_registry,
7785 Some(result.lsp_adapter),
7786 &mut symbols,
7787 )
7788 .await;
7789 }
7790
7791 Ok(symbols)
7792 })
7793 } else {
7794 Task::ready(Err(anyhow!("No upstream client or local language server")))
7795 }
7796 }
7797
7798 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7799 let mut summary = DiagnosticSummary::default();
7800 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7801 summary.error_count += path_summary.error_count;
7802 summary.warning_count += path_summary.warning_count;
7803 }
7804 summary
7805 }
7806
7807 /// Returns the diagnostic summary for a specific project path.
7808 pub fn diagnostic_summary_for_path(
7809 &self,
7810 project_path: &ProjectPath,
7811 _: &App,
7812 ) -> DiagnosticSummary {
7813 if let Some(summaries) = self
7814 .diagnostic_summaries
7815 .get(&project_path.worktree_id)
7816 .and_then(|map| map.get(&project_path.path))
7817 {
7818 let (error_count, warning_count) = summaries.iter().fold(
7819 (0, 0),
7820 |(error_count, warning_count), (_language_server_id, summary)| {
7821 (
7822 error_count + summary.error_count,
7823 warning_count + summary.warning_count,
7824 )
7825 },
7826 );
7827
7828 DiagnosticSummary {
7829 error_count,
7830 warning_count,
7831 }
7832 } else {
7833 DiagnosticSummary::default()
7834 }
7835 }
7836
7837 pub fn diagnostic_summaries<'a>(
7838 &'a self,
7839 include_ignored: bool,
7840 cx: &'a App,
7841 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7842 self.worktree_store
7843 .read(cx)
7844 .visible_worktrees(cx)
7845 .filter_map(|worktree| {
7846 let worktree = worktree.read(cx);
7847 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7848 })
7849 .flat_map(move |(worktree, summaries)| {
7850 let worktree_id = worktree.id();
7851 summaries
7852 .iter()
7853 .filter(move |(path, _)| {
7854 include_ignored
7855 || worktree
7856 .entry_for_path(path.as_ref())
7857 .is_some_and(|entry| !entry.is_ignored)
7858 })
7859 .flat_map(move |(path, summaries)| {
7860 summaries.iter().map(move |(server_id, summary)| {
7861 (
7862 ProjectPath {
7863 worktree_id,
7864 path: path.clone(),
7865 },
7866 *server_id,
7867 *summary,
7868 )
7869 })
7870 })
7871 })
7872 }
7873
7874 pub fn on_buffer_edited(
7875 &mut self,
7876 buffer: Entity<Buffer>,
7877 cx: &mut Context<Self>,
7878 ) -> Option<()> {
7879 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7880 Some(
7881 self.as_local()?
7882 .language_servers_for_buffer(buffer, cx)
7883 .map(|i| i.1.clone())
7884 .collect(),
7885 )
7886 })?;
7887
7888 let buffer = buffer.read(cx);
7889 let file = File::from_dyn(buffer.file())?;
7890 let abs_path = file.as_local()?.abs_path(cx);
7891 let uri = lsp::Uri::from_file_path(&abs_path)
7892 .ok()
7893 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7894 .log_err()?;
7895 let next_snapshot = buffer.text_snapshot();
7896 for language_server in language_servers {
7897 let language_server = language_server.clone();
7898
7899 let buffer_snapshots = self
7900 .as_local_mut()?
7901 .buffer_snapshots
7902 .get_mut(&buffer.remote_id())
7903 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7904 let previous_snapshot = buffer_snapshots.last()?;
7905
7906 let build_incremental_change = || {
7907 buffer
7908 .edits_since::<Dimensions<PointUtf16, usize>>(
7909 previous_snapshot.snapshot.version(),
7910 )
7911 .map(|edit| {
7912 let edit_start = edit.new.start.0;
7913 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7914 let new_text = next_snapshot
7915 .text_for_range(edit.new.start.1..edit.new.end.1)
7916 .collect();
7917 lsp::TextDocumentContentChangeEvent {
7918 range: Some(lsp::Range::new(
7919 point_to_lsp(edit_start),
7920 point_to_lsp(edit_end),
7921 )),
7922 range_length: None,
7923 text: new_text,
7924 }
7925 })
7926 .collect()
7927 };
7928
7929 let document_sync_kind = language_server
7930 .capabilities()
7931 .text_document_sync
7932 .as_ref()
7933 .and_then(|sync| match sync {
7934 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7935 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7936 });
7937
7938 let content_changes: Vec<_> = match document_sync_kind {
7939 Some(lsp::TextDocumentSyncKind::FULL) => {
7940 vec![lsp::TextDocumentContentChangeEvent {
7941 range: None,
7942 range_length: None,
7943 text: next_snapshot.text(),
7944 }]
7945 }
7946 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7947 _ => {
7948 #[cfg(any(test, feature = "test-support"))]
7949 {
7950 build_incremental_change()
7951 }
7952
7953 #[cfg(not(any(test, feature = "test-support")))]
7954 {
7955 continue;
7956 }
7957 }
7958 };
7959
7960 let next_version = previous_snapshot.version + 1;
7961 buffer_snapshots.push(LspBufferSnapshot {
7962 version: next_version,
7963 snapshot: next_snapshot.clone(),
7964 });
7965
7966 language_server
7967 .notify::<lsp::notification::DidChangeTextDocument>(
7968 lsp::DidChangeTextDocumentParams {
7969 text_document: lsp::VersionedTextDocumentIdentifier::new(
7970 uri.clone(),
7971 next_version,
7972 ),
7973 content_changes,
7974 },
7975 )
7976 .ok();
7977 self.pull_workspace_diagnostics(language_server.server_id());
7978 }
7979
7980 None
7981 }
7982
7983 pub fn on_buffer_saved(
7984 &mut self,
7985 buffer: Entity<Buffer>,
7986 cx: &mut Context<Self>,
7987 ) -> Option<()> {
7988 let file = File::from_dyn(buffer.read(cx).file())?;
7989 let worktree_id = file.worktree_id(cx);
7990 let abs_path = file.as_local()?.abs_path(cx);
7991 let text_document = lsp::TextDocumentIdentifier {
7992 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7993 };
7994 let local = self.as_local()?;
7995
7996 for server in local.language_servers_for_worktree(worktree_id) {
7997 if let Some(include_text) = include_text(server.as_ref()) {
7998 let text = if include_text {
7999 Some(buffer.read(cx).text())
8000 } else {
8001 None
8002 };
8003 server
8004 .notify::<lsp::notification::DidSaveTextDocument>(
8005 lsp::DidSaveTextDocumentParams {
8006 text_document: text_document.clone(),
8007 text,
8008 },
8009 )
8010 .ok();
8011 }
8012 }
8013
8014 let language_servers = buffer.update(cx, |buffer, cx| {
8015 local.language_server_ids_for_buffer(buffer, cx)
8016 });
8017 for language_server_id in language_servers {
8018 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8019 }
8020
8021 None
8022 }
8023
8024 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8025 maybe!(async move {
8026 let mut refreshed_servers = HashSet::default();
8027 let servers = lsp_store
8028 .update(cx, |lsp_store, cx| {
8029 let local = lsp_store.as_local()?;
8030
8031 let servers = local
8032 .language_server_ids
8033 .iter()
8034 .filter_map(|(seed, state)| {
8035 let worktree = lsp_store
8036 .worktree_store
8037 .read(cx)
8038 .worktree_for_id(seed.worktree_id, cx);
8039 let delegate: Arc<dyn LspAdapterDelegate> =
8040 worktree.map(|worktree| {
8041 LocalLspAdapterDelegate::new(
8042 local.languages.clone(),
8043 &local.environment,
8044 cx.weak_entity(),
8045 &worktree,
8046 local.http_client.clone(),
8047 local.fs.clone(),
8048 cx,
8049 )
8050 })?;
8051 let server_id = state.id;
8052
8053 let states = local.language_servers.get(&server_id)?;
8054
8055 match states {
8056 LanguageServerState::Starting { .. } => None,
8057 LanguageServerState::Running {
8058 adapter, server, ..
8059 } => {
8060 let adapter = adapter.clone();
8061 let server = server.clone();
8062 refreshed_servers.insert(server.name());
8063 let toolchain = seed.toolchain.clone();
8064 Some(cx.spawn(async move |_, cx| {
8065 let settings =
8066 LocalLspStore::workspace_configuration_for_adapter(
8067 adapter.adapter.clone(),
8068 &delegate,
8069 toolchain,
8070 None,
8071 cx,
8072 )
8073 .await
8074 .ok()?;
8075 server
8076 .notify::<lsp::notification::DidChangeConfiguration>(
8077 lsp::DidChangeConfigurationParams { settings },
8078 )
8079 .ok()?;
8080 Some(())
8081 }))
8082 }
8083 }
8084 })
8085 .collect::<Vec<_>>();
8086
8087 Some(servers)
8088 })
8089 .ok()
8090 .flatten()?;
8091
8092 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8093 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8094 // to stop and unregister its language server wrapper.
8095 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8096 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8097 let _: Vec<Option<()>> = join_all(servers).await;
8098
8099 Some(())
8100 })
8101 .await;
8102 }
8103
8104 fn maintain_workspace_config(
8105 external_refresh_requests: watch::Receiver<()>,
8106 cx: &mut Context<Self>,
8107 ) -> Task<Result<()>> {
8108 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8109 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8110
8111 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8112 *settings_changed_tx.borrow_mut() = ();
8113 });
8114
8115 let mut joint_future =
8116 futures::stream::select(settings_changed_rx, external_refresh_requests);
8117 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8118 // - 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).
8119 // - 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.
8120 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8121 // - 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,
8122 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8123 cx.spawn(async move |this, cx| {
8124 while let Some(()) = joint_future.next().await {
8125 this.update(cx, |this, cx| {
8126 this.refresh_server_tree(cx);
8127 })
8128 .ok();
8129
8130 Self::refresh_workspace_configurations(&this, cx).await;
8131 }
8132
8133 drop(settings_observation);
8134 anyhow::Ok(())
8135 })
8136 }
8137
8138 pub fn running_language_servers_for_local_buffer<'a>(
8139 &'a self,
8140 buffer: &Buffer,
8141 cx: &mut App,
8142 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8143 let local = self.as_local();
8144 let language_server_ids = local
8145 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8146 .unwrap_or_default();
8147
8148 language_server_ids
8149 .into_iter()
8150 .filter_map(
8151 move |server_id| match local?.language_servers.get(&server_id)? {
8152 LanguageServerState::Running {
8153 adapter, server, ..
8154 } => Some((adapter, server)),
8155 _ => None,
8156 },
8157 )
8158 }
8159
8160 pub fn language_servers_for_local_buffer(
8161 &self,
8162 buffer: &Buffer,
8163 cx: &mut App,
8164 ) -> Vec<LanguageServerId> {
8165 let local = self.as_local();
8166 local
8167 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8168 .unwrap_or_default()
8169 }
8170
8171 pub fn language_server_for_local_buffer<'a>(
8172 &'a self,
8173 buffer: &'a Buffer,
8174 server_id: LanguageServerId,
8175 cx: &'a mut App,
8176 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8177 self.as_local()?
8178 .language_servers_for_buffer(buffer, cx)
8179 .find(|(_, s)| s.server_id() == server_id)
8180 }
8181
8182 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8183 self.diagnostic_summaries.remove(&id_to_remove);
8184 if let Some(local) = self.as_local_mut() {
8185 let to_remove = local.remove_worktree(id_to_remove, cx);
8186 for server in to_remove {
8187 self.language_server_statuses.remove(&server);
8188 }
8189 }
8190 }
8191
8192 pub fn shared(
8193 &mut self,
8194 project_id: u64,
8195 downstream_client: AnyProtoClient,
8196 _: &mut Context<Self>,
8197 ) {
8198 self.downstream_client = Some((downstream_client.clone(), project_id));
8199
8200 for (server_id, status) in &self.language_server_statuses {
8201 if let Some(server) = self.language_server_for_id(*server_id) {
8202 downstream_client
8203 .send(proto::StartLanguageServer {
8204 project_id,
8205 server: Some(proto::LanguageServer {
8206 id: server_id.to_proto(),
8207 name: status.name.to_string(),
8208 worktree_id: status.worktree.map(|id| id.to_proto()),
8209 }),
8210 capabilities: serde_json::to_string(&server.capabilities())
8211 .expect("serializing server LSP capabilities"),
8212 })
8213 .log_err();
8214 }
8215 }
8216 }
8217
8218 pub fn disconnected_from_host(&mut self) {
8219 self.downstream_client.take();
8220 }
8221
8222 pub fn disconnected_from_ssh_remote(&mut self) {
8223 if let LspStoreMode::Remote(RemoteLspStore {
8224 upstream_client, ..
8225 }) = &mut self.mode
8226 {
8227 upstream_client.take();
8228 }
8229 }
8230
8231 pub(crate) fn set_language_server_statuses_from_proto(
8232 &mut self,
8233 project: WeakEntity<Project>,
8234 language_servers: Vec<proto::LanguageServer>,
8235 server_capabilities: Vec<String>,
8236 cx: &mut Context<Self>,
8237 ) {
8238 let lsp_logs = cx
8239 .try_global::<GlobalLogStore>()
8240 .map(|lsp_store| lsp_store.0.clone());
8241
8242 self.language_server_statuses = language_servers
8243 .into_iter()
8244 .zip(server_capabilities)
8245 .map(|(server, server_capabilities)| {
8246 let server_id = LanguageServerId(server.id as usize);
8247 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8248 self.lsp_server_capabilities
8249 .insert(server_id, server_capabilities);
8250 }
8251
8252 let name = LanguageServerName::from_proto(server.name);
8253 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8254
8255 if let Some(lsp_logs) = &lsp_logs {
8256 lsp_logs.update(cx, |lsp_logs, cx| {
8257 lsp_logs.add_language_server(
8258 // Only remote clients get their language servers set from proto
8259 LanguageServerKind::Remote {
8260 project: project.clone(),
8261 },
8262 server_id,
8263 Some(name.clone()),
8264 worktree,
8265 None,
8266 cx,
8267 );
8268 });
8269 }
8270
8271 (
8272 server_id,
8273 LanguageServerStatus {
8274 name,
8275 pending_work: Default::default(),
8276 has_pending_diagnostic_updates: false,
8277 progress_tokens: Default::default(),
8278 worktree,
8279 binary: None,
8280 configuration: None,
8281 workspace_folders: BTreeSet::new(),
8282 },
8283 )
8284 })
8285 .collect();
8286 }
8287
8288 #[cfg(test)]
8289 pub fn update_diagnostic_entries(
8290 &mut self,
8291 server_id: LanguageServerId,
8292 abs_path: PathBuf,
8293 result_id: Option<SharedString>,
8294 version: Option<i32>,
8295 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8296 cx: &mut Context<Self>,
8297 ) -> anyhow::Result<()> {
8298 self.merge_diagnostic_entries(
8299 vec![DocumentDiagnosticsUpdate {
8300 diagnostics: DocumentDiagnostics {
8301 diagnostics,
8302 document_abs_path: abs_path,
8303 version,
8304 },
8305 result_id,
8306 server_id,
8307 disk_based_sources: Cow::Borrowed(&[]),
8308 registration_id: None,
8309 }],
8310 |_, _, _| false,
8311 cx,
8312 )?;
8313 Ok(())
8314 }
8315
8316 pub fn merge_diagnostic_entries<'a>(
8317 &mut self,
8318 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8319 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8320 cx: &mut Context<Self>,
8321 ) -> anyhow::Result<()> {
8322 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8323 let mut updated_diagnostics_paths = HashMap::default();
8324 for mut update in diagnostic_updates {
8325 let abs_path = &update.diagnostics.document_abs_path;
8326 let server_id = update.server_id;
8327 let Some((worktree, relative_path)) =
8328 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8329 else {
8330 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8331 return Ok(());
8332 };
8333
8334 let worktree_id = worktree.read(cx).id();
8335 let project_path = ProjectPath {
8336 worktree_id,
8337 path: relative_path,
8338 };
8339
8340 let document_uri = lsp::Uri::from_file_path(abs_path)
8341 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8342 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8343 let snapshot = buffer_handle.read(cx).snapshot();
8344 let buffer = buffer_handle.read(cx);
8345 let reused_diagnostics = buffer
8346 .buffer_diagnostics(Some(server_id))
8347 .iter()
8348 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8349 .map(|v| {
8350 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8351 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8352 DiagnosticEntry {
8353 range: start..end,
8354 diagnostic: v.diagnostic.clone(),
8355 }
8356 })
8357 .collect::<Vec<_>>();
8358
8359 self.as_local_mut()
8360 .context("cannot merge diagnostics on a remote LspStore")?
8361 .update_buffer_diagnostics(
8362 &buffer_handle,
8363 server_id,
8364 Some(update.registration_id),
8365 update.result_id,
8366 update.diagnostics.version,
8367 update.diagnostics.diagnostics.clone(),
8368 reused_diagnostics.clone(),
8369 cx,
8370 )?;
8371
8372 update.diagnostics.diagnostics.extend(reused_diagnostics);
8373 } else if let Some(local) = self.as_local() {
8374 let reused_diagnostics = local
8375 .diagnostics
8376 .get(&worktree_id)
8377 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8378 .and_then(|diagnostics_by_server_id| {
8379 diagnostics_by_server_id
8380 .binary_search_by_key(&server_id, |e| e.0)
8381 .ok()
8382 .map(|ix| &diagnostics_by_server_id[ix].1)
8383 })
8384 .into_iter()
8385 .flatten()
8386 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8387
8388 update
8389 .diagnostics
8390 .diagnostics
8391 .extend(reused_diagnostics.cloned());
8392 }
8393
8394 let updated = worktree.update(cx, |worktree, cx| {
8395 self.update_worktree_diagnostics(
8396 worktree.id(),
8397 server_id,
8398 project_path.path.clone(),
8399 update.diagnostics.diagnostics,
8400 cx,
8401 )
8402 })?;
8403 match updated {
8404 ControlFlow::Continue(new_summary) => {
8405 if let Some((project_id, new_summary)) = new_summary {
8406 match &mut diagnostics_summary {
8407 Some(diagnostics_summary) => {
8408 diagnostics_summary
8409 .more_summaries
8410 .push(proto::DiagnosticSummary {
8411 path: project_path.path.as_ref().to_proto(),
8412 language_server_id: server_id.0 as u64,
8413 error_count: new_summary.error_count,
8414 warning_count: new_summary.warning_count,
8415 })
8416 }
8417 None => {
8418 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8419 project_id,
8420 worktree_id: worktree_id.to_proto(),
8421 summary: Some(proto::DiagnosticSummary {
8422 path: project_path.path.as_ref().to_proto(),
8423 language_server_id: server_id.0 as u64,
8424 error_count: new_summary.error_count,
8425 warning_count: new_summary.warning_count,
8426 }),
8427 more_summaries: Vec::new(),
8428 })
8429 }
8430 }
8431 }
8432 updated_diagnostics_paths
8433 .entry(server_id)
8434 .or_insert_with(Vec::new)
8435 .push(project_path);
8436 }
8437 ControlFlow::Break(()) => {}
8438 }
8439 }
8440
8441 if let Some((diagnostics_summary, (downstream_client, _))) =
8442 diagnostics_summary.zip(self.downstream_client.as_ref())
8443 {
8444 downstream_client.send(diagnostics_summary).log_err();
8445 }
8446 for (server_id, paths) in updated_diagnostics_paths {
8447 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8448 }
8449 Ok(())
8450 }
8451
8452 fn update_worktree_diagnostics(
8453 &mut self,
8454 worktree_id: WorktreeId,
8455 server_id: LanguageServerId,
8456 path_in_worktree: Arc<RelPath>,
8457 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8458 _: &mut Context<Worktree>,
8459 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8460 let local = match &mut self.mode {
8461 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8462 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8463 };
8464
8465 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8466 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8467 let summaries_by_server_id = summaries_for_tree
8468 .entry(path_in_worktree.clone())
8469 .or_default();
8470
8471 let old_summary = summaries_by_server_id
8472 .remove(&server_id)
8473 .unwrap_or_default();
8474
8475 let new_summary = DiagnosticSummary::new(&diagnostics);
8476 if diagnostics.is_empty() {
8477 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8478 {
8479 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8480 diagnostics_by_server_id.remove(ix);
8481 }
8482 if diagnostics_by_server_id.is_empty() {
8483 diagnostics_for_tree.remove(&path_in_worktree);
8484 }
8485 }
8486 } else {
8487 summaries_by_server_id.insert(server_id, new_summary);
8488 let diagnostics_by_server_id = diagnostics_for_tree
8489 .entry(path_in_worktree.clone())
8490 .or_default();
8491 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8492 Ok(ix) => {
8493 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8494 }
8495 Err(ix) => {
8496 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8497 }
8498 }
8499 }
8500
8501 if !old_summary.is_empty() || !new_summary.is_empty() {
8502 if let Some((_, project_id)) = &self.downstream_client {
8503 Ok(ControlFlow::Continue(Some((
8504 *project_id,
8505 proto::DiagnosticSummary {
8506 path: path_in_worktree.to_proto(),
8507 language_server_id: server_id.0 as u64,
8508 error_count: new_summary.error_count as u32,
8509 warning_count: new_summary.warning_count as u32,
8510 },
8511 ))))
8512 } else {
8513 Ok(ControlFlow::Continue(None))
8514 }
8515 } else {
8516 Ok(ControlFlow::Break(()))
8517 }
8518 }
8519
8520 pub fn open_buffer_for_symbol(
8521 &mut self,
8522 symbol: &Symbol,
8523 cx: &mut Context<Self>,
8524 ) -> Task<Result<Entity<Buffer>>> {
8525 if let Some((client, project_id)) = self.upstream_client() {
8526 let request = client.request(proto::OpenBufferForSymbol {
8527 project_id,
8528 symbol: Some(Self::serialize_symbol(symbol)),
8529 });
8530 cx.spawn(async move |this, cx| {
8531 let response = request.await?;
8532 let buffer_id = BufferId::new(response.buffer_id)?;
8533 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8534 .await
8535 })
8536 } else if let Some(local) = self.as_local() {
8537 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8538 seed.worktree_id == symbol.source_worktree_id
8539 && state.id == symbol.source_language_server_id
8540 && symbol.language_server_name == seed.name
8541 });
8542 if !is_valid {
8543 return Task::ready(Err(anyhow!(
8544 "language server for worktree and language not found"
8545 )));
8546 };
8547
8548 let symbol_abs_path = match &symbol.path {
8549 SymbolLocation::InProject(project_path) => self
8550 .worktree_store
8551 .read(cx)
8552 .absolutize(&project_path, cx)
8553 .context("no such worktree"),
8554 SymbolLocation::OutsideProject {
8555 abs_path,
8556 signature: _,
8557 } => Ok(abs_path.to_path_buf()),
8558 };
8559 let symbol_abs_path = match symbol_abs_path {
8560 Ok(abs_path) => abs_path,
8561 Err(err) => return Task::ready(Err(err)),
8562 };
8563 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8564 uri
8565 } else {
8566 return Task::ready(Err(anyhow!("invalid symbol path")));
8567 };
8568
8569 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8570 } else {
8571 Task::ready(Err(anyhow!("no upstream client or local store")))
8572 }
8573 }
8574
8575 pub(crate) fn open_local_buffer_via_lsp(
8576 &mut self,
8577 abs_path: lsp::Uri,
8578 language_server_id: LanguageServerId,
8579 cx: &mut Context<Self>,
8580 ) -> Task<Result<Entity<Buffer>>> {
8581 cx.spawn(async move |lsp_store, cx| {
8582 // Escape percent-encoded string.
8583 let current_scheme = abs_path.scheme().to_owned();
8584 // Uri is immutable, so we can't modify the scheme
8585
8586 let abs_path = abs_path
8587 .to_file_path()
8588 .map_err(|()| anyhow!("can't convert URI to path"))?;
8589 let p = abs_path.clone();
8590 let yarn_worktree = lsp_store
8591 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8592 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8593 cx.spawn(async move |this, cx| {
8594 let t = this
8595 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8596 .ok()?;
8597 t.await
8598 })
8599 }),
8600 None => Task::ready(None),
8601 })?
8602 .await;
8603 let (worktree_root_target, known_relative_path) =
8604 if let Some((zip_root, relative_path)) = yarn_worktree {
8605 (zip_root, Some(relative_path))
8606 } else {
8607 (Arc::<Path>::from(abs_path.as_path()), None)
8608 };
8609 let (worktree, relative_path) = if let Some(result) =
8610 lsp_store.update(cx, |lsp_store, cx| {
8611 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8612 worktree_store.find_worktree(&worktree_root_target, cx)
8613 })
8614 })? {
8615 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8616 (result.0, relative_path)
8617 } else {
8618 let worktree = lsp_store
8619 .update(cx, |lsp_store, cx| {
8620 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8621 worktree_store.create_worktree(&worktree_root_target, false, cx)
8622 })
8623 })?
8624 .await?;
8625 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8626 lsp_store
8627 .update(cx, |lsp_store, cx| {
8628 if let Some(local) = lsp_store.as_local_mut() {
8629 local.register_language_server_for_invisible_worktree(
8630 &worktree,
8631 language_server_id,
8632 cx,
8633 )
8634 }
8635 })
8636 .ok();
8637 }
8638 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8639 let relative_path = if let Some(known_path) = known_relative_path {
8640 known_path
8641 } else {
8642 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8643 .into_arc()
8644 };
8645 (worktree, relative_path)
8646 };
8647 let project_path = ProjectPath {
8648 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8649 path: relative_path,
8650 };
8651 lsp_store
8652 .update(cx, |lsp_store, cx| {
8653 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8654 buffer_store.open_buffer(project_path, cx)
8655 })
8656 })?
8657 .await
8658 })
8659 }
8660
8661 fn request_multiple_lsp_locally<P, R>(
8662 &mut self,
8663 buffer: &Entity<Buffer>,
8664 position: Option<P>,
8665 request: R,
8666 cx: &mut Context<Self>,
8667 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8668 where
8669 P: ToOffset,
8670 R: LspCommand + Clone,
8671 <R::LspRequest as lsp::request::Request>::Result: Send,
8672 <R::LspRequest as lsp::request::Request>::Params: Send,
8673 {
8674 let Some(local) = self.as_local() else {
8675 return Task::ready(Vec::new());
8676 };
8677
8678 let snapshot = buffer.read(cx).snapshot();
8679 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8680
8681 let server_ids = buffer.update(cx, |buffer, cx| {
8682 local
8683 .language_servers_for_buffer(buffer, cx)
8684 .filter(|(adapter, _)| {
8685 scope
8686 .as_ref()
8687 .map(|scope| scope.language_allowed(&adapter.name))
8688 .unwrap_or(true)
8689 })
8690 .map(|(_, server)| server.server_id())
8691 .filter(|server_id| {
8692 self.as_local().is_none_or(|local| {
8693 local
8694 .buffers_opened_in_servers
8695 .get(&snapshot.remote_id())
8696 .is_some_and(|servers| servers.contains(server_id))
8697 })
8698 })
8699 .collect::<Vec<_>>()
8700 });
8701
8702 let mut response_results = server_ids
8703 .into_iter()
8704 .map(|server_id| {
8705 let task = self.request_lsp(
8706 buffer.clone(),
8707 LanguageServerToQuery::Other(server_id),
8708 request.clone(),
8709 cx,
8710 );
8711 async move { (server_id, task.await) }
8712 })
8713 .collect::<FuturesUnordered<_>>();
8714
8715 cx.background_spawn(async move {
8716 let mut responses = Vec::with_capacity(response_results.len());
8717 while let Some((server_id, response_result)) = response_results.next().await {
8718 match response_result {
8719 Ok(response) => responses.push((server_id, response)),
8720 // rust-analyzer likes to error with this when its still loading up
8721 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8722 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8723 }
8724 }
8725 responses
8726 })
8727 }
8728
8729 async fn handle_lsp_get_completions(
8730 this: Entity<Self>,
8731 envelope: TypedEnvelope<proto::GetCompletions>,
8732 mut cx: AsyncApp,
8733 ) -> Result<proto::GetCompletionsResponse> {
8734 let sender_id = envelope.original_sender_id().unwrap_or_default();
8735
8736 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8737 let buffer_handle = this.update(&mut cx, |this, cx| {
8738 this.buffer_store.read(cx).get_existing(buffer_id)
8739 })??;
8740 let request = GetCompletions::from_proto(
8741 envelope.payload,
8742 this.clone(),
8743 buffer_handle.clone(),
8744 cx.clone(),
8745 )
8746 .await?;
8747
8748 let server_to_query = match request.server_id {
8749 Some(server_id) => LanguageServerToQuery::Other(server_id),
8750 None => LanguageServerToQuery::FirstCapable,
8751 };
8752
8753 let response = this
8754 .update(&mut cx, |this, cx| {
8755 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8756 })?
8757 .await?;
8758 this.update(&mut cx, |this, cx| {
8759 Ok(GetCompletions::response_to_proto(
8760 response,
8761 this,
8762 sender_id,
8763 &buffer_handle.read(cx).version(),
8764 cx,
8765 ))
8766 })?
8767 }
8768
8769 async fn handle_lsp_command<T: LspCommand>(
8770 this: Entity<Self>,
8771 envelope: TypedEnvelope<T::ProtoRequest>,
8772 mut cx: AsyncApp,
8773 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8774 where
8775 <T::LspRequest as lsp::request::Request>::Params: Send,
8776 <T::LspRequest as lsp::request::Request>::Result: Send,
8777 {
8778 let sender_id = envelope.original_sender_id().unwrap_or_default();
8779 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8780 let buffer_handle = this.update(&mut cx, |this, cx| {
8781 this.buffer_store.read(cx).get_existing(buffer_id)
8782 })??;
8783 let request = T::from_proto(
8784 envelope.payload,
8785 this.clone(),
8786 buffer_handle.clone(),
8787 cx.clone(),
8788 )
8789 .await?;
8790 let response = this
8791 .update(&mut cx, |this, cx| {
8792 this.request_lsp(
8793 buffer_handle.clone(),
8794 LanguageServerToQuery::FirstCapable,
8795 request,
8796 cx,
8797 )
8798 })?
8799 .await?;
8800 this.update(&mut cx, |this, cx| {
8801 Ok(T::response_to_proto(
8802 response,
8803 this,
8804 sender_id,
8805 &buffer_handle.read(cx).version(),
8806 cx,
8807 ))
8808 })?
8809 }
8810
8811 async fn handle_lsp_query(
8812 lsp_store: Entity<Self>,
8813 envelope: TypedEnvelope<proto::LspQuery>,
8814 mut cx: AsyncApp,
8815 ) -> Result<proto::Ack> {
8816 use proto::lsp_query::Request;
8817 let sender_id = envelope.original_sender_id().unwrap_or_default();
8818 let lsp_query = envelope.payload;
8819 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8820 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8821 match lsp_query.request.context("invalid LSP query request")? {
8822 Request::GetReferences(get_references) => {
8823 let position = get_references.position.clone().and_then(deserialize_anchor);
8824 Self::query_lsp_locally::<GetReferences>(
8825 lsp_store,
8826 server_id,
8827 sender_id,
8828 lsp_request_id,
8829 get_references,
8830 position,
8831 &mut cx,
8832 )
8833 .await?;
8834 }
8835 Request::GetDocumentColor(get_document_color) => {
8836 Self::query_lsp_locally::<GetDocumentColor>(
8837 lsp_store,
8838 server_id,
8839 sender_id,
8840 lsp_request_id,
8841 get_document_color,
8842 None,
8843 &mut cx,
8844 )
8845 .await?;
8846 }
8847 Request::GetHover(get_hover) => {
8848 let position = get_hover.position.clone().and_then(deserialize_anchor);
8849 Self::query_lsp_locally::<GetHover>(
8850 lsp_store,
8851 server_id,
8852 sender_id,
8853 lsp_request_id,
8854 get_hover,
8855 position,
8856 &mut cx,
8857 )
8858 .await?;
8859 }
8860 Request::GetCodeActions(get_code_actions) => {
8861 Self::query_lsp_locally::<GetCodeActions>(
8862 lsp_store,
8863 server_id,
8864 sender_id,
8865 lsp_request_id,
8866 get_code_actions,
8867 None,
8868 &mut cx,
8869 )
8870 .await?;
8871 }
8872 Request::GetSignatureHelp(get_signature_help) => {
8873 let position = get_signature_help
8874 .position
8875 .clone()
8876 .and_then(deserialize_anchor);
8877 Self::query_lsp_locally::<GetSignatureHelp>(
8878 lsp_store,
8879 server_id,
8880 sender_id,
8881 lsp_request_id,
8882 get_signature_help,
8883 position,
8884 &mut cx,
8885 )
8886 .await?;
8887 }
8888 Request::GetCodeLens(get_code_lens) => {
8889 Self::query_lsp_locally::<GetCodeLens>(
8890 lsp_store,
8891 server_id,
8892 sender_id,
8893 lsp_request_id,
8894 get_code_lens,
8895 None,
8896 &mut cx,
8897 )
8898 .await?;
8899 }
8900 Request::GetDefinition(get_definition) => {
8901 let position = get_definition.position.clone().and_then(deserialize_anchor);
8902 Self::query_lsp_locally::<GetDefinitions>(
8903 lsp_store,
8904 server_id,
8905 sender_id,
8906 lsp_request_id,
8907 get_definition,
8908 position,
8909 &mut cx,
8910 )
8911 .await?;
8912 }
8913 Request::GetDeclaration(get_declaration) => {
8914 let position = get_declaration
8915 .position
8916 .clone()
8917 .and_then(deserialize_anchor);
8918 Self::query_lsp_locally::<GetDeclarations>(
8919 lsp_store,
8920 server_id,
8921 sender_id,
8922 lsp_request_id,
8923 get_declaration,
8924 position,
8925 &mut cx,
8926 )
8927 .await?;
8928 }
8929 Request::GetTypeDefinition(get_type_definition) => {
8930 let position = get_type_definition
8931 .position
8932 .clone()
8933 .and_then(deserialize_anchor);
8934 Self::query_lsp_locally::<GetTypeDefinitions>(
8935 lsp_store,
8936 server_id,
8937 sender_id,
8938 lsp_request_id,
8939 get_type_definition,
8940 position,
8941 &mut cx,
8942 )
8943 .await?;
8944 }
8945 Request::GetImplementation(get_implementation) => {
8946 let position = get_implementation
8947 .position
8948 .clone()
8949 .and_then(deserialize_anchor);
8950 Self::query_lsp_locally::<GetImplementations>(
8951 lsp_store,
8952 server_id,
8953 sender_id,
8954 lsp_request_id,
8955 get_implementation,
8956 position,
8957 &mut cx,
8958 )
8959 .await?;
8960 }
8961 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8962 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8963 let version = deserialize_version(get_document_diagnostics.buffer_version());
8964 let buffer = lsp_store.update(&mut cx, |this, cx| {
8965 this.buffer_store.read(cx).get_existing(buffer_id)
8966 })??;
8967 buffer
8968 .update(&mut cx, |buffer, _| {
8969 buffer.wait_for_version(version.clone())
8970 })?
8971 .await?;
8972 lsp_store.update(&mut cx, |lsp_store, cx| {
8973 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8974 let key = LspKey {
8975 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8976 server_queried: server_id,
8977 };
8978 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8979 ) {
8980 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8981 lsp_requests.clear();
8982 };
8983 }
8984
8985 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8986 existing_queries.insert(
8987 lsp_request_id,
8988 cx.spawn(async move |lsp_store, cx| {
8989 let diagnostics_pull = lsp_store
8990 .update(cx, |lsp_store, cx| {
8991 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8992 })
8993 .ok();
8994 if let Some(diagnostics_pull) = diagnostics_pull {
8995 match diagnostics_pull.await {
8996 Ok(()) => {}
8997 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8998 };
8999 }
9000 }),
9001 );
9002 })?;
9003 }
9004 Request::InlayHints(inlay_hints) => {
9005 let query_start = inlay_hints
9006 .start
9007 .clone()
9008 .and_then(deserialize_anchor)
9009 .context("invalid inlay hints range start")?;
9010 let query_end = inlay_hints
9011 .end
9012 .clone()
9013 .and_then(deserialize_anchor)
9014 .context("invalid inlay hints range end")?;
9015 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9016 &lsp_store,
9017 server_id,
9018 lsp_request_id,
9019 &inlay_hints,
9020 query_start..query_end,
9021 &mut cx,
9022 )
9023 .await
9024 .context("preparing inlay hints request")?;
9025 Self::query_lsp_locally::<InlayHints>(
9026 lsp_store,
9027 server_id,
9028 sender_id,
9029 lsp_request_id,
9030 inlay_hints,
9031 None,
9032 &mut cx,
9033 )
9034 .await
9035 .context("querying for inlay hints")?
9036 }
9037 }
9038 Ok(proto::Ack {})
9039 }
9040
9041 async fn handle_lsp_query_response(
9042 lsp_store: Entity<Self>,
9043 envelope: TypedEnvelope<proto::LspQueryResponse>,
9044 cx: AsyncApp,
9045 ) -> Result<()> {
9046 lsp_store.read_with(&cx, |lsp_store, _| {
9047 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9048 upstream_client.handle_lsp_response(envelope.clone());
9049 }
9050 })?;
9051 Ok(())
9052 }
9053
9054 async fn handle_apply_code_action(
9055 this: Entity<Self>,
9056 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9057 mut cx: AsyncApp,
9058 ) -> Result<proto::ApplyCodeActionResponse> {
9059 let sender_id = envelope.original_sender_id().unwrap_or_default();
9060 let action =
9061 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9062 let apply_code_action = this.update(&mut cx, |this, cx| {
9063 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9064 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9065 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9066 })??;
9067
9068 let project_transaction = apply_code_action.await?;
9069 let project_transaction = this.update(&mut cx, |this, cx| {
9070 this.buffer_store.update(cx, |buffer_store, cx| {
9071 buffer_store.serialize_project_transaction_for_peer(
9072 project_transaction,
9073 sender_id,
9074 cx,
9075 )
9076 })
9077 })?;
9078 Ok(proto::ApplyCodeActionResponse {
9079 transaction: Some(project_transaction),
9080 })
9081 }
9082
9083 async fn handle_register_buffer_with_language_servers(
9084 this: Entity<Self>,
9085 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9086 mut cx: AsyncApp,
9087 ) -> Result<proto::Ack> {
9088 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9089 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9090 this.update(&mut cx, |this, cx| {
9091 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9092 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9093 project_id: upstream_project_id,
9094 buffer_id: buffer_id.to_proto(),
9095 only_servers: envelope.payload.only_servers,
9096 });
9097 }
9098
9099 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9100 anyhow::bail!("buffer is not open");
9101 };
9102
9103 let handle = this.register_buffer_with_language_servers(
9104 &buffer,
9105 envelope
9106 .payload
9107 .only_servers
9108 .into_iter()
9109 .filter_map(|selector| {
9110 Some(match selector.selector? {
9111 proto::language_server_selector::Selector::ServerId(server_id) => {
9112 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9113 }
9114 proto::language_server_selector::Selector::Name(name) => {
9115 LanguageServerSelector::Name(LanguageServerName(
9116 SharedString::from(name),
9117 ))
9118 }
9119 })
9120 })
9121 .collect(),
9122 false,
9123 cx,
9124 );
9125 this.buffer_store().update(cx, |buffer_store, _| {
9126 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9127 });
9128
9129 Ok(())
9130 })??;
9131 Ok(proto::Ack {})
9132 }
9133
9134 async fn handle_rename_project_entry(
9135 this: Entity<Self>,
9136 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9137 mut cx: AsyncApp,
9138 ) -> Result<proto::ProjectEntryResponse> {
9139 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9140 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9141 let new_path =
9142 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9143
9144 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9145 .update(&mut cx, |this, cx| {
9146 let (worktree, entry) = this
9147 .worktree_store
9148 .read(cx)
9149 .worktree_and_entry_for_id(entry_id, cx)?;
9150 let new_worktree = this
9151 .worktree_store
9152 .read(cx)
9153 .worktree_for_id(new_worktree_id, cx)?;
9154 Some((
9155 this.worktree_store.clone(),
9156 worktree,
9157 new_worktree,
9158 entry.clone(),
9159 ))
9160 })?
9161 .context("worktree not found")?;
9162 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9163 (worktree.absolutize(&old_entry.path), worktree.id())
9164 })?;
9165 let new_abs_path =
9166 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9167
9168 let _transaction = Self::will_rename_entry(
9169 this.downgrade(),
9170 old_worktree_id,
9171 &old_abs_path,
9172 &new_abs_path,
9173 old_entry.is_dir(),
9174 cx.clone(),
9175 )
9176 .await;
9177 let response = WorktreeStore::handle_rename_project_entry(
9178 worktree_store,
9179 envelope.payload,
9180 cx.clone(),
9181 )
9182 .await;
9183 this.read_with(&cx, |this, _| {
9184 this.did_rename_entry(
9185 old_worktree_id,
9186 &old_abs_path,
9187 &new_abs_path,
9188 old_entry.is_dir(),
9189 );
9190 })
9191 .ok();
9192 response
9193 }
9194
9195 async fn handle_update_diagnostic_summary(
9196 this: Entity<Self>,
9197 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9198 mut cx: AsyncApp,
9199 ) -> Result<()> {
9200 this.update(&mut cx, |lsp_store, cx| {
9201 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9202 let mut updated_diagnostics_paths = HashMap::default();
9203 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9204 for message_summary in envelope
9205 .payload
9206 .summary
9207 .into_iter()
9208 .chain(envelope.payload.more_summaries)
9209 {
9210 let project_path = ProjectPath {
9211 worktree_id,
9212 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9213 };
9214 let path = project_path.path.clone();
9215 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9216 let summary = DiagnosticSummary {
9217 error_count: message_summary.error_count as usize,
9218 warning_count: message_summary.warning_count as usize,
9219 };
9220
9221 if summary.is_empty() {
9222 if let Some(worktree_summaries) =
9223 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9224 && let Some(summaries) = worktree_summaries.get_mut(&path)
9225 {
9226 summaries.remove(&server_id);
9227 if summaries.is_empty() {
9228 worktree_summaries.remove(&path);
9229 }
9230 }
9231 } else {
9232 lsp_store
9233 .diagnostic_summaries
9234 .entry(worktree_id)
9235 .or_default()
9236 .entry(path)
9237 .or_default()
9238 .insert(server_id, summary);
9239 }
9240
9241 if let Some((_, project_id)) = &lsp_store.downstream_client {
9242 match &mut diagnostics_summary {
9243 Some(diagnostics_summary) => {
9244 diagnostics_summary
9245 .more_summaries
9246 .push(proto::DiagnosticSummary {
9247 path: project_path.path.as_ref().to_proto(),
9248 language_server_id: server_id.0 as u64,
9249 error_count: summary.error_count as u32,
9250 warning_count: summary.warning_count as u32,
9251 })
9252 }
9253 None => {
9254 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9255 project_id: *project_id,
9256 worktree_id: worktree_id.to_proto(),
9257 summary: Some(proto::DiagnosticSummary {
9258 path: project_path.path.as_ref().to_proto(),
9259 language_server_id: server_id.0 as u64,
9260 error_count: summary.error_count as u32,
9261 warning_count: summary.warning_count as u32,
9262 }),
9263 more_summaries: Vec::new(),
9264 })
9265 }
9266 }
9267 }
9268 updated_diagnostics_paths
9269 .entry(server_id)
9270 .or_insert_with(Vec::new)
9271 .push(project_path);
9272 }
9273
9274 if let Some((diagnostics_summary, (downstream_client, _))) =
9275 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9276 {
9277 downstream_client.send(diagnostics_summary).log_err();
9278 }
9279 for (server_id, paths) in updated_diagnostics_paths {
9280 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9281 }
9282 Ok(())
9283 })?
9284 }
9285
9286 async fn handle_start_language_server(
9287 lsp_store: Entity<Self>,
9288 envelope: TypedEnvelope<proto::StartLanguageServer>,
9289 mut cx: AsyncApp,
9290 ) -> Result<()> {
9291 let server = envelope.payload.server.context("invalid server")?;
9292 let server_capabilities =
9293 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9294 .with_context(|| {
9295 format!(
9296 "incorrect server capabilities {}",
9297 envelope.payload.capabilities
9298 )
9299 })?;
9300 lsp_store.update(&mut cx, |lsp_store, cx| {
9301 let server_id = LanguageServerId(server.id as usize);
9302 let server_name = LanguageServerName::from_proto(server.name.clone());
9303 lsp_store
9304 .lsp_server_capabilities
9305 .insert(server_id, server_capabilities);
9306 lsp_store.language_server_statuses.insert(
9307 server_id,
9308 LanguageServerStatus {
9309 name: server_name.clone(),
9310 pending_work: Default::default(),
9311 has_pending_diagnostic_updates: false,
9312 progress_tokens: Default::default(),
9313 worktree: server.worktree_id.map(WorktreeId::from_proto),
9314 binary: None,
9315 configuration: None,
9316 workspace_folders: BTreeSet::new(),
9317 },
9318 );
9319 cx.emit(LspStoreEvent::LanguageServerAdded(
9320 server_id,
9321 server_name,
9322 server.worktree_id.map(WorktreeId::from_proto),
9323 ));
9324 cx.notify();
9325 })?;
9326 Ok(())
9327 }
9328
9329 async fn handle_update_language_server(
9330 lsp_store: Entity<Self>,
9331 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9332 mut cx: AsyncApp,
9333 ) -> Result<()> {
9334 lsp_store.update(&mut cx, |lsp_store, cx| {
9335 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9336
9337 match envelope.payload.variant.context("invalid variant")? {
9338 proto::update_language_server::Variant::WorkStart(payload) => {
9339 lsp_store.on_lsp_work_start(
9340 language_server_id,
9341 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9342 .context("invalid progress token value")?,
9343 LanguageServerProgress {
9344 title: payload.title,
9345 is_disk_based_diagnostics_progress: false,
9346 is_cancellable: payload.is_cancellable.unwrap_or(false),
9347 message: payload.message,
9348 percentage: payload.percentage.map(|p| p as usize),
9349 last_update_at: cx.background_executor().now(),
9350 },
9351 cx,
9352 );
9353 }
9354 proto::update_language_server::Variant::WorkProgress(payload) => {
9355 lsp_store.on_lsp_work_progress(
9356 language_server_id,
9357 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9358 .context("invalid progress token value")?,
9359 LanguageServerProgress {
9360 title: None,
9361 is_disk_based_diagnostics_progress: false,
9362 is_cancellable: payload.is_cancellable.unwrap_or(false),
9363 message: payload.message,
9364 percentage: payload.percentage.map(|p| p as usize),
9365 last_update_at: cx.background_executor().now(),
9366 },
9367 cx,
9368 );
9369 }
9370
9371 proto::update_language_server::Variant::WorkEnd(payload) => {
9372 lsp_store.on_lsp_work_end(
9373 language_server_id,
9374 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9375 .context("invalid progress token value")?,
9376 cx,
9377 );
9378 }
9379
9380 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9381 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9382 }
9383
9384 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9385 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9386 }
9387
9388 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9389 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9390 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9391 cx.emit(LspStoreEvent::LanguageServerUpdate {
9392 language_server_id,
9393 name: envelope
9394 .payload
9395 .server_name
9396 .map(SharedString::new)
9397 .map(LanguageServerName),
9398 message: non_lsp,
9399 });
9400 }
9401 }
9402
9403 Ok(())
9404 })?
9405 }
9406
9407 async fn handle_language_server_log(
9408 this: Entity<Self>,
9409 envelope: TypedEnvelope<proto::LanguageServerLog>,
9410 mut cx: AsyncApp,
9411 ) -> Result<()> {
9412 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9413 let log_type = envelope
9414 .payload
9415 .log_type
9416 .map(LanguageServerLogType::from_proto)
9417 .context("invalid language server log type")?;
9418
9419 let message = envelope.payload.message;
9420
9421 this.update(&mut cx, |_, cx| {
9422 cx.emit(LspStoreEvent::LanguageServerLog(
9423 language_server_id,
9424 log_type,
9425 message,
9426 ));
9427 })
9428 }
9429
9430 async fn handle_lsp_ext_cancel_flycheck(
9431 lsp_store: Entity<Self>,
9432 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9433 cx: AsyncApp,
9434 ) -> Result<proto::Ack> {
9435 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9436 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9437 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9438 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9439 } else {
9440 None
9441 }
9442 })?;
9443 if let Some(task) = task {
9444 task.context("handling lsp ext cancel flycheck")?;
9445 }
9446
9447 Ok(proto::Ack {})
9448 }
9449
9450 async fn handle_lsp_ext_run_flycheck(
9451 lsp_store: Entity<Self>,
9452 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9453 mut cx: AsyncApp,
9454 ) -> Result<proto::Ack> {
9455 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9456 lsp_store.update(&mut cx, |lsp_store, cx| {
9457 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9458 let text_document = if envelope.payload.current_file_only {
9459 let buffer_id = envelope
9460 .payload
9461 .buffer_id
9462 .map(|id| BufferId::new(id))
9463 .transpose()?;
9464 buffer_id
9465 .and_then(|buffer_id| {
9466 lsp_store
9467 .buffer_store()
9468 .read(cx)
9469 .get(buffer_id)
9470 .and_then(|buffer| {
9471 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9472 })
9473 .map(|path| make_text_document_identifier(&path))
9474 })
9475 .transpose()?
9476 } else {
9477 None
9478 };
9479 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9480 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9481 )?;
9482 }
9483 anyhow::Ok(())
9484 })??;
9485
9486 Ok(proto::Ack {})
9487 }
9488
9489 async fn handle_lsp_ext_clear_flycheck(
9490 lsp_store: Entity<Self>,
9491 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9492 cx: AsyncApp,
9493 ) -> Result<proto::Ack> {
9494 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9495 lsp_store
9496 .read_with(&cx, |lsp_store, _| {
9497 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9498 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9499 } else {
9500 None
9501 }
9502 })
9503 .context("handling lsp ext clear flycheck")?;
9504
9505 Ok(proto::Ack {})
9506 }
9507
9508 pub fn disk_based_diagnostics_started(
9509 &mut self,
9510 language_server_id: LanguageServerId,
9511 cx: &mut Context<Self>,
9512 ) {
9513 if let Some(language_server_status) =
9514 self.language_server_statuses.get_mut(&language_server_id)
9515 {
9516 language_server_status.has_pending_diagnostic_updates = true;
9517 }
9518
9519 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9520 cx.emit(LspStoreEvent::LanguageServerUpdate {
9521 language_server_id,
9522 name: self
9523 .language_server_adapter_for_id(language_server_id)
9524 .map(|adapter| adapter.name()),
9525 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9526 Default::default(),
9527 ),
9528 })
9529 }
9530
9531 pub fn disk_based_diagnostics_finished(
9532 &mut self,
9533 language_server_id: LanguageServerId,
9534 cx: &mut Context<Self>,
9535 ) {
9536 if let Some(language_server_status) =
9537 self.language_server_statuses.get_mut(&language_server_id)
9538 {
9539 language_server_status.has_pending_diagnostic_updates = false;
9540 }
9541
9542 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9543 cx.emit(LspStoreEvent::LanguageServerUpdate {
9544 language_server_id,
9545 name: self
9546 .language_server_adapter_for_id(language_server_id)
9547 .map(|adapter| adapter.name()),
9548 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9549 Default::default(),
9550 ),
9551 })
9552 }
9553
9554 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9555 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9556 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9557 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9558 // the language server might take some time to publish diagnostics.
9559 fn simulate_disk_based_diagnostics_events_if_needed(
9560 &mut self,
9561 language_server_id: LanguageServerId,
9562 cx: &mut Context<Self>,
9563 ) {
9564 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9565
9566 let Some(LanguageServerState::Running {
9567 simulate_disk_based_diagnostics_completion,
9568 adapter,
9569 ..
9570 }) = self
9571 .as_local_mut()
9572 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9573 else {
9574 return;
9575 };
9576
9577 if adapter.disk_based_diagnostics_progress_token.is_some() {
9578 return;
9579 }
9580
9581 let prev_task =
9582 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9583 cx.background_executor()
9584 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9585 .await;
9586
9587 this.update(cx, |this, cx| {
9588 this.disk_based_diagnostics_finished(language_server_id, cx);
9589
9590 if let Some(LanguageServerState::Running {
9591 simulate_disk_based_diagnostics_completion,
9592 ..
9593 }) = this.as_local_mut().and_then(|local_store| {
9594 local_store.language_servers.get_mut(&language_server_id)
9595 }) {
9596 *simulate_disk_based_diagnostics_completion = None;
9597 }
9598 })
9599 .ok();
9600 }));
9601
9602 if prev_task.is_none() {
9603 self.disk_based_diagnostics_started(language_server_id, cx);
9604 }
9605 }
9606
9607 pub fn language_server_statuses(
9608 &self,
9609 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9610 self.language_server_statuses
9611 .iter()
9612 .map(|(key, value)| (*key, value))
9613 }
9614
9615 pub(super) fn did_rename_entry(
9616 &self,
9617 worktree_id: WorktreeId,
9618 old_path: &Path,
9619 new_path: &Path,
9620 is_dir: bool,
9621 ) {
9622 maybe!({
9623 let local_store = self.as_local()?;
9624
9625 let old_uri = lsp::Uri::from_file_path(old_path)
9626 .ok()
9627 .map(|uri| uri.to_string())?;
9628 let new_uri = lsp::Uri::from_file_path(new_path)
9629 .ok()
9630 .map(|uri| uri.to_string())?;
9631
9632 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9633 let Some(filter) = local_store
9634 .language_server_paths_watched_for_rename
9635 .get(&language_server.server_id())
9636 else {
9637 continue;
9638 };
9639
9640 if filter.should_send_did_rename(&old_uri, is_dir) {
9641 language_server
9642 .notify::<DidRenameFiles>(RenameFilesParams {
9643 files: vec![FileRename {
9644 old_uri: old_uri.clone(),
9645 new_uri: new_uri.clone(),
9646 }],
9647 })
9648 .ok();
9649 }
9650 }
9651 Some(())
9652 });
9653 }
9654
9655 pub(super) fn will_rename_entry(
9656 this: WeakEntity<Self>,
9657 worktree_id: WorktreeId,
9658 old_path: &Path,
9659 new_path: &Path,
9660 is_dir: bool,
9661 cx: AsyncApp,
9662 ) -> Task<ProjectTransaction> {
9663 let old_uri = lsp::Uri::from_file_path(old_path)
9664 .ok()
9665 .map(|uri| uri.to_string());
9666 let new_uri = lsp::Uri::from_file_path(new_path)
9667 .ok()
9668 .map(|uri| uri.to_string());
9669 cx.spawn(async move |cx| {
9670 let mut tasks = vec![];
9671 this.update(cx, |this, cx| {
9672 let local_store = this.as_local()?;
9673 let old_uri = old_uri?;
9674 let new_uri = new_uri?;
9675 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9676 let Some(filter) = local_store
9677 .language_server_paths_watched_for_rename
9678 .get(&language_server.server_id())
9679 else {
9680 continue;
9681 };
9682
9683 if filter.should_send_will_rename(&old_uri, is_dir) {
9684 let apply_edit = cx.spawn({
9685 let old_uri = old_uri.clone();
9686 let new_uri = new_uri.clone();
9687 let language_server = language_server.clone();
9688 async move |this, cx| {
9689 let edit = language_server
9690 .request::<WillRenameFiles>(RenameFilesParams {
9691 files: vec![FileRename { old_uri, new_uri }],
9692 })
9693 .await
9694 .into_response()
9695 .context("will rename files")
9696 .log_err()
9697 .flatten()?;
9698
9699 let transaction = LocalLspStore::deserialize_workspace_edit(
9700 this.upgrade()?,
9701 edit,
9702 false,
9703 language_server.clone(),
9704 cx,
9705 )
9706 .await
9707 .ok()?;
9708 Some(transaction)
9709 }
9710 });
9711 tasks.push(apply_edit);
9712 }
9713 }
9714 Some(())
9715 })
9716 .ok()
9717 .flatten();
9718 let mut merged_transaction = ProjectTransaction::default();
9719 for task in tasks {
9720 // Await on tasks sequentially so that the order of application of edits is deterministic
9721 // (at least with regards to the order of registration of language servers)
9722 if let Some(transaction) = task.await {
9723 for (buffer, buffer_transaction) in transaction.0 {
9724 merged_transaction.0.insert(buffer, buffer_transaction);
9725 }
9726 }
9727 }
9728 merged_transaction
9729 })
9730 }
9731
9732 fn lsp_notify_abs_paths_changed(
9733 &mut self,
9734 server_id: LanguageServerId,
9735 changes: Vec<PathEvent>,
9736 ) {
9737 maybe!({
9738 let server = self.language_server_for_id(server_id)?;
9739 let changes = changes
9740 .into_iter()
9741 .filter_map(|event| {
9742 let typ = match event.kind? {
9743 PathEventKind::Created => lsp::FileChangeType::CREATED,
9744 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9745 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9746 };
9747 Some(lsp::FileEvent {
9748 uri: file_path_to_lsp_url(&event.path).log_err()?,
9749 typ,
9750 })
9751 })
9752 .collect::<Vec<_>>();
9753 if !changes.is_empty() {
9754 server
9755 .notify::<lsp::notification::DidChangeWatchedFiles>(
9756 lsp::DidChangeWatchedFilesParams { changes },
9757 )
9758 .ok();
9759 }
9760 Some(())
9761 });
9762 }
9763
9764 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9765 self.as_local()?.language_server_for_id(id)
9766 }
9767
9768 fn on_lsp_progress(
9769 &mut self,
9770 progress_params: lsp::ProgressParams,
9771 language_server_id: LanguageServerId,
9772 disk_based_diagnostics_progress_token: Option<String>,
9773 cx: &mut Context<Self>,
9774 ) {
9775 match progress_params.value {
9776 lsp::ProgressParamsValue::WorkDone(progress) => {
9777 self.handle_work_done_progress(
9778 progress,
9779 language_server_id,
9780 disk_based_diagnostics_progress_token,
9781 ProgressToken::from_lsp(progress_params.token),
9782 cx,
9783 );
9784 }
9785 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9786 let registration_id = match progress_params.token {
9787 lsp::NumberOrString::Number(_) => None,
9788 lsp::NumberOrString::String(token) => token
9789 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9790 .map(|(_, id)| id.to_owned()),
9791 };
9792 if let Some(LanguageServerState::Running {
9793 workspace_diagnostics_refresh_tasks,
9794 ..
9795 }) = self
9796 .as_local_mut()
9797 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9798 && let Some(workspace_diagnostics) =
9799 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9800 {
9801 workspace_diagnostics.progress_tx.try_send(()).ok();
9802 self.apply_workspace_diagnostic_report(
9803 language_server_id,
9804 report,
9805 registration_id.map(SharedString::from),
9806 cx,
9807 )
9808 }
9809 }
9810 }
9811 }
9812
9813 fn handle_work_done_progress(
9814 &mut self,
9815 progress: lsp::WorkDoneProgress,
9816 language_server_id: LanguageServerId,
9817 disk_based_diagnostics_progress_token: Option<String>,
9818 token: ProgressToken,
9819 cx: &mut Context<Self>,
9820 ) {
9821 let language_server_status =
9822 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9823 status
9824 } else {
9825 return;
9826 };
9827
9828 if !language_server_status.progress_tokens.contains(&token) {
9829 return;
9830 }
9831
9832 let is_disk_based_diagnostics_progress =
9833 if let (Some(disk_based_token), ProgressToken::String(token)) =
9834 (&disk_based_diagnostics_progress_token, &token)
9835 {
9836 token.starts_with(disk_based_token)
9837 } else {
9838 false
9839 };
9840
9841 match progress {
9842 lsp::WorkDoneProgress::Begin(report) => {
9843 if is_disk_based_diagnostics_progress {
9844 self.disk_based_diagnostics_started(language_server_id, cx);
9845 }
9846 self.on_lsp_work_start(
9847 language_server_id,
9848 token.clone(),
9849 LanguageServerProgress {
9850 title: Some(report.title),
9851 is_disk_based_diagnostics_progress,
9852 is_cancellable: report.cancellable.unwrap_or(false),
9853 message: report.message.clone(),
9854 percentage: report.percentage.map(|p| p as usize),
9855 last_update_at: cx.background_executor().now(),
9856 },
9857 cx,
9858 );
9859 }
9860 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9861 language_server_id,
9862 token,
9863 LanguageServerProgress {
9864 title: None,
9865 is_disk_based_diagnostics_progress,
9866 is_cancellable: report.cancellable.unwrap_or(false),
9867 message: report.message,
9868 percentage: report.percentage.map(|p| p as usize),
9869 last_update_at: cx.background_executor().now(),
9870 },
9871 cx,
9872 ),
9873 lsp::WorkDoneProgress::End(_) => {
9874 language_server_status.progress_tokens.remove(&token);
9875 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9876 if is_disk_based_diagnostics_progress {
9877 self.disk_based_diagnostics_finished(language_server_id, cx);
9878 }
9879 }
9880 }
9881 }
9882
9883 fn on_lsp_work_start(
9884 &mut self,
9885 language_server_id: LanguageServerId,
9886 token: ProgressToken,
9887 progress: LanguageServerProgress,
9888 cx: &mut Context<Self>,
9889 ) {
9890 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9891 status.pending_work.insert(token.clone(), progress.clone());
9892 cx.notify();
9893 }
9894 cx.emit(LspStoreEvent::LanguageServerUpdate {
9895 language_server_id,
9896 name: self
9897 .language_server_adapter_for_id(language_server_id)
9898 .map(|adapter| adapter.name()),
9899 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9900 token: Some(token.to_proto()),
9901 title: progress.title,
9902 message: progress.message,
9903 percentage: progress.percentage.map(|p| p as u32),
9904 is_cancellable: Some(progress.is_cancellable),
9905 }),
9906 })
9907 }
9908
9909 fn on_lsp_work_progress(
9910 &mut self,
9911 language_server_id: LanguageServerId,
9912 token: ProgressToken,
9913 progress: LanguageServerProgress,
9914 cx: &mut Context<Self>,
9915 ) {
9916 let mut did_update = false;
9917 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9918 match status.pending_work.entry(token.clone()) {
9919 btree_map::Entry::Vacant(entry) => {
9920 entry.insert(progress.clone());
9921 did_update = true;
9922 }
9923 btree_map::Entry::Occupied(mut entry) => {
9924 let entry = entry.get_mut();
9925 if (progress.last_update_at - entry.last_update_at)
9926 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9927 {
9928 entry.last_update_at = progress.last_update_at;
9929 if progress.message.is_some() {
9930 entry.message = progress.message.clone();
9931 }
9932 if progress.percentage.is_some() {
9933 entry.percentage = progress.percentage;
9934 }
9935 if progress.is_cancellable != entry.is_cancellable {
9936 entry.is_cancellable = progress.is_cancellable;
9937 }
9938 did_update = true;
9939 }
9940 }
9941 }
9942 }
9943
9944 if did_update {
9945 cx.emit(LspStoreEvent::LanguageServerUpdate {
9946 language_server_id,
9947 name: self
9948 .language_server_adapter_for_id(language_server_id)
9949 .map(|adapter| adapter.name()),
9950 message: proto::update_language_server::Variant::WorkProgress(
9951 proto::LspWorkProgress {
9952 token: Some(token.to_proto()),
9953 message: progress.message,
9954 percentage: progress.percentage.map(|p| p as u32),
9955 is_cancellable: Some(progress.is_cancellable),
9956 },
9957 ),
9958 })
9959 }
9960 }
9961
9962 fn on_lsp_work_end(
9963 &mut self,
9964 language_server_id: LanguageServerId,
9965 token: ProgressToken,
9966 cx: &mut Context<Self>,
9967 ) {
9968 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9969 if let Some(work) = status.pending_work.remove(&token)
9970 && !work.is_disk_based_diagnostics_progress
9971 {
9972 cx.emit(LspStoreEvent::RefreshInlayHints {
9973 server_id: language_server_id,
9974 request_id: None,
9975 });
9976 }
9977 cx.notify();
9978 }
9979
9980 cx.emit(LspStoreEvent::LanguageServerUpdate {
9981 language_server_id,
9982 name: self
9983 .language_server_adapter_for_id(language_server_id)
9984 .map(|adapter| adapter.name()),
9985 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9986 token: Some(token.to_proto()),
9987 }),
9988 })
9989 }
9990
9991 pub async fn handle_resolve_completion_documentation(
9992 this: Entity<Self>,
9993 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9994 mut cx: AsyncApp,
9995 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9996 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9997
9998 let completion = this
9999 .read_with(&cx, |this, cx| {
10000 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10001 let server = this
10002 .language_server_for_id(id)
10003 .with_context(|| format!("No language server {id}"))?;
10004
10005 anyhow::Ok(cx.background_spawn(async move {
10006 let can_resolve = server
10007 .capabilities()
10008 .completion_provider
10009 .as_ref()
10010 .and_then(|options| options.resolve_provider)
10011 .unwrap_or(false);
10012 if can_resolve {
10013 server
10014 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10015 .await
10016 .into_response()
10017 .context("resolve completion item")
10018 } else {
10019 anyhow::Ok(lsp_completion)
10020 }
10021 }))
10022 })??
10023 .await?;
10024
10025 let mut documentation_is_markdown = false;
10026 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10027 let documentation = match completion.documentation {
10028 Some(lsp::Documentation::String(text)) => text,
10029
10030 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10031 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10032 value
10033 }
10034
10035 _ => String::new(),
10036 };
10037
10038 // If we have a new buffer_id, that means we're talking to a new client
10039 // and want to check for new text_edits in the completion too.
10040 let mut old_replace_start = None;
10041 let mut old_replace_end = None;
10042 let mut old_insert_start = None;
10043 let mut old_insert_end = None;
10044 let mut new_text = String::default();
10045 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10046 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10047 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10048 anyhow::Ok(buffer.read(cx).snapshot())
10049 })??;
10050
10051 if let Some(text_edit) = completion.text_edit.as_ref() {
10052 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10053
10054 if let Some(mut edit) = edit {
10055 LineEnding::normalize(&mut edit.new_text);
10056
10057 new_text = edit.new_text;
10058 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10059 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10060 if let Some(insert_range) = edit.insert_range {
10061 old_insert_start = Some(serialize_anchor(&insert_range.start));
10062 old_insert_end = Some(serialize_anchor(&insert_range.end));
10063 }
10064 }
10065 }
10066 }
10067
10068 Ok(proto::ResolveCompletionDocumentationResponse {
10069 documentation,
10070 documentation_is_markdown,
10071 old_replace_start,
10072 old_replace_end,
10073 new_text,
10074 lsp_completion,
10075 old_insert_start,
10076 old_insert_end,
10077 })
10078 }
10079
10080 async fn handle_on_type_formatting(
10081 this: Entity<Self>,
10082 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10083 mut cx: AsyncApp,
10084 ) -> Result<proto::OnTypeFormattingResponse> {
10085 let on_type_formatting = this.update(&mut cx, |this, cx| {
10086 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10087 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10088 let position = envelope
10089 .payload
10090 .position
10091 .and_then(deserialize_anchor)
10092 .context("invalid position")?;
10093 anyhow::Ok(this.apply_on_type_formatting(
10094 buffer,
10095 position,
10096 envelope.payload.trigger.clone(),
10097 cx,
10098 ))
10099 })??;
10100
10101 let transaction = on_type_formatting
10102 .await?
10103 .as_ref()
10104 .map(language::proto::serialize_transaction);
10105 Ok(proto::OnTypeFormattingResponse { transaction })
10106 }
10107
10108 async fn handle_refresh_inlay_hints(
10109 lsp_store: Entity<Self>,
10110 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10111 mut cx: AsyncApp,
10112 ) -> Result<proto::Ack> {
10113 lsp_store.update(&mut cx, |_, cx| {
10114 cx.emit(LspStoreEvent::RefreshInlayHints {
10115 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10116 request_id: envelope.payload.request_id.map(|id| id as usize),
10117 });
10118 })?;
10119 Ok(proto::Ack {})
10120 }
10121
10122 async fn handle_pull_workspace_diagnostics(
10123 lsp_store: Entity<Self>,
10124 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10125 mut cx: AsyncApp,
10126 ) -> Result<proto::Ack> {
10127 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10128 lsp_store.update(&mut cx, |lsp_store, _| {
10129 lsp_store.pull_workspace_diagnostics(server_id);
10130 })?;
10131 Ok(proto::Ack {})
10132 }
10133
10134 async fn handle_get_color_presentation(
10135 lsp_store: Entity<Self>,
10136 envelope: TypedEnvelope<proto::GetColorPresentation>,
10137 mut cx: AsyncApp,
10138 ) -> Result<proto::GetColorPresentationResponse> {
10139 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10140 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10141 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10142 })??;
10143
10144 let color = envelope
10145 .payload
10146 .color
10147 .context("invalid color resolve request")?;
10148 let start = color
10149 .lsp_range_start
10150 .context("invalid color resolve request")?;
10151 let end = color
10152 .lsp_range_end
10153 .context("invalid color resolve request")?;
10154
10155 let color = DocumentColor {
10156 lsp_range: lsp::Range {
10157 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10158 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10159 },
10160 color: lsp::Color {
10161 red: color.red,
10162 green: color.green,
10163 blue: color.blue,
10164 alpha: color.alpha,
10165 },
10166 resolved: false,
10167 color_presentations: Vec::new(),
10168 };
10169 let resolved_color = lsp_store
10170 .update(&mut cx, |lsp_store, cx| {
10171 lsp_store.resolve_color_presentation(
10172 color,
10173 buffer.clone(),
10174 LanguageServerId(envelope.payload.server_id as usize),
10175 cx,
10176 )
10177 })?
10178 .await
10179 .context("resolving color presentation")?;
10180
10181 Ok(proto::GetColorPresentationResponse {
10182 presentations: resolved_color
10183 .color_presentations
10184 .into_iter()
10185 .map(|presentation| proto::ColorPresentation {
10186 label: presentation.label.to_string(),
10187 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10188 additional_text_edits: presentation
10189 .additional_text_edits
10190 .into_iter()
10191 .map(serialize_lsp_edit)
10192 .collect(),
10193 })
10194 .collect(),
10195 })
10196 }
10197
10198 async fn handle_resolve_inlay_hint(
10199 lsp_store: Entity<Self>,
10200 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10201 mut cx: AsyncApp,
10202 ) -> Result<proto::ResolveInlayHintResponse> {
10203 let proto_hint = envelope
10204 .payload
10205 .hint
10206 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10207 let hint = InlayHints::proto_to_project_hint(proto_hint)
10208 .context("resolved proto inlay hint conversion")?;
10209 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10210 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10211 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10212 })??;
10213 let response_hint = lsp_store
10214 .update(&mut cx, |lsp_store, cx| {
10215 lsp_store.resolve_inlay_hint(
10216 hint,
10217 buffer,
10218 LanguageServerId(envelope.payload.language_server_id as usize),
10219 cx,
10220 )
10221 })?
10222 .await
10223 .context("inlay hints fetch")?;
10224 Ok(proto::ResolveInlayHintResponse {
10225 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10226 })
10227 }
10228
10229 async fn handle_refresh_code_lens(
10230 this: Entity<Self>,
10231 _: TypedEnvelope<proto::RefreshCodeLens>,
10232 mut cx: AsyncApp,
10233 ) -> Result<proto::Ack> {
10234 this.update(&mut cx, |_, cx| {
10235 cx.emit(LspStoreEvent::RefreshCodeLens);
10236 })?;
10237 Ok(proto::Ack {})
10238 }
10239
10240 async fn handle_open_buffer_for_symbol(
10241 this: Entity<Self>,
10242 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10243 mut cx: AsyncApp,
10244 ) -> Result<proto::OpenBufferForSymbolResponse> {
10245 let peer_id = envelope.original_sender_id().unwrap_or_default();
10246 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10247 let symbol = Self::deserialize_symbol(symbol)?;
10248 this.read_with(&cx, |this, _| {
10249 if let SymbolLocation::OutsideProject {
10250 abs_path,
10251 signature,
10252 } = &symbol.path
10253 {
10254 let new_signature = this.symbol_signature(&abs_path);
10255 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10256 }
10257 Ok(())
10258 })??;
10259 let buffer = this
10260 .update(&mut cx, |this, cx| {
10261 this.open_buffer_for_symbol(
10262 &Symbol {
10263 language_server_name: symbol.language_server_name,
10264 source_worktree_id: symbol.source_worktree_id,
10265 source_language_server_id: symbol.source_language_server_id,
10266 path: symbol.path,
10267 name: symbol.name,
10268 kind: symbol.kind,
10269 range: symbol.range,
10270 label: CodeLabel::default(),
10271 },
10272 cx,
10273 )
10274 })?
10275 .await?;
10276
10277 this.update(&mut cx, |this, cx| {
10278 let is_private = buffer
10279 .read(cx)
10280 .file()
10281 .map(|f| f.is_private())
10282 .unwrap_or_default();
10283 if is_private {
10284 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10285 } else {
10286 this.buffer_store
10287 .update(cx, |buffer_store, cx| {
10288 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10289 })
10290 .detach_and_log_err(cx);
10291 let buffer_id = buffer.read(cx).remote_id().to_proto();
10292 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10293 }
10294 })?
10295 }
10296
10297 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10298 let mut hasher = Sha256::new();
10299 hasher.update(abs_path.to_string_lossy().as_bytes());
10300 hasher.update(self.nonce.to_be_bytes());
10301 hasher.finalize().as_slice().try_into().unwrap()
10302 }
10303
10304 pub async fn handle_get_project_symbols(
10305 this: Entity<Self>,
10306 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10307 mut cx: AsyncApp,
10308 ) -> Result<proto::GetProjectSymbolsResponse> {
10309 let symbols = this
10310 .update(&mut cx, |this, cx| {
10311 this.symbols(&envelope.payload.query, cx)
10312 })?
10313 .await?;
10314
10315 Ok(proto::GetProjectSymbolsResponse {
10316 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10317 })
10318 }
10319
10320 pub async fn handle_restart_language_servers(
10321 this: Entity<Self>,
10322 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10323 mut cx: AsyncApp,
10324 ) -> Result<proto::Ack> {
10325 this.update(&mut cx, |lsp_store, cx| {
10326 let buffers =
10327 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10328 lsp_store.restart_language_servers_for_buffers(
10329 buffers,
10330 envelope
10331 .payload
10332 .only_servers
10333 .into_iter()
10334 .filter_map(|selector| {
10335 Some(match selector.selector? {
10336 proto::language_server_selector::Selector::ServerId(server_id) => {
10337 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10338 }
10339 proto::language_server_selector::Selector::Name(name) => {
10340 LanguageServerSelector::Name(LanguageServerName(
10341 SharedString::from(name),
10342 ))
10343 }
10344 })
10345 })
10346 .collect(),
10347 cx,
10348 );
10349 })?;
10350
10351 Ok(proto::Ack {})
10352 }
10353
10354 pub async fn handle_stop_language_servers(
10355 lsp_store: Entity<Self>,
10356 envelope: TypedEnvelope<proto::StopLanguageServers>,
10357 mut cx: AsyncApp,
10358 ) -> Result<proto::Ack> {
10359 lsp_store.update(&mut cx, |lsp_store, cx| {
10360 if envelope.payload.all
10361 && envelope.payload.also_servers.is_empty()
10362 && envelope.payload.buffer_ids.is_empty()
10363 {
10364 lsp_store.stop_all_language_servers(cx);
10365 } else {
10366 let buffers =
10367 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10368 lsp_store
10369 .stop_language_servers_for_buffers(
10370 buffers,
10371 envelope
10372 .payload
10373 .also_servers
10374 .into_iter()
10375 .filter_map(|selector| {
10376 Some(match selector.selector? {
10377 proto::language_server_selector::Selector::ServerId(
10378 server_id,
10379 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10380 server_id,
10381 )),
10382 proto::language_server_selector::Selector::Name(name) => {
10383 LanguageServerSelector::Name(LanguageServerName(
10384 SharedString::from(name),
10385 ))
10386 }
10387 })
10388 })
10389 .collect(),
10390 cx,
10391 )
10392 .detach_and_log_err(cx);
10393 }
10394 })?;
10395
10396 Ok(proto::Ack {})
10397 }
10398
10399 pub async fn handle_cancel_language_server_work(
10400 lsp_store: Entity<Self>,
10401 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10402 mut cx: AsyncApp,
10403 ) -> Result<proto::Ack> {
10404 lsp_store.update(&mut cx, |lsp_store, cx| {
10405 if let Some(work) = envelope.payload.work {
10406 match work {
10407 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10408 let buffers =
10409 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10410 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10411 }
10412 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10413 let server_id = LanguageServerId::from_proto(work.language_server_id);
10414 let token = work
10415 .token
10416 .map(|token| {
10417 ProgressToken::from_proto(token)
10418 .context("invalid work progress token")
10419 })
10420 .transpose()?;
10421 lsp_store.cancel_language_server_work(server_id, token, cx);
10422 }
10423 }
10424 }
10425 anyhow::Ok(())
10426 })??;
10427
10428 Ok(proto::Ack {})
10429 }
10430
10431 fn buffer_ids_to_buffers(
10432 &mut self,
10433 buffer_ids: impl Iterator<Item = u64>,
10434 cx: &mut Context<Self>,
10435 ) -> Vec<Entity<Buffer>> {
10436 buffer_ids
10437 .into_iter()
10438 .flat_map(|buffer_id| {
10439 self.buffer_store
10440 .read(cx)
10441 .get(BufferId::new(buffer_id).log_err()?)
10442 })
10443 .collect::<Vec<_>>()
10444 }
10445
10446 async fn handle_apply_additional_edits_for_completion(
10447 this: Entity<Self>,
10448 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10449 mut cx: AsyncApp,
10450 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10451 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10452 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10453 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10454 let completion = Self::deserialize_completion(
10455 envelope.payload.completion.context("invalid completion")?,
10456 )?;
10457 anyhow::Ok((buffer, completion))
10458 })??;
10459
10460 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10461 this.apply_additional_edits_for_completion(
10462 buffer,
10463 Rc::new(RefCell::new(Box::new([Completion {
10464 replace_range: completion.replace_range,
10465 new_text: completion.new_text,
10466 source: completion.source,
10467 documentation: None,
10468 label: CodeLabel::default(),
10469 match_start: None,
10470 snippet_deduplication_key: None,
10471 insert_text_mode: None,
10472 icon_path: None,
10473 confirm: None,
10474 }]))),
10475 0,
10476 false,
10477 cx,
10478 )
10479 })?;
10480
10481 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10482 transaction: apply_additional_edits
10483 .await?
10484 .as_ref()
10485 .map(language::proto::serialize_transaction),
10486 })
10487 }
10488
10489 pub fn last_formatting_failure(&self) -> Option<&str> {
10490 self.last_formatting_failure.as_deref()
10491 }
10492
10493 pub fn reset_last_formatting_failure(&mut self) {
10494 self.last_formatting_failure = None;
10495 }
10496
10497 pub fn environment_for_buffer(
10498 &self,
10499 buffer: &Entity<Buffer>,
10500 cx: &mut Context<Self>,
10501 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10502 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10503 environment.update(cx, |env, cx| {
10504 env.buffer_environment(buffer, &self.worktree_store, cx)
10505 })
10506 } else {
10507 Task::ready(None).shared()
10508 }
10509 }
10510
10511 pub fn format(
10512 &mut self,
10513 buffers: HashSet<Entity<Buffer>>,
10514 target: LspFormatTarget,
10515 push_to_history: bool,
10516 trigger: FormatTrigger,
10517 cx: &mut Context<Self>,
10518 ) -> Task<anyhow::Result<ProjectTransaction>> {
10519 let logger = zlog::scoped!("format");
10520 if self.as_local().is_some() {
10521 zlog::trace!(logger => "Formatting locally");
10522 let logger = zlog::scoped!(logger => "local");
10523 let buffers = buffers
10524 .into_iter()
10525 .map(|buffer_handle| {
10526 let buffer = buffer_handle.read(cx);
10527 let buffer_abs_path = File::from_dyn(buffer.file())
10528 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10529
10530 (buffer_handle, buffer_abs_path, buffer.remote_id())
10531 })
10532 .collect::<Vec<_>>();
10533
10534 cx.spawn(async move |lsp_store, cx| {
10535 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10536
10537 for (handle, abs_path, id) in buffers {
10538 let env = lsp_store
10539 .update(cx, |lsp_store, cx| {
10540 lsp_store.environment_for_buffer(&handle, cx)
10541 })?
10542 .await;
10543
10544 let ranges = match &target {
10545 LspFormatTarget::Buffers => None,
10546 LspFormatTarget::Ranges(ranges) => {
10547 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10548 }
10549 };
10550
10551 formattable_buffers.push(FormattableBuffer {
10552 handle,
10553 abs_path,
10554 env,
10555 ranges,
10556 });
10557 }
10558 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10559
10560 let format_timer = zlog::time!(logger => "Formatting buffers");
10561 let result = LocalLspStore::format_locally(
10562 lsp_store.clone(),
10563 formattable_buffers,
10564 push_to_history,
10565 trigger,
10566 logger,
10567 cx,
10568 )
10569 .await;
10570 format_timer.end();
10571
10572 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10573
10574 lsp_store.update(cx, |lsp_store, _| {
10575 lsp_store.update_last_formatting_failure(&result);
10576 })?;
10577
10578 result
10579 })
10580 } else if let Some((client, project_id)) = self.upstream_client() {
10581 zlog::trace!(logger => "Formatting remotely");
10582 let logger = zlog::scoped!(logger => "remote");
10583 // Don't support formatting ranges via remote
10584 match target {
10585 LspFormatTarget::Buffers => {}
10586 LspFormatTarget::Ranges(_) => {
10587 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10588 return Task::ready(Ok(ProjectTransaction::default()));
10589 }
10590 }
10591
10592 let buffer_store = self.buffer_store();
10593 cx.spawn(async move |lsp_store, cx| {
10594 zlog::trace!(logger => "Sending remote format request");
10595 let request_timer = zlog::time!(logger => "remote format request");
10596 let result = client
10597 .request(proto::FormatBuffers {
10598 project_id,
10599 trigger: trigger as i32,
10600 buffer_ids: buffers
10601 .iter()
10602 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10603 .collect::<Result<_>>()?,
10604 })
10605 .await
10606 .and_then(|result| result.transaction.context("missing transaction"));
10607 request_timer.end();
10608
10609 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10610
10611 lsp_store.update(cx, |lsp_store, _| {
10612 lsp_store.update_last_formatting_failure(&result);
10613 })?;
10614
10615 let transaction_response = result?;
10616 let _timer = zlog::time!(logger => "deserializing project transaction");
10617 buffer_store
10618 .update(cx, |buffer_store, cx| {
10619 buffer_store.deserialize_project_transaction(
10620 transaction_response,
10621 push_to_history,
10622 cx,
10623 )
10624 })?
10625 .await
10626 })
10627 } else {
10628 zlog::trace!(logger => "Not formatting");
10629 Task::ready(Ok(ProjectTransaction::default()))
10630 }
10631 }
10632
10633 async fn handle_format_buffers(
10634 this: Entity<Self>,
10635 envelope: TypedEnvelope<proto::FormatBuffers>,
10636 mut cx: AsyncApp,
10637 ) -> Result<proto::FormatBuffersResponse> {
10638 let sender_id = envelope.original_sender_id().unwrap_or_default();
10639 let format = this.update(&mut cx, |this, cx| {
10640 let mut buffers = HashSet::default();
10641 for buffer_id in &envelope.payload.buffer_ids {
10642 let buffer_id = BufferId::new(*buffer_id)?;
10643 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10644 }
10645 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10646 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10647 })??;
10648
10649 let project_transaction = format.await?;
10650 let project_transaction = this.update(&mut cx, |this, cx| {
10651 this.buffer_store.update(cx, |buffer_store, cx| {
10652 buffer_store.serialize_project_transaction_for_peer(
10653 project_transaction,
10654 sender_id,
10655 cx,
10656 )
10657 })
10658 })?;
10659 Ok(proto::FormatBuffersResponse {
10660 transaction: Some(project_transaction),
10661 })
10662 }
10663
10664 async fn handle_apply_code_action_kind(
10665 this: Entity<Self>,
10666 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10667 mut cx: AsyncApp,
10668 ) -> Result<proto::ApplyCodeActionKindResponse> {
10669 let sender_id = envelope.original_sender_id().unwrap_or_default();
10670 let format = this.update(&mut cx, |this, cx| {
10671 let mut buffers = HashSet::default();
10672 for buffer_id in &envelope.payload.buffer_ids {
10673 let buffer_id = BufferId::new(*buffer_id)?;
10674 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10675 }
10676 let kind = match envelope.payload.kind.as_str() {
10677 "" => CodeActionKind::EMPTY,
10678 "quickfix" => CodeActionKind::QUICKFIX,
10679 "refactor" => CodeActionKind::REFACTOR,
10680 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10681 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10682 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10683 "source" => CodeActionKind::SOURCE,
10684 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10685 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10686 _ => anyhow::bail!(
10687 "Invalid code action kind {}",
10688 envelope.payload.kind.as_str()
10689 ),
10690 };
10691 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10692 })??;
10693
10694 let project_transaction = format.await?;
10695 let project_transaction = this.update(&mut cx, |this, cx| {
10696 this.buffer_store.update(cx, |buffer_store, cx| {
10697 buffer_store.serialize_project_transaction_for_peer(
10698 project_transaction,
10699 sender_id,
10700 cx,
10701 )
10702 })
10703 })?;
10704 Ok(proto::ApplyCodeActionKindResponse {
10705 transaction: Some(project_transaction),
10706 })
10707 }
10708
10709 async fn shutdown_language_server(
10710 server_state: Option<LanguageServerState>,
10711 name: LanguageServerName,
10712 cx: &mut AsyncApp,
10713 ) {
10714 let server = match server_state {
10715 Some(LanguageServerState::Starting { startup, .. }) => {
10716 let mut timer = cx
10717 .background_executor()
10718 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10719 .fuse();
10720
10721 select! {
10722 server = startup.fuse() => server,
10723 () = timer => {
10724 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10725 None
10726 },
10727 }
10728 }
10729
10730 Some(LanguageServerState::Running { server, .. }) => Some(server),
10731
10732 None => None,
10733 };
10734
10735 if let Some(server) = server
10736 && let Some(shutdown) = server.shutdown()
10737 {
10738 shutdown.await;
10739 }
10740 }
10741
10742 // Returns a list of all of the worktrees which no longer have a language server and the root path
10743 // for the stopped server
10744 fn stop_local_language_server(
10745 &mut self,
10746 server_id: LanguageServerId,
10747 cx: &mut Context<Self>,
10748 ) -> Task<()> {
10749 let local = match &mut self.mode {
10750 LspStoreMode::Local(local) => local,
10751 _ => {
10752 return Task::ready(());
10753 }
10754 };
10755
10756 // Remove this server ID from all entries in the given worktree.
10757 local
10758 .language_server_ids
10759 .retain(|_, state| state.id != server_id);
10760 self.buffer_store.update(cx, |buffer_store, cx| {
10761 for buffer in buffer_store.buffers() {
10762 buffer.update(cx, |buffer, cx| {
10763 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10764 buffer.set_completion_triggers(server_id, Default::default(), cx);
10765 });
10766 }
10767 });
10768
10769 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10770 summaries.retain(|path, summaries_by_server_id| {
10771 if summaries_by_server_id.remove(&server_id).is_some() {
10772 if let Some((client, project_id)) = self.downstream_client.clone() {
10773 client
10774 .send(proto::UpdateDiagnosticSummary {
10775 project_id,
10776 worktree_id: worktree_id.to_proto(),
10777 summary: Some(proto::DiagnosticSummary {
10778 path: path.as_ref().to_proto(),
10779 language_server_id: server_id.0 as u64,
10780 error_count: 0,
10781 warning_count: 0,
10782 }),
10783 more_summaries: Vec::new(),
10784 })
10785 .log_err();
10786 }
10787 !summaries_by_server_id.is_empty()
10788 } else {
10789 true
10790 }
10791 });
10792 }
10793
10794 let local = self.as_local_mut().unwrap();
10795 for diagnostics in local.diagnostics.values_mut() {
10796 diagnostics.retain(|_, diagnostics_by_server_id| {
10797 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10798 diagnostics_by_server_id.remove(ix);
10799 !diagnostics_by_server_id.is_empty()
10800 } else {
10801 true
10802 }
10803 });
10804 }
10805 local.language_server_watched_paths.remove(&server_id);
10806
10807 let server_state = local.language_servers.remove(&server_id);
10808 self.cleanup_lsp_data(server_id);
10809 let name = self
10810 .language_server_statuses
10811 .remove(&server_id)
10812 .map(|status| status.name)
10813 .or_else(|| {
10814 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10815 Some(adapter.name())
10816 } else {
10817 None
10818 }
10819 });
10820
10821 if let Some(name) = name {
10822 log::info!("stopping language server {name}");
10823 self.languages
10824 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10825 cx.notify();
10826
10827 return cx.spawn(async move |lsp_store, cx| {
10828 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10829 lsp_store
10830 .update(cx, |lsp_store, cx| {
10831 lsp_store
10832 .languages
10833 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10834 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10835 cx.notify();
10836 })
10837 .ok();
10838 });
10839 }
10840
10841 if server_state.is_some() {
10842 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10843 }
10844 Task::ready(())
10845 }
10846
10847 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10848 if let Some((client, project_id)) = self.upstream_client() {
10849 let request = client.request(proto::StopLanguageServers {
10850 project_id,
10851 buffer_ids: Vec::new(),
10852 also_servers: Vec::new(),
10853 all: true,
10854 });
10855 cx.background_spawn(request).detach_and_log_err(cx);
10856 } else {
10857 let Some(local) = self.as_local_mut() else {
10858 return;
10859 };
10860 let language_servers_to_stop = local
10861 .language_server_ids
10862 .values()
10863 .map(|state| state.id)
10864 .collect();
10865 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10866 let tasks = language_servers_to_stop
10867 .into_iter()
10868 .map(|server| self.stop_local_language_server(server, cx))
10869 .collect::<Vec<_>>();
10870 cx.background_spawn(async move {
10871 futures::future::join_all(tasks).await;
10872 })
10873 .detach();
10874 }
10875 }
10876
10877 pub fn restart_language_servers_for_buffers(
10878 &mut self,
10879 buffers: Vec<Entity<Buffer>>,
10880 only_restart_servers: HashSet<LanguageServerSelector>,
10881 cx: &mut Context<Self>,
10882 ) {
10883 if let Some((client, project_id)) = self.upstream_client() {
10884 let request = client.request(proto::RestartLanguageServers {
10885 project_id,
10886 buffer_ids: buffers
10887 .into_iter()
10888 .map(|b| b.read(cx).remote_id().to_proto())
10889 .collect(),
10890 only_servers: only_restart_servers
10891 .into_iter()
10892 .map(|selector| {
10893 let selector = match selector {
10894 LanguageServerSelector::Id(language_server_id) => {
10895 proto::language_server_selector::Selector::ServerId(
10896 language_server_id.to_proto(),
10897 )
10898 }
10899 LanguageServerSelector::Name(language_server_name) => {
10900 proto::language_server_selector::Selector::Name(
10901 language_server_name.to_string(),
10902 )
10903 }
10904 };
10905 proto::LanguageServerSelector {
10906 selector: Some(selector),
10907 }
10908 })
10909 .collect(),
10910 all: false,
10911 });
10912 cx.background_spawn(request).detach_and_log_err(cx);
10913 } else {
10914 let stop_task = if only_restart_servers.is_empty() {
10915 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10916 } else {
10917 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10918 };
10919 cx.spawn(async move |lsp_store, cx| {
10920 stop_task.await;
10921 lsp_store
10922 .update(cx, |lsp_store, cx| {
10923 for buffer in buffers {
10924 lsp_store.register_buffer_with_language_servers(
10925 &buffer,
10926 only_restart_servers.clone(),
10927 true,
10928 cx,
10929 );
10930 }
10931 })
10932 .ok()
10933 })
10934 .detach();
10935 }
10936 }
10937
10938 pub fn stop_language_servers_for_buffers(
10939 &mut self,
10940 buffers: Vec<Entity<Buffer>>,
10941 also_stop_servers: HashSet<LanguageServerSelector>,
10942 cx: &mut Context<Self>,
10943 ) -> Task<Result<()>> {
10944 if let Some((client, project_id)) = self.upstream_client() {
10945 let request = client.request(proto::StopLanguageServers {
10946 project_id,
10947 buffer_ids: buffers
10948 .into_iter()
10949 .map(|b| b.read(cx).remote_id().to_proto())
10950 .collect(),
10951 also_servers: also_stop_servers
10952 .into_iter()
10953 .map(|selector| {
10954 let selector = match selector {
10955 LanguageServerSelector::Id(language_server_id) => {
10956 proto::language_server_selector::Selector::ServerId(
10957 language_server_id.to_proto(),
10958 )
10959 }
10960 LanguageServerSelector::Name(language_server_name) => {
10961 proto::language_server_selector::Selector::Name(
10962 language_server_name.to_string(),
10963 )
10964 }
10965 };
10966 proto::LanguageServerSelector {
10967 selector: Some(selector),
10968 }
10969 })
10970 .collect(),
10971 all: false,
10972 });
10973 cx.background_spawn(async move {
10974 let _ = request.await?;
10975 Ok(())
10976 })
10977 } else {
10978 let task =
10979 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10980 cx.background_spawn(async move {
10981 task.await;
10982 Ok(())
10983 })
10984 }
10985 }
10986
10987 fn stop_local_language_servers_for_buffers(
10988 &mut self,
10989 buffers: &[Entity<Buffer>],
10990 also_stop_servers: HashSet<LanguageServerSelector>,
10991 cx: &mut Context<Self>,
10992 ) -> Task<()> {
10993 let Some(local) = self.as_local_mut() else {
10994 return Task::ready(());
10995 };
10996 let mut language_server_names_to_stop = BTreeSet::default();
10997 let mut language_servers_to_stop = also_stop_servers
10998 .into_iter()
10999 .flat_map(|selector| match selector {
11000 LanguageServerSelector::Id(id) => Some(id),
11001 LanguageServerSelector::Name(name) => {
11002 language_server_names_to_stop.insert(name);
11003 None
11004 }
11005 })
11006 .collect::<BTreeSet<_>>();
11007
11008 let mut covered_worktrees = HashSet::default();
11009 for buffer in buffers {
11010 buffer.update(cx, |buffer, cx| {
11011 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11012 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11013 && covered_worktrees.insert(worktree_id)
11014 {
11015 language_server_names_to_stop.retain(|name| {
11016 let old_ids_count = language_servers_to_stop.len();
11017 let all_language_servers_with_this_name = local
11018 .language_server_ids
11019 .iter()
11020 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11021 language_servers_to_stop.extend(all_language_servers_with_this_name);
11022 old_ids_count == language_servers_to_stop.len()
11023 });
11024 }
11025 });
11026 }
11027 for name in language_server_names_to_stop {
11028 language_servers_to_stop.extend(
11029 local
11030 .language_server_ids
11031 .iter()
11032 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11033 );
11034 }
11035
11036 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11037 let tasks = language_servers_to_stop
11038 .into_iter()
11039 .map(|server| self.stop_local_language_server(server, cx))
11040 .collect::<Vec<_>>();
11041
11042 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11043 }
11044
11045 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11046 let (worktree, relative_path) =
11047 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11048
11049 let project_path = ProjectPath {
11050 worktree_id: worktree.read(cx).id(),
11051 path: relative_path,
11052 };
11053
11054 Some(
11055 self.buffer_store()
11056 .read(cx)
11057 .get_by_path(&project_path)?
11058 .read(cx),
11059 )
11060 }
11061
11062 #[cfg(any(test, feature = "test-support"))]
11063 pub fn update_diagnostics(
11064 &mut self,
11065 server_id: LanguageServerId,
11066 diagnostics: lsp::PublishDiagnosticsParams,
11067 result_id: Option<SharedString>,
11068 source_kind: DiagnosticSourceKind,
11069 disk_based_sources: &[String],
11070 cx: &mut Context<Self>,
11071 ) -> Result<()> {
11072 self.merge_lsp_diagnostics(
11073 source_kind,
11074 vec![DocumentDiagnosticsUpdate {
11075 diagnostics,
11076 result_id,
11077 server_id,
11078 disk_based_sources: Cow::Borrowed(disk_based_sources),
11079 registration_id: None,
11080 }],
11081 |_, _, _| false,
11082 cx,
11083 )
11084 }
11085
11086 pub fn merge_lsp_diagnostics(
11087 &mut self,
11088 source_kind: DiagnosticSourceKind,
11089 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11090 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11091 cx: &mut Context<Self>,
11092 ) -> Result<()> {
11093 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11094 let updates = lsp_diagnostics
11095 .into_iter()
11096 .filter_map(|update| {
11097 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11098 Some(DocumentDiagnosticsUpdate {
11099 diagnostics: self.lsp_to_document_diagnostics(
11100 abs_path,
11101 source_kind,
11102 update.server_id,
11103 update.diagnostics,
11104 &update.disk_based_sources,
11105 update.registration_id.clone(),
11106 ),
11107 result_id: update.result_id,
11108 server_id: update.server_id,
11109 disk_based_sources: update.disk_based_sources,
11110 registration_id: update.registration_id,
11111 })
11112 })
11113 .collect();
11114 self.merge_diagnostic_entries(updates, merge, cx)?;
11115 Ok(())
11116 }
11117
11118 fn lsp_to_document_diagnostics(
11119 &mut self,
11120 document_abs_path: PathBuf,
11121 source_kind: DiagnosticSourceKind,
11122 server_id: LanguageServerId,
11123 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11124 disk_based_sources: &[String],
11125 registration_id: Option<SharedString>,
11126 ) -> DocumentDiagnostics {
11127 let mut diagnostics = Vec::default();
11128 let mut primary_diagnostic_group_ids = HashMap::default();
11129 let mut sources_by_group_id = HashMap::default();
11130 let mut supporting_diagnostics = HashMap::default();
11131
11132 let adapter = self.language_server_adapter_for_id(server_id);
11133
11134 // Ensure that primary diagnostics are always the most severe
11135 lsp_diagnostics
11136 .diagnostics
11137 .sort_by_key(|item| item.severity);
11138
11139 for diagnostic in &lsp_diagnostics.diagnostics {
11140 let source = diagnostic.source.as_ref();
11141 let range = range_from_lsp(diagnostic.range);
11142 let is_supporting = diagnostic
11143 .related_information
11144 .as_ref()
11145 .is_some_and(|infos| {
11146 infos.iter().any(|info| {
11147 primary_diagnostic_group_ids.contains_key(&(
11148 source,
11149 diagnostic.code.clone(),
11150 range_from_lsp(info.location.range),
11151 ))
11152 })
11153 });
11154
11155 let is_unnecessary = diagnostic
11156 .tags
11157 .as_ref()
11158 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11159
11160 let underline = self
11161 .language_server_adapter_for_id(server_id)
11162 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11163
11164 if is_supporting {
11165 supporting_diagnostics.insert(
11166 (source, diagnostic.code.clone(), range),
11167 (diagnostic.severity, is_unnecessary),
11168 );
11169 } else {
11170 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11171 let is_disk_based =
11172 source.is_some_and(|source| disk_based_sources.contains(source));
11173
11174 sources_by_group_id.insert(group_id, source);
11175 primary_diagnostic_group_ids
11176 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11177
11178 diagnostics.push(DiagnosticEntry {
11179 range,
11180 diagnostic: Diagnostic {
11181 source: diagnostic.source.clone(),
11182 source_kind,
11183 code: diagnostic.code.clone(),
11184 code_description: diagnostic
11185 .code_description
11186 .as_ref()
11187 .and_then(|d| d.href.clone()),
11188 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11189 markdown: adapter.as_ref().and_then(|adapter| {
11190 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11191 }),
11192 message: diagnostic.message.trim().to_string(),
11193 group_id,
11194 is_primary: true,
11195 is_disk_based,
11196 is_unnecessary,
11197 underline,
11198 data: diagnostic.data.clone(),
11199 registration_id: registration_id.clone(),
11200 },
11201 });
11202 if let Some(infos) = &diagnostic.related_information {
11203 for info in infos {
11204 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11205 let range = range_from_lsp(info.location.range);
11206 diagnostics.push(DiagnosticEntry {
11207 range,
11208 diagnostic: Diagnostic {
11209 source: diagnostic.source.clone(),
11210 source_kind,
11211 code: diagnostic.code.clone(),
11212 code_description: diagnostic
11213 .code_description
11214 .as_ref()
11215 .and_then(|d| d.href.clone()),
11216 severity: DiagnosticSeverity::INFORMATION,
11217 markdown: adapter.as_ref().and_then(|adapter| {
11218 adapter.diagnostic_message_to_markdown(&info.message)
11219 }),
11220 message: info.message.trim().to_string(),
11221 group_id,
11222 is_primary: false,
11223 is_disk_based,
11224 is_unnecessary: false,
11225 underline,
11226 data: diagnostic.data.clone(),
11227 registration_id: registration_id.clone(),
11228 },
11229 });
11230 }
11231 }
11232 }
11233 }
11234 }
11235
11236 for entry in &mut diagnostics {
11237 let diagnostic = &mut entry.diagnostic;
11238 if !diagnostic.is_primary {
11239 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11240 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11241 source,
11242 diagnostic.code.clone(),
11243 entry.range.clone(),
11244 )) {
11245 if let Some(severity) = severity {
11246 diagnostic.severity = severity;
11247 }
11248 diagnostic.is_unnecessary = is_unnecessary;
11249 }
11250 }
11251 }
11252
11253 DocumentDiagnostics {
11254 diagnostics,
11255 document_abs_path,
11256 version: lsp_diagnostics.version,
11257 }
11258 }
11259
11260 fn insert_newly_running_language_server(
11261 &mut self,
11262 adapter: Arc<CachedLspAdapter>,
11263 language_server: Arc<LanguageServer>,
11264 server_id: LanguageServerId,
11265 key: LanguageServerSeed,
11266 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11267 cx: &mut Context<Self>,
11268 ) {
11269 let Some(local) = self.as_local_mut() else {
11270 return;
11271 };
11272 // If the language server for this key doesn't match the server id, don't store the
11273 // server. Which will cause it to be dropped, killing the process
11274 if local
11275 .language_server_ids
11276 .get(&key)
11277 .map(|state| state.id != server_id)
11278 .unwrap_or(false)
11279 {
11280 return;
11281 }
11282
11283 // Update language_servers collection with Running variant of LanguageServerState
11284 // indicating that the server is up and running and ready
11285 let workspace_folders = workspace_folders.lock().clone();
11286 language_server.set_workspace_folders(workspace_folders);
11287
11288 let workspace_diagnostics_refresh_tasks = language_server
11289 .capabilities()
11290 .diagnostic_provider
11291 .and_then(|provider| {
11292 local
11293 .language_server_dynamic_registrations
11294 .entry(server_id)
11295 .or_default()
11296 .diagnostics
11297 .entry(None)
11298 .or_insert(provider.clone());
11299 let workspace_refresher =
11300 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11301
11302 Some((None, workspace_refresher))
11303 })
11304 .into_iter()
11305 .collect();
11306 local.language_servers.insert(
11307 server_id,
11308 LanguageServerState::Running {
11309 workspace_diagnostics_refresh_tasks,
11310 adapter: adapter.clone(),
11311 server: language_server.clone(),
11312 simulate_disk_based_diagnostics_completion: None,
11313 },
11314 );
11315 local
11316 .languages
11317 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11318 if let Some(file_ops_caps) = language_server
11319 .capabilities()
11320 .workspace
11321 .as_ref()
11322 .and_then(|ws| ws.file_operations.as_ref())
11323 {
11324 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11325 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11326 if did_rename_caps.or(will_rename_caps).is_some() {
11327 let watcher = RenamePathsWatchedForServer::default()
11328 .with_did_rename_patterns(did_rename_caps)
11329 .with_will_rename_patterns(will_rename_caps);
11330 local
11331 .language_server_paths_watched_for_rename
11332 .insert(server_id, watcher);
11333 }
11334 }
11335
11336 self.language_server_statuses.insert(
11337 server_id,
11338 LanguageServerStatus {
11339 name: language_server.name(),
11340 pending_work: Default::default(),
11341 has_pending_diagnostic_updates: false,
11342 progress_tokens: Default::default(),
11343 worktree: Some(key.worktree_id),
11344 binary: Some(language_server.binary().clone()),
11345 configuration: Some(language_server.configuration().clone()),
11346 workspace_folders: language_server.workspace_folders(),
11347 },
11348 );
11349
11350 cx.emit(LspStoreEvent::LanguageServerAdded(
11351 server_id,
11352 language_server.name(),
11353 Some(key.worktree_id),
11354 ));
11355
11356 let server_capabilities = language_server.capabilities();
11357 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11358 downstream_client
11359 .send(proto::StartLanguageServer {
11360 project_id: *project_id,
11361 server: Some(proto::LanguageServer {
11362 id: server_id.to_proto(),
11363 name: language_server.name().to_string(),
11364 worktree_id: Some(key.worktree_id.to_proto()),
11365 }),
11366 capabilities: serde_json::to_string(&server_capabilities)
11367 .expect("serializing server LSP capabilities"),
11368 })
11369 .log_err();
11370 }
11371 self.lsp_server_capabilities
11372 .insert(server_id, server_capabilities);
11373
11374 // Tell the language server about every open buffer in the worktree that matches the language.
11375 // Also check for buffers in worktrees that reused this server
11376 let mut worktrees_using_server = vec![key.worktree_id];
11377 if let Some(local) = self.as_local() {
11378 // Find all worktrees that have this server in their language server tree
11379 for (worktree_id, servers) in &local.lsp_tree.instances {
11380 if *worktree_id != key.worktree_id {
11381 for server_map in servers.roots.values() {
11382 if server_map
11383 .values()
11384 .any(|(node, _)| node.id() == Some(server_id))
11385 {
11386 worktrees_using_server.push(*worktree_id);
11387 }
11388 }
11389 }
11390 }
11391 }
11392
11393 let mut buffer_paths_registered = Vec::new();
11394 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11395 let mut lsp_adapters = HashMap::default();
11396 for buffer_handle in buffer_store.buffers() {
11397 let buffer = buffer_handle.read(cx);
11398 let file = match File::from_dyn(buffer.file()) {
11399 Some(file) => file,
11400 None => continue,
11401 };
11402 let language = match buffer.language() {
11403 Some(language) => language,
11404 None => continue,
11405 };
11406
11407 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11408 || !lsp_adapters
11409 .entry(language.name())
11410 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11411 .iter()
11412 .any(|a| a.name == key.name)
11413 {
11414 continue;
11415 }
11416 // didOpen
11417 let file = match file.as_local() {
11418 Some(file) => file,
11419 None => continue,
11420 };
11421
11422 let local = self.as_local_mut().unwrap();
11423
11424 let buffer_id = buffer.remote_id();
11425 if local.registered_buffers.contains_key(&buffer_id) {
11426 let versions = local
11427 .buffer_snapshots
11428 .entry(buffer_id)
11429 .or_default()
11430 .entry(server_id)
11431 .and_modify(|_| {
11432 assert!(
11433 false,
11434 "There should not be an existing snapshot for a newly inserted buffer"
11435 )
11436 })
11437 .or_insert_with(|| {
11438 vec![LspBufferSnapshot {
11439 version: 0,
11440 snapshot: buffer.text_snapshot(),
11441 }]
11442 });
11443
11444 let snapshot = versions.last().unwrap();
11445 let version = snapshot.version;
11446 let initial_snapshot = &snapshot.snapshot;
11447 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11448 language_server.register_buffer(
11449 uri,
11450 adapter.language_id(&language.name()),
11451 version,
11452 initial_snapshot.text(),
11453 );
11454 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11455 local
11456 .buffers_opened_in_servers
11457 .entry(buffer_id)
11458 .or_default()
11459 .insert(server_id);
11460 }
11461 buffer_handle.update(cx, |buffer, cx| {
11462 buffer.set_completion_triggers(
11463 server_id,
11464 language_server
11465 .capabilities()
11466 .completion_provider
11467 .as_ref()
11468 .and_then(|provider| {
11469 provider
11470 .trigger_characters
11471 .as_ref()
11472 .map(|characters| characters.iter().cloned().collect())
11473 })
11474 .unwrap_or_default(),
11475 cx,
11476 )
11477 });
11478 }
11479 });
11480
11481 for (buffer_id, abs_path) in buffer_paths_registered {
11482 cx.emit(LspStoreEvent::LanguageServerUpdate {
11483 language_server_id: server_id,
11484 name: Some(adapter.name()),
11485 message: proto::update_language_server::Variant::RegisteredForBuffer(
11486 proto::RegisteredForBuffer {
11487 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11488 buffer_id: buffer_id.to_proto(),
11489 },
11490 ),
11491 });
11492 }
11493
11494 cx.notify();
11495 }
11496
11497 pub fn language_servers_running_disk_based_diagnostics(
11498 &self,
11499 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11500 self.language_server_statuses
11501 .iter()
11502 .filter_map(|(id, status)| {
11503 if status.has_pending_diagnostic_updates {
11504 Some(*id)
11505 } else {
11506 None
11507 }
11508 })
11509 }
11510
11511 pub(crate) fn cancel_language_server_work_for_buffers(
11512 &mut self,
11513 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11514 cx: &mut Context<Self>,
11515 ) {
11516 if let Some((client, project_id)) = self.upstream_client() {
11517 let request = client.request(proto::CancelLanguageServerWork {
11518 project_id,
11519 work: Some(proto::cancel_language_server_work::Work::Buffers(
11520 proto::cancel_language_server_work::Buffers {
11521 buffer_ids: buffers
11522 .into_iter()
11523 .map(|b| b.read(cx).remote_id().to_proto())
11524 .collect(),
11525 },
11526 )),
11527 });
11528 cx.background_spawn(request).detach_and_log_err(cx);
11529 } else if let Some(local) = self.as_local() {
11530 let servers = buffers
11531 .into_iter()
11532 .flat_map(|buffer| {
11533 buffer.update(cx, |buffer, cx| {
11534 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11535 })
11536 })
11537 .collect::<HashSet<_>>();
11538 for server_id in servers {
11539 self.cancel_language_server_work(server_id, None, cx);
11540 }
11541 }
11542 }
11543
11544 pub(crate) fn cancel_language_server_work(
11545 &mut self,
11546 server_id: LanguageServerId,
11547 token_to_cancel: Option<ProgressToken>,
11548 cx: &mut Context<Self>,
11549 ) {
11550 if let Some(local) = self.as_local() {
11551 let status = self.language_server_statuses.get(&server_id);
11552 let server = local.language_servers.get(&server_id);
11553 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11554 {
11555 for (token, progress) in &status.pending_work {
11556 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11557 && token != token_to_cancel
11558 {
11559 continue;
11560 }
11561 if progress.is_cancellable {
11562 server
11563 .notify::<lsp::notification::WorkDoneProgressCancel>(
11564 WorkDoneProgressCancelParams {
11565 token: token.to_lsp(),
11566 },
11567 )
11568 .ok();
11569 }
11570 }
11571 }
11572 } else if let Some((client, project_id)) = self.upstream_client() {
11573 let request = client.request(proto::CancelLanguageServerWork {
11574 project_id,
11575 work: Some(
11576 proto::cancel_language_server_work::Work::LanguageServerWork(
11577 proto::cancel_language_server_work::LanguageServerWork {
11578 language_server_id: server_id.to_proto(),
11579 token: token_to_cancel.map(|token| token.to_proto()),
11580 },
11581 ),
11582 ),
11583 });
11584 cx.background_spawn(request).detach_and_log_err(cx);
11585 }
11586 }
11587
11588 fn register_supplementary_language_server(
11589 &mut self,
11590 id: LanguageServerId,
11591 name: LanguageServerName,
11592 server: Arc<LanguageServer>,
11593 cx: &mut Context<Self>,
11594 ) {
11595 if let Some(local) = self.as_local_mut() {
11596 local
11597 .supplementary_language_servers
11598 .insert(id, (name.clone(), server));
11599 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11600 }
11601 }
11602
11603 fn unregister_supplementary_language_server(
11604 &mut self,
11605 id: LanguageServerId,
11606 cx: &mut Context<Self>,
11607 ) {
11608 if let Some(local) = self.as_local_mut() {
11609 local.supplementary_language_servers.remove(&id);
11610 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11611 }
11612 }
11613
11614 pub(crate) fn supplementary_language_servers(
11615 &self,
11616 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11617 self.as_local().into_iter().flat_map(|local| {
11618 local
11619 .supplementary_language_servers
11620 .iter()
11621 .map(|(id, (name, _))| (*id, name.clone()))
11622 })
11623 }
11624
11625 pub fn language_server_adapter_for_id(
11626 &self,
11627 id: LanguageServerId,
11628 ) -> Option<Arc<CachedLspAdapter>> {
11629 self.as_local()
11630 .and_then(|local| local.language_servers.get(&id))
11631 .and_then(|language_server_state| match language_server_state {
11632 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11633 _ => None,
11634 })
11635 }
11636
11637 pub(super) fn update_local_worktree_language_servers(
11638 &mut self,
11639 worktree_handle: &Entity<Worktree>,
11640 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11641 cx: &mut Context<Self>,
11642 ) {
11643 if changes.is_empty() {
11644 return;
11645 }
11646
11647 let Some(local) = self.as_local() else { return };
11648
11649 local.prettier_store.update(cx, |prettier_store, cx| {
11650 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11651 });
11652
11653 let worktree_id = worktree_handle.read(cx).id();
11654 let mut language_server_ids = local
11655 .language_server_ids
11656 .iter()
11657 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11658 .collect::<Vec<_>>();
11659 language_server_ids.sort();
11660 language_server_ids.dedup();
11661
11662 // let abs_path = worktree_handle.read(cx).abs_path();
11663 for server_id in &language_server_ids {
11664 if let Some(LanguageServerState::Running { server, .. }) =
11665 local.language_servers.get(server_id)
11666 && let Some(watched_paths) = local
11667 .language_server_watched_paths
11668 .get(server_id)
11669 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11670 {
11671 let params = lsp::DidChangeWatchedFilesParams {
11672 changes: changes
11673 .iter()
11674 .filter_map(|(path, _, change)| {
11675 if !watched_paths.is_match(path.as_std_path()) {
11676 return None;
11677 }
11678 let typ = match change {
11679 PathChange::Loaded => return None,
11680 PathChange::Added => lsp::FileChangeType::CREATED,
11681 PathChange::Removed => lsp::FileChangeType::DELETED,
11682 PathChange::Updated => lsp::FileChangeType::CHANGED,
11683 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11684 };
11685 let uri = lsp::Uri::from_file_path(
11686 worktree_handle.read(cx).absolutize(&path),
11687 )
11688 .ok()?;
11689 Some(lsp::FileEvent { uri, typ })
11690 })
11691 .collect(),
11692 };
11693 if !params.changes.is_empty() {
11694 server
11695 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11696 .ok();
11697 }
11698 }
11699 }
11700 for (path, _, _) in changes {
11701 if let Some(file_name) = path.file_name()
11702 && local.watched_manifest_filenames.contains(file_name)
11703 {
11704 self.request_workspace_config_refresh();
11705 break;
11706 }
11707 }
11708 }
11709
11710 pub fn wait_for_remote_buffer(
11711 &mut self,
11712 id: BufferId,
11713 cx: &mut Context<Self>,
11714 ) -> Task<Result<Entity<Buffer>>> {
11715 self.buffer_store.update(cx, |buffer_store, cx| {
11716 buffer_store.wait_for_remote_buffer(id, cx)
11717 })
11718 }
11719
11720 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11721 let mut result = proto::Symbol {
11722 language_server_name: symbol.language_server_name.0.to_string(),
11723 source_worktree_id: symbol.source_worktree_id.to_proto(),
11724 language_server_id: symbol.source_language_server_id.to_proto(),
11725 name: symbol.name.clone(),
11726 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11727 start: Some(proto::PointUtf16 {
11728 row: symbol.range.start.0.row,
11729 column: symbol.range.start.0.column,
11730 }),
11731 end: Some(proto::PointUtf16 {
11732 row: symbol.range.end.0.row,
11733 column: symbol.range.end.0.column,
11734 }),
11735 worktree_id: Default::default(),
11736 path: Default::default(),
11737 signature: Default::default(),
11738 };
11739 match &symbol.path {
11740 SymbolLocation::InProject(path) => {
11741 result.worktree_id = path.worktree_id.to_proto();
11742 result.path = path.path.to_proto();
11743 }
11744 SymbolLocation::OutsideProject {
11745 abs_path,
11746 signature,
11747 } => {
11748 result.path = abs_path.to_string_lossy().into_owned();
11749 result.signature = signature.to_vec();
11750 }
11751 }
11752 result
11753 }
11754
11755 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11756 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11757 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11758 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11759
11760 let path = if serialized_symbol.signature.is_empty() {
11761 SymbolLocation::InProject(ProjectPath {
11762 worktree_id,
11763 path: RelPath::from_proto(&serialized_symbol.path)
11764 .context("invalid symbol path")?,
11765 })
11766 } else {
11767 SymbolLocation::OutsideProject {
11768 abs_path: Path::new(&serialized_symbol.path).into(),
11769 signature: serialized_symbol
11770 .signature
11771 .try_into()
11772 .map_err(|_| anyhow!("invalid signature"))?,
11773 }
11774 };
11775
11776 let start = serialized_symbol.start.context("invalid start")?;
11777 let end = serialized_symbol.end.context("invalid end")?;
11778 Ok(CoreSymbol {
11779 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11780 source_worktree_id,
11781 source_language_server_id: LanguageServerId::from_proto(
11782 serialized_symbol.language_server_id,
11783 ),
11784 path,
11785 name: serialized_symbol.name,
11786 range: Unclipped(PointUtf16::new(start.row, start.column))
11787 ..Unclipped(PointUtf16::new(end.row, end.column)),
11788 kind,
11789 })
11790 }
11791
11792 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11793 let mut serialized_completion = proto::Completion {
11794 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11795 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11796 new_text: completion.new_text.clone(),
11797 ..proto::Completion::default()
11798 };
11799 match &completion.source {
11800 CompletionSource::Lsp {
11801 insert_range,
11802 server_id,
11803 lsp_completion,
11804 lsp_defaults,
11805 resolved,
11806 } => {
11807 let (old_insert_start, old_insert_end) = insert_range
11808 .as_ref()
11809 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11810 .unzip();
11811
11812 serialized_completion.old_insert_start = old_insert_start;
11813 serialized_completion.old_insert_end = old_insert_end;
11814 serialized_completion.source = proto::completion::Source::Lsp as i32;
11815 serialized_completion.server_id = server_id.0 as u64;
11816 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11817 serialized_completion.lsp_defaults = lsp_defaults
11818 .as_deref()
11819 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11820 serialized_completion.resolved = *resolved;
11821 }
11822 CompletionSource::BufferWord {
11823 word_range,
11824 resolved,
11825 } => {
11826 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11827 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11828 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11829 serialized_completion.resolved = *resolved;
11830 }
11831 CompletionSource::Custom => {
11832 serialized_completion.source = proto::completion::Source::Custom as i32;
11833 serialized_completion.resolved = true;
11834 }
11835 CompletionSource::Dap { sort_text } => {
11836 serialized_completion.source = proto::completion::Source::Dap as i32;
11837 serialized_completion.sort_text = Some(sort_text.clone());
11838 }
11839 }
11840
11841 serialized_completion
11842 }
11843
11844 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11845 let old_replace_start = completion
11846 .old_replace_start
11847 .and_then(deserialize_anchor)
11848 .context("invalid old start")?;
11849 let old_replace_end = completion
11850 .old_replace_end
11851 .and_then(deserialize_anchor)
11852 .context("invalid old end")?;
11853 let insert_range = {
11854 match completion.old_insert_start.zip(completion.old_insert_end) {
11855 Some((start, end)) => {
11856 let start = deserialize_anchor(start).context("invalid insert old start")?;
11857 let end = deserialize_anchor(end).context("invalid insert old end")?;
11858 Some(start..end)
11859 }
11860 None => None,
11861 }
11862 };
11863 Ok(CoreCompletion {
11864 replace_range: old_replace_start..old_replace_end,
11865 new_text: completion.new_text,
11866 source: match proto::completion::Source::from_i32(completion.source) {
11867 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11868 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11869 insert_range,
11870 server_id: LanguageServerId::from_proto(completion.server_id),
11871 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11872 lsp_defaults: completion
11873 .lsp_defaults
11874 .as_deref()
11875 .map(serde_json::from_slice)
11876 .transpose()?,
11877 resolved: completion.resolved,
11878 },
11879 Some(proto::completion::Source::BufferWord) => {
11880 let word_range = completion
11881 .buffer_word_start
11882 .and_then(deserialize_anchor)
11883 .context("invalid buffer word start")?
11884 ..completion
11885 .buffer_word_end
11886 .and_then(deserialize_anchor)
11887 .context("invalid buffer word end")?;
11888 CompletionSource::BufferWord {
11889 word_range,
11890 resolved: completion.resolved,
11891 }
11892 }
11893 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11894 sort_text: completion
11895 .sort_text
11896 .context("expected sort text to exist")?,
11897 },
11898 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11899 },
11900 })
11901 }
11902
11903 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11904 let (kind, lsp_action) = match &action.lsp_action {
11905 LspAction::Action(code_action) => (
11906 proto::code_action::Kind::Action as i32,
11907 serde_json::to_vec(code_action).unwrap(),
11908 ),
11909 LspAction::Command(command) => (
11910 proto::code_action::Kind::Command as i32,
11911 serde_json::to_vec(command).unwrap(),
11912 ),
11913 LspAction::CodeLens(code_lens) => (
11914 proto::code_action::Kind::CodeLens as i32,
11915 serde_json::to_vec(code_lens).unwrap(),
11916 ),
11917 };
11918
11919 proto::CodeAction {
11920 server_id: action.server_id.0 as u64,
11921 start: Some(serialize_anchor(&action.range.start)),
11922 end: Some(serialize_anchor(&action.range.end)),
11923 lsp_action,
11924 kind,
11925 resolved: action.resolved,
11926 }
11927 }
11928
11929 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11930 let start = action
11931 .start
11932 .and_then(deserialize_anchor)
11933 .context("invalid start")?;
11934 let end = action
11935 .end
11936 .and_then(deserialize_anchor)
11937 .context("invalid end")?;
11938 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11939 Some(proto::code_action::Kind::Action) => {
11940 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11941 }
11942 Some(proto::code_action::Kind::Command) => {
11943 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11944 }
11945 Some(proto::code_action::Kind::CodeLens) => {
11946 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11947 }
11948 None => anyhow::bail!("Unknown action kind {}", action.kind),
11949 };
11950 Ok(CodeAction {
11951 server_id: LanguageServerId(action.server_id as usize),
11952 range: start..end,
11953 resolved: action.resolved,
11954 lsp_action,
11955 })
11956 }
11957
11958 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11959 match &formatting_result {
11960 Ok(_) => self.last_formatting_failure = None,
11961 Err(error) => {
11962 let error_string = format!("{error:#}");
11963 log::error!("Formatting failed: {error_string}");
11964 self.last_formatting_failure
11965 .replace(error_string.lines().join(" "));
11966 }
11967 }
11968 }
11969
11970 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11971 self.lsp_server_capabilities.remove(&for_server);
11972 for lsp_data in self.lsp_data.values_mut() {
11973 lsp_data.remove_server_data(for_server);
11974 }
11975 if let Some(local) = self.as_local_mut() {
11976 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11977 local
11978 .workspace_pull_diagnostics_result_ids
11979 .remove(&for_server);
11980 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11981 buffer_servers.remove(&for_server);
11982 }
11983 }
11984 }
11985
11986 pub fn result_id_for_buffer_pull(
11987 &self,
11988 server_id: LanguageServerId,
11989 buffer_id: BufferId,
11990 registration_id: &Option<SharedString>,
11991 cx: &App,
11992 ) -> Option<SharedString> {
11993 let abs_path = self
11994 .buffer_store
11995 .read(cx)
11996 .get(buffer_id)
11997 .and_then(|b| File::from_dyn(b.read(cx).file()))
11998 .map(|f| f.abs_path(cx))?;
11999 self.as_local()?
12000 .buffer_pull_diagnostics_result_ids
12001 .get(&server_id)?
12002 .get(registration_id)?
12003 .get(&abs_path)?
12004 .clone()
12005 }
12006
12007 /// Gets all result_ids for a workspace diagnostics pull request.
12008 /// 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.
12009 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12010 pub fn result_ids_for_workspace_refresh(
12011 &self,
12012 server_id: LanguageServerId,
12013 registration_id: &Option<SharedString>,
12014 ) -> HashMap<PathBuf, SharedString> {
12015 let Some(local) = self.as_local() else {
12016 return HashMap::default();
12017 };
12018 local
12019 .workspace_pull_diagnostics_result_ids
12020 .get(&server_id)
12021 .into_iter()
12022 .filter_map(|diagnostics| diagnostics.get(registration_id))
12023 .flatten()
12024 .filter_map(|(abs_path, result_id)| {
12025 let result_id = local
12026 .buffer_pull_diagnostics_result_ids
12027 .get(&server_id)
12028 .and_then(|buffer_ids_result_ids| {
12029 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12030 })
12031 .cloned()
12032 .flatten()
12033 .or_else(|| result_id.clone())?;
12034 Some((abs_path.clone(), result_id))
12035 })
12036 .collect()
12037 }
12038
12039 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12040 if let Some(LanguageServerState::Running {
12041 workspace_diagnostics_refresh_tasks,
12042 ..
12043 }) = self
12044 .as_local_mut()
12045 .and_then(|local| local.language_servers.get_mut(&server_id))
12046 {
12047 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12048 diagnostics.refresh_tx.try_send(()).ok();
12049 }
12050 }
12051 }
12052
12053 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12054 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12055 return;
12056 };
12057 let Some(local) = self.as_local_mut() else {
12058 return;
12059 };
12060
12061 for server_id in buffer.update(cx, |buffer, cx| {
12062 local.language_server_ids_for_buffer(buffer, cx)
12063 }) {
12064 if let Some(LanguageServerState::Running {
12065 workspace_diagnostics_refresh_tasks,
12066 ..
12067 }) = local.language_servers.get_mut(&server_id)
12068 {
12069 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12070 diagnostics.refresh_tx.try_send(()).ok();
12071 }
12072 }
12073 }
12074 }
12075
12076 fn apply_workspace_diagnostic_report(
12077 &mut self,
12078 server_id: LanguageServerId,
12079 report: lsp::WorkspaceDiagnosticReportResult,
12080 registration_id: Option<SharedString>,
12081 cx: &mut Context<Self>,
12082 ) {
12083 let workspace_diagnostics =
12084 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12085 report,
12086 server_id,
12087 registration_id,
12088 );
12089 let mut unchanged_buffers = HashMap::default();
12090 let workspace_diagnostics_updates = workspace_diagnostics
12091 .into_iter()
12092 .filter_map(
12093 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12094 LspPullDiagnostics::Response {
12095 server_id,
12096 uri,
12097 diagnostics,
12098 registration_id,
12099 } => Some((
12100 server_id,
12101 uri,
12102 diagnostics,
12103 workspace_diagnostics.version,
12104 registration_id,
12105 )),
12106 LspPullDiagnostics::Default => None,
12107 },
12108 )
12109 .fold(
12110 HashMap::default(),
12111 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12112 let (result_id, diagnostics) = match diagnostics {
12113 PulledDiagnostics::Unchanged { result_id } => {
12114 unchanged_buffers
12115 .entry(new_registration_id.clone())
12116 .or_insert_with(HashSet::default)
12117 .insert(uri.clone());
12118 (Some(result_id), Vec::new())
12119 }
12120 PulledDiagnostics::Changed {
12121 result_id,
12122 diagnostics,
12123 } => (result_id, diagnostics),
12124 };
12125 let disk_based_sources = Cow::Owned(
12126 self.language_server_adapter_for_id(server_id)
12127 .as_ref()
12128 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12129 .unwrap_or(&[])
12130 .to_vec(),
12131 );
12132
12133 let Some(abs_path) = uri.to_file_path().ok() else {
12134 return acc;
12135 };
12136 let Some((worktree, relative_path)) =
12137 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12138 else {
12139 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12140 return acc;
12141 };
12142 let worktree_id = worktree.read(cx).id();
12143 let project_path = ProjectPath {
12144 worktree_id,
12145 path: relative_path,
12146 };
12147 if let Some(local_lsp_store) = self.as_local_mut() {
12148 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12149 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12150 }
12151 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12152 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12153 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12154 acc.entry(server_id)
12155 .or_insert_with(HashMap::default)
12156 .entry(new_registration_id.clone())
12157 .or_insert_with(Vec::new)
12158 .push(DocumentDiagnosticsUpdate {
12159 server_id,
12160 diagnostics: lsp::PublishDiagnosticsParams {
12161 uri,
12162 diagnostics,
12163 version,
12164 },
12165 result_id,
12166 disk_based_sources,
12167 registration_id: new_registration_id,
12168 });
12169 }
12170 acc
12171 },
12172 );
12173
12174 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12175 for (registration_id, diagnostic_updates) in diagnostic_updates {
12176 self.merge_lsp_diagnostics(
12177 DiagnosticSourceKind::Pulled,
12178 diagnostic_updates,
12179 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12180 DiagnosticSourceKind::Pulled => {
12181 old_diagnostic.registration_id != registration_id
12182 || unchanged_buffers
12183 .get(&old_diagnostic.registration_id)
12184 .is_some_and(|unchanged_buffers| {
12185 unchanged_buffers.contains(&document_uri)
12186 })
12187 }
12188 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12189 },
12190 cx,
12191 )
12192 .log_err();
12193 }
12194 }
12195 }
12196
12197 fn register_server_capabilities(
12198 &mut self,
12199 server_id: LanguageServerId,
12200 params: lsp::RegistrationParams,
12201 cx: &mut Context<Self>,
12202 ) -> anyhow::Result<()> {
12203 let server = self
12204 .language_server_for_id(server_id)
12205 .with_context(|| format!("no server {server_id} found"))?;
12206 for reg in params.registrations {
12207 match reg.method.as_str() {
12208 "workspace/didChangeWatchedFiles" => {
12209 if let Some(options) = reg.register_options {
12210 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12211 let caps = serde_json::from_value(options)?;
12212 local_lsp_store
12213 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12214 true
12215 } else {
12216 false
12217 };
12218 if notify {
12219 notify_server_capabilities_updated(&server, cx);
12220 }
12221 }
12222 }
12223 "workspace/didChangeConfiguration" => {
12224 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12225 }
12226 "workspace/didChangeWorkspaceFolders" => {
12227 // In this case register options is an empty object, we can ignore it
12228 let caps = lsp::WorkspaceFoldersServerCapabilities {
12229 supported: Some(true),
12230 change_notifications: Some(OneOf::Right(reg.id)),
12231 };
12232 server.update_capabilities(|capabilities| {
12233 capabilities
12234 .workspace
12235 .get_or_insert_default()
12236 .workspace_folders = Some(caps);
12237 });
12238 notify_server_capabilities_updated(&server, cx);
12239 }
12240 "workspace/symbol" => {
12241 let options = parse_register_capabilities(reg)?;
12242 server.update_capabilities(|capabilities| {
12243 capabilities.workspace_symbol_provider = Some(options);
12244 });
12245 notify_server_capabilities_updated(&server, cx);
12246 }
12247 "workspace/fileOperations" => {
12248 if let Some(options) = reg.register_options {
12249 let caps = serde_json::from_value(options)?;
12250 server.update_capabilities(|capabilities| {
12251 capabilities
12252 .workspace
12253 .get_or_insert_default()
12254 .file_operations = Some(caps);
12255 });
12256 notify_server_capabilities_updated(&server, cx);
12257 }
12258 }
12259 "workspace/executeCommand" => {
12260 if let Some(options) = reg.register_options {
12261 let options = serde_json::from_value(options)?;
12262 server.update_capabilities(|capabilities| {
12263 capabilities.execute_command_provider = Some(options);
12264 });
12265 notify_server_capabilities_updated(&server, cx);
12266 }
12267 }
12268 "textDocument/rangeFormatting" => {
12269 let options = parse_register_capabilities(reg)?;
12270 server.update_capabilities(|capabilities| {
12271 capabilities.document_range_formatting_provider = Some(options);
12272 });
12273 notify_server_capabilities_updated(&server, cx);
12274 }
12275 "textDocument/onTypeFormatting" => {
12276 if let Some(options) = reg
12277 .register_options
12278 .map(serde_json::from_value)
12279 .transpose()?
12280 {
12281 server.update_capabilities(|capabilities| {
12282 capabilities.document_on_type_formatting_provider = Some(options);
12283 });
12284 notify_server_capabilities_updated(&server, cx);
12285 }
12286 }
12287 "textDocument/formatting" => {
12288 let options = parse_register_capabilities(reg)?;
12289 server.update_capabilities(|capabilities| {
12290 capabilities.document_formatting_provider = Some(options);
12291 });
12292 notify_server_capabilities_updated(&server, cx);
12293 }
12294 "textDocument/rename" => {
12295 let options = parse_register_capabilities(reg)?;
12296 server.update_capabilities(|capabilities| {
12297 capabilities.rename_provider = Some(options);
12298 });
12299 notify_server_capabilities_updated(&server, cx);
12300 }
12301 "textDocument/inlayHint" => {
12302 let options = parse_register_capabilities(reg)?;
12303 server.update_capabilities(|capabilities| {
12304 capabilities.inlay_hint_provider = Some(options);
12305 });
12306 notify_server_capabilities_updated(&server, cx);
12307 }
12308 "textDocument/documentSymbol" => {
12309 let options = parse_register_capabilities(reg)?;
12310 server.update_capabilities(|capabilities| {
12311 capabilities.document_symbol_provider = Some(options);
12312 });
12313 notify_server_capabilities_updated(&server, cx);
12314 }
12315 "textDocument/codeAction" => {
12316 let options = parse_register_capabilities(reg)?;
12317 let provider = match options {
12318 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12319 OneOf::Right(caps) => caps,
12320 };
12321 server.update_capabilities(|capabilities| {
12322 capabilities.code_action_provider = Some(provider);
12323 });
12324 notify_server_capabilities_updated(&server, cx);
12325 }
12326 "textDocument/definition" => {
12327 let options = parse_register_capabilities(reg)?;
12328 server.update_capabilities(|capabilities| {
12329 capabilities.definition_provider = Some(options);
12330 });
12331 notify_server_capabilities_updated(&server, cx);
12332 }
12333 "textDocument/completion" => {
12334 if let Some(caps) = reg
12335 .register_options
12336 .map(serde_json::from_value::<CompletionOptions>)
12337 .transpose()?
12338 {
12339 server.update_capabilities(|capabilities| {
12340 capabilities.completion_provider = Some(caps.clone());
12341 });
12342
12343 if let Some(local) = self.as_local() {
12344 let mut buffers_with_language_server = Vec::new();
12345 for handle in self.buffer_store.read(cx).buffers() {
12346 let buffer_id = handle.read(cx).remote_id();
12347 if local
12348 .buffers_opened_in_servers
12349 .get(&buffer_id)
12350 .filter(|s| s.contains(&server_id))
12351 .is_some()
12352 {
12353 buffers_with_language_server.push(handle);
12354 }
12355 }
12356 let triggers = caps
12357 .trigger_characters
12358 .unwrap_or_default()
12359 .into_iter()
12360 .collect::<BTreeSet<_>>();
12361 for handle in buffers_with_language_server {
12362 let triggers = triggers.clone();
12363 let _ = handle.update(cx, move |buffer, cx| {
12364 buffer.set_completion_triggers(server_id, triggers, cx);
12365 });
12366 }
12367 }
12368 notify_server_capabilities_updated(&server, cx);
12369 }
12370 }
12371 "textDocument/hover" => {
12372 let options = parse_register_capabilities(reg)?;
12373 let provider = match options {
12374 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12375 OneOf::Right(caps) => caps,
12376 };
12377 server.update_capabilities(|capabilities| {
12378 capabilities.hover_provider = Some(provider);
12379 });
12380 notify_server_capabilities_updated(&server, cx);
12381 }
12382 "textDocument/signatureHelp" => {
12383 if let Some(caps) = reg
12384 .register_options
12385 .map(serde_json::from_value)
12386 .transpose()?
12387 {
12388 server.update_capabilities(|capabilities| {
12389 capabilities.signature_help_provider = Some(caps);
12390 });
12391 notify_server_capabilities_updated(&server, cx);
12392 }
12393 }
12394 "textDocument/didChange" => {
12395 if let Some(sync_kind) = reg
12396 .register_options
12397 .and_then(|opts| opts.get("syncKind").cloned())
12398 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12399 .transpose()?
12400 {
12401 server.update_capabilities(|capabilities| {
12402 let mut sync_options =
12403 Self::take_text_document_sync_options(capabilities);
12404 sync_options.change = Some(sync_kind);
12405 capabilities.text_document_sync =
12406 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12407 });
12408 notify_server_capabilities_updated(&server, cx);
12409 }
12410 }
12411 "textDocument/didSave" => {
12412 if let Some(include_text) = reg
12413 .register_options
12414 .map(|opts| {
12415 let transpose = opts
12416 .get("includeText")
12417 .cloned()
12418 .map(serde_json::from_value::<Option<bool>>)
12419 .transpose();
12420 match transpose {
12421 Ok(value) => Ok(value.flatten()),
12422 Err(e) => Err(e),
12423 }
12424 })
12425 .transpose()?
12426 {
12427 server.update_capabilities(|capabilities| {
12428 let mut sync_options =
12429 Self::take_text_document_sync_options(capabilities);
12430 sync_options.save =
12431 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12432 include_text,
12433 }));
12434 capabilities.text_document_sync =
12435 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12436 });
12437 notify_server_capabilities_updated(&server, cx);
12438 }
12439 }
12440 "textDocument/codeLens" => {
12441 if let Some(caps) = reg
12442 .register_options
12443 .map(serde_json::from_value)
12444 .transpose()?
12445 {
12446 server.update_capabilities(|capabilities| {
12447 capabilities.code_lens_provider = Some(caps);
12448 });
12449 notify_server_capabilities_updated(&server, cx);
12450 }
12451 }
12452 "textDocument/diagnostic" => {
12453 if let Some(caps) = reg
12454 .register_options
12455 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12456 .transpose()?
12457 {
12458 let local = self
12459 .as_local_mut()
12460 .context("Expected LSP Store to be local")?;
12461 let state = local
12462 .language_servers
12463 .get_mut(&server_id)
12464 .context("Could not obtain Language Servers state")?;
12465 local
12466 .language_server_dynamic_registrations
12467 .entry(server_id)
12468 .or_default()
12469 .diagnostics
12470 .insert(Some(reg.id.clone()), caps.clone());
12471
12472 let supports_workspace_diagnostics =
12473 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12474 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12475 diagnostic_options.workspace_diagnostics
12476 }
12477 DiagnosticServerCapabilities::RegistrationOptions(
12478 diagnostic_registration_options,
12479 ) => {
12480 diagnostic_registration_options
12481 .diagnostic_options
12482 .workspace_diagnostics
12483 }
12484 };
12485
12486 if supports_workspace_diagnostics(&caps) {
12487 if let LanguageServerState::Running {
12488 workspace_diagnostics_refresh_tasks,
12489 ..
12490 } = state
12491 && let Some(task) = lsp_workspace_diagnostics_refresh(
12492 Some(reg.id.clone()),
12493 caps.clone(),
12494 server.clone(),
12495 cx,
12496 )
12497 {
12498 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12499 }
12500 }
12501
12502 server.update_capabilities(|capabilities| {
12503 capabilities.diagnostic_provider = Some(caps);
12504 });
12505
12506 notify_server_capabilities_updated(&server, cx);
12507 }
12508 }
12509 "textDocument/documentColor" => {
12510 let options = parse_register_capabilities(reg)?;
12511 let provider = match options {
12512 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12513 OneOf::Right(caps) => caps,
12514 };
12515 server.update_capabilities(|capabilities| {
12516 capabilities.color_provider = Some(provider);
12517 });
12518 notify_server_capabilities_updated(&server, cx);
12519 }
12520 _ => log::warn!("unhandled capability registration: {reg:?}"),
12521 }
12522 }
12523
12524 Ok(())
12525 }
12526
12527 fn unregister_server_capabilities(
12528 &mut self,
12529 server_id: LanguageServerId,
12530 params: lsp::UnregistrationParams,
12531 cx: &mut Context<Self>,
12532 ) -> anyhow::Result<()> {
12533 let server = self
12534 .language_server_for_id(server_id)
12535 .with_context(|| format!("no server {server_id} found"))?;
12536 for unreg in params.unregisterations.iter() {
12537 match unreg.method.as_str() {
12538 "workspace/didChangeWatchedFiles" => {
12539 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12540 local_lsp_store
12541 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12542 true
12543 } else {
12544 false
12545 };
12546 if notify {
12547 notify_server_capabilities_updated(&server, cx);
12548 }
12549 }
12550 "workspace/didChangeConfiguration" => {
12551 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12552 }
12553 "workspace/didChangeWorkspaceFolders" => {
12554 server.update_capabilities(|capabilities| {
12555 capabilities
12556 .workspace
12557 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12558 workspace_folders: None,
12559 file_operations: None,
12560 })
12561 .workspace_folders = None;
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 "workspace/symbol" => {
12566 server.update_capabilities(|capabilities| {
12567 capabilities.workspace_symbol_provider = None
12568 });
12569 notify_server_capabilities_updated(&server, cx);
12570 }
12571 "workspace/fileOperations" => {
12572 server.update_capabilities(|capabilities| {
12573 capabilities
12574 .workspace
12575 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12576 workspace_folders: None,
12577 file_operations: None,
12578 })
12579 .file_operations = None;
12580 });
12581 notify_server_capabilities_updated(&server, cx);
12582 }
12583 "workspace/executeCommand" => {
12584 server.update_capabilities(|capabilities| {
12585 capabilities.execute_command_provider = None;
12586 });
12587 notify_server_capabilities_updated(&server, cx);
12588 }
12589 "textDocument/rangeFormatting" => {
12590 server.update_capabilities(|capabilities| {
12591 capabilities.document_range_formatting_provider = None
12592 });
12593 notify_server_capabilities_updated(&server, cx);
12594 }
12595 "textDocument/onTypeFormatting" => {
12596 server.update_capabilities(|capabilities| {
12597 capabilities.document_on_type_formatting_provider = None;
12598 });
12599 notify_server_capabilities_updated(&server, cx);
12600 }
12601 "textDocument/formatting" => {
12602 server.update_capabilities(|capabilities| {
12603 capabilities.document_formatting_provider = None;
12604 });
12605 notify_server_capabilities_updated(&server, cx);
12606 }
12607 "textDocument/rename" => {
12608 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12609 notify_server_capabilities_updated(&server, cx);
12610 }
12611 "textDocument/codeAction" => {
12612 server.update_capabilities(|capabilities| {
12613 capabilities.code_action_provider = None;
12614 });
12615 notify_server_capabilities_updated(&server, cx);
12616 }
12617 "textDocument/definition" => {
12618 server.update_capabilities(|capabilities| {
12619 capabilities.definition_provider = None;
12620 });
12621 notify_server_capabilities_updated(&server, cx);
12622 }
12623 "textDocument/completion" => {
12624 server.update_capabilities(|capabilities| {
12625 capabilities.completion_provider = None;
12626 });
12627 notify_server_capabilities_updated(&server, cx);
12628 }
12629 "textDocument/hover" => {
12630 server.update_capabilities(|capabilities| {
12631 capabilities.hover_provider = None;
12632 });
12633 notify_server_capabilities_updated(&server, cx);
12634 }
12635 "textDocument/signatureHelp" => {
12636 server.update_capabilities(|capabilities| {
12637 capabilities.signature_help_provider = None;
12638 });
12639 notify_server_capabilities_updated(&server, cx);
12640 }
12641 "textDocument/didChange" => {
12642 server.update_capabilities(|capabilities| {
12643 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12644 sync_options.change = None;
12645 capabilities.text_document_sync =
12646 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12647 });
12648 notify_server_capabilities_updated(&server, cx);
12649 }
12650 "textDocument/didSave" => {
12651 server.update_capabilities(|capabilities| {
12652 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12653 sync_options.save = None;
12654 capabilities.text_document_sync =
12655 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12656 });
12657 notify_server_capabilities_updated(&server, cx);
12658 }
12659 "textDocument/codeLens" => {
12660 server.update_capabilities(|capabilities| {
12661 capabilities.code_lens_provider = None;
12662 });
12663 notify_server_capabilities_updated(&server, cx);
12664 }
12665 "textDocument/diagnostic" => {
12666 let local = self
12667 .as_local_mut()
12668 .context("Expected LSP Store to be local")?;
12669
12670 let state = local
12671 .language_servers
12672 .get_mut(&server_id)
12673 .context("Could not obtain Language Servers state")?;
12674 let registrations = local
12675 .language_server_dynamic_registrations
12676 .get_mut(&server_id)
12677 .with_context(|| {
12678 format!("Expected dynamic registration to exist for server {server_id}")
12679 })?;
12680 registrations.diagnostics
12681 .remove(&Some(unreg.id.clone()))
12682 .with_context(|| format!(
12683 "Attempted to unregister non-existent diagnostic registration with ID {}",
12684 unreg.id)
12685 )?;
12686 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12687
12688 if let LanguageServerState::Running {
12689 workspace_diagnostics_refresh_tasks,
12690 ..
12691 } = state
12692 {
12693 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12694 }
12695
12696 if removed_last_diagnostic_provider {
12697 server.update_capabilities(|capabilities| {
12698 debug_assert!(capabilities.diagnostic_provider.is_some());
12699 capabilities.diagnostic_provider = None;
12700 });
12701 }
12702
12703 notify_server_capabilities_updated(&server, cx);
12704 }
12705 "textDocument/documentColor" => {
12706 server.update_capabilities(|capabilities| {
12707 capabilities.color_provider = None;
12708 });
12709 notify_server_capabilities_updated(&server, cx);
12710 }
12711 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12712 }
12713 }
12714
12715 Ok(())
12716 }
12717
12718 async fn deduplicate_range_based_lsp_requests<T>(
12719 lsp_store: &Entity<Self>,
12720 server_id: Option<LanguageServerId>,
12721 lsp_request_id: LspRequestId,
12722 proto_request: &T::ProtoRequest,
12723 range: Range<Anchor>,
12724 cx: &mut AsyncApp,
12725 ) -> Result<()>
12726 where
12727 T: LspCommand,
12728 T::ProtoRequest: proto::LspRequestMessage,
12729 {
12730 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12731 let version = deserialize_version(proto_request.buffer_version());
12732 let buffer = lsp_store.update(cx, |this, cx| {
12733 this.buffer_store.read(cx).get_existing(buffer_id)
12734 })??;
12735 buffer
12736 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12737 .await?;
12738 lsp_store.update(cx, |lsp_store, cx| {
12739 let buffer_snapshot = buffer.read(cx).snapshot();
12740 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12741 let chunks_queried_for = lsp_data
12742 .inlay_hints
12743 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12744 .collect::<Vec<_>>();
12745 match chunks_queried_for.as_slice() {
12746 &[chunk] => {
12747 let key = LspKey {
12748 request_type: TypeId::of::<T>(),
12749 server_queried: server_id,
12750 };
12751 let previous_request = lsp_data
12752 .chunk_lsp_requests
12753 .entry(key)
12754 .or_default()
12755 .insert(chunk, lsp_request_id);
12756 if let Some((previous_request, running_requests)) =
12757 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12758 {
12759 running_requests.remove(&previous_request);
12760 }
12761 }
12762 _ambiguous_chunks => {
12763 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12764 // there, a buffer version-based check will be performed and outdated requests discarded.
12765 }
12766 }
12767 anyhow::Ok(())
12768 })??;
12769
12770 Ok(())
12771 }
12772
12773 async fn query_lsp_locally<T>(
12774 lsp_store: Entity<Self>,
12775 for_server_id: Option<LanguageServerId>,
12776 sender_id: proto::PeerId,
12777 lsp_request_id: LspRequestId,
12778 proto_request: T::ProtoRequest,
12779 position: Option<Anchor>,
12780 cx: &mut AsyncApp,
12781 ) -> Result<()>
12782 where
12783 T: LspCommand + Clone,
12784 T::ProtoRequest: proto::LspRequestMessage,
12785 <T::ProtoRequest as proto::RequestMessage>::Response:
12786 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12787 {
12788 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12789 let version = deserialize_version(proto_request.buffer_version());
12790 let buffer = lsp_store.update(cx, |this, cx| {
12791 this.buffer_store.read(cx).get_existing(buffer_id)
12792 })??;
12793 buffer
12794 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12795 .await?;
12796 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12797 let request =
12798 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12799 let key = LspKey {
12800 request_type: TypeId::of::<T>(),
12801 server_queried: for_server_id,
12802 };
12803 lsp_store.update(cx, |lsp_store, cx| {
12804 let request_task = match for_server_id {
12805 Some(server_id) => {
12806 let server_task = lsp_store.request_lsp(
12807 buffer.clone(),
12808 LanguageServerToQuery::Other(server_id),
12809 request.clone(),
12810 cx,
12811 );
12812 cx.background_spawn(async move {
12813 let mut responses = Vec::new();
12814 match server_task.await {
12815 Ok(response) => responses.push((server_id, response)),
12816 // rust-analyzer likes to error with this when its still loading up
12817 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12818 Err(e) => log::error!(
12819 "Error handling response for request {request:?}: {e:#}"
12820 ),
12821 }
12822 responses
12823 })
12824 }
12825 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12826 };
12827 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12828 if T::ProtoRequest::stop_previous_requests() {
12829 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12830 lsp_requests.clear();
12831 }
12832 }
12833 lsp_data.lsp_requests.entry(key).or_default().insert(
12834 lsp_request_id,
12835 cx.spawn(async move |lsp_store, cx| {
12836 let response = request_task.await;
12837 lsp_store
12838 .update(cx, |lsp_store, cx| {
12839 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12840 {
12841 let response = response
12842 .into_iter()
12843 .map(|(server_id, response)| {
12844 (
12845 server_id.to_proto(),
12846 T::response_to_proto(
12847 response,
12848 lsp_store,
12849 sender_id,
12850 &buffer_version,
12851 cx,
12852 )
12853 .into(),
12854 )
12855 })
12856 .collect::<HashMap<_, _>>();
12857 match client.send_lsp_response::<T::ProtoRequest>(
12858 project_id,
12859 lsp_request_id,
12860 response,
12861 ) {
12862 Ok(()) => {}
12863 Err(e) => {
12864 log::error!("Failed to send LSP response: {e:#}",)
12865 }
12866 }
12867 }
12868 })
12869 .ok();
12870 }),
12871 );
12872 })?;
12873 Ok(())
12874 }
12875
12876 fn take_text_document_sync_options(
12877 capabilities: &mut lsp::ServerCapabilities,
12878 ) -> lsp::TextDocumentSyncOptions {
12879 match capabilities.text_document_sync.take() {
12880 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12881 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12882 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12883 sync_options.change = Some(sync_kind);
12884 sync_options
12885 }
12886 None => lsp::TextDocumentSyncOptions::default(),
12887 }
12888 }
12889
12890 #[cfg(any(test, feature = "test-support"))]
12891 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12892 Some(
12893 self.lsp_data
12894 .get_mut(&buffer_id)?
12895 .code_lens
12896 .take()?
12897 .update
12898 .take()?
12899 .1,
12900 )
12901 }
12902
12903 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12904 self.downstream_client.clone()
12905 }
12906
12907 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12908 self.worktree_store.clone()
12909 }
12910
12911 /// Gets what's stored in the LSP data for the given buffer.
12912 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12913 self.lsp_data.get_mut(&buffer_id)
12914 }
12915
12916 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12917 /// new [`BufferLspData`] will be created to replace the previous state.
12918 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12919 let (buffer_id, buffer_version) =
12920 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12921 let lsp_data = self
12922 .lsp_data
12923 .entry(buffer_id)
12924 .or_insert_with(|| BufferLspData::new(buffer, cx));
12925 if buffer_version.changed_since(&lsp_data.buffer_version) {
12926 *lsp_data = BufferLspData::new(buffer, cx);
12927 }
12928 lsp_data
12929 }
12930}
12931
12932// Registration with registerOptions as null, should fallback to true.
12933// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12934fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12935 reg: lsp::Registration,
12936) -> Result<OneOf<bool, T>> {
12937 Ok(match reg.register_options {
12938 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12939 None => OneOf::Left(true),
12940 })
12941}
12942
12943fn subscribe_to_binary_statuses(
12944 languages: &Arc<LanguageRegistry>,
12945 cx: &mut Context<'_, LspStore>,
12946) -> Task<()> {
12947 let mut server_statuses = languages.language_server_binary_statuses();
12948 cx.spawn(async move |lsp_store, cx| {
12949 while let Some((server_name, binary_status)) = server_statuses.next().await {
12950 if lsp_store
12951 .update(cx, |_, cx| {
12952 let mut message = None;
12953 let binary_status = match binary_status {
12954 BinaryStatus::None => proto::ServerBinaryStatus::None,
12955 BinaryStatus::CheckingForUpdate => {
12956 proto::ServerBinaryStatus::CheckingForUpdate
12957 }
12958 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12959 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12960 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12961 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12962 BinaryStatus::Failed { error } => {
12963 message = Some(error);
12964 proto::ServerBinaryStatus::Failed
12965 }
12966 };
12967 cx.emit(LspStoreEvent::LanguageServerUpdate {
12968 // Binary updates are about the binary that might not have any language server id at that point.
12969 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12970 language_server_id: LanguageServerId(0),
12971 name: Some(server_name),
12972 message: proto::update_language_server::Variant::StatusUpdate(
12973 proto::StatusUpdate {
12974 message,
12975 status: Some(proto::status_update::Status::Binary(
12976 binary_status as i32,
12977 )),
12978 },
12979 ),
12980 });
12981 })
12982 .is_err()
12983 {
12984 break;
12985 }
12986 }
12987 })
12988}
12989
12990fn lsp_workspace_diagnostics_refresh(
12991 registration_id: Option<String>,
12992 options: DiagnosticServerCapabilities,
12993 server: Arc<LanguageServer>,
12994 cx: &mut Context<'_, LspStore>,
12995) -> Option<WorkspaceRefreshTask> {
12996 let identifier = workspace_diagnostic_identifier(&options)?;
12997 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
12998
12999 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13000 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13001 refresh_tx.try_send(()).ok();
13002
13003 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13004 let mut attempts = 0;
13005 let max_attempts = 50;
13006 let mut requests = 0;
13007
13008 loop {
13009 let Some(()) = refresh_rx.recv().await else {
13010 return;
13011 };
13012
13013 'request: loop {
13014 requests += 1;
13015 if attempts > max_attempts {
13016 log::error!(
13017 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13018 );
13019 return;
13020 }
13021 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13022 cx.background_executor()
13023 .timer(Duration::from_millis(backoff_millis))
13024 .await;
13025 attempts += 1;
13026
13027 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13028 lsp_store
13029 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13030 .into_iter()
13031 .filter_map(|(abs_path, result_id)| {
13032 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13033 Some(lsp::PreviousResultId {
13034 uri,
13035 value: result_id.to_string(),
13036 })
13037 })
13038 .collect()
13039 }) else {
13040 return;
13041 };
13042
13043 let token = if let Some(registration_id) = ®istration_id {
13044 format!(
13045 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13046 server.server_id(),
13047 )
13048 } else {
13049 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13050 };
13051
13052 progress_rx.try_recv().ok();
13053 let timer =
13054 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13055 let progress = pin!(progress_rx.recv().fuse());
13056 let response_result = server
13057 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13058 lsp::WorkspaceDiagnosticParams {
13059 previous_result_ids,
13060 identifier: identifier.clone(),
13061 work_done_progress_params: Default::default(),
13062 partial_result_params: lsp::PartialResultParams {
13063 partial_result_token: Some(lsp::ProgressToken::String(token)),
13064 },
13065 },
13066 select(timer, progress).then(|either| match either {
13067 Either::Left((message, ..)) => ready(message).left_future(),
13068 Either::Right(..) => pending::<String>().right_future(),
13069 }),
13070 )
13071 .await;
13072
13073 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13074 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13075 match response_result {
13076 ConnectionResult::Timeout => {
13077 log::error!("Timeout during workspace diagnostics pull");
13078 continue 'request;
13079 }
13080 ConnectionResult::ConnectionReset => {
13081 log::error!("Server closed a workspace diagnostics pull request");
13082 continue 'request;
13083 }
13084 ConnectionResult::Result(Err(e)) => {
13085 log::error!("Error during workspace diagnostics pull: {e:#}");
13086 break 'request;
13087 }
13088 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13089 attempts = 0;
13090 if lsp_store
13091 .update(cx, |lsp_store, cx| {
13092 lsp_store.apply_workspace_diagnostic_report(
13093 server.server_id(),
13094 pulled_diagnostics,
13095 registration_id_shared.clone(),
13096 cx,
13097 )
13098 })
13099 .is_err()
13100 {
13101 return;
13102 }
13103 break 'request;
13104 }
13105 }
13106 }
13107 }
13108 });
13109
13110 Some(WorkspaceRefreshTask {
13111 refresh_tx,
13112 progress_tx,
13113 task: workspace_query_language_server,
13114 })
13115}
13116
13117fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13118 match &options {
13119 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13120 diagnostic_options.identifier.clone()
13121 }
13122 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13123 let diagnostic_options = ®istration_options.diagnostic_options;
13124 diagnostic_options.identifier.clone()
13125 }
13126 }
13127}
13128
13129fn workspace_diagnostic_identifier(
13130 options: &DiagnosticServerCapabilities,
13131) -> Option<Option<String>> {
13132 match &options {
13133 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13134 if !diagnostic_options.workspace_diagnostics {
13135 return None;
13136 }
13137 Some(diagnostic_options.identifier.clone())
13138 }
13139 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13140 let diagnostic_options = ®istration_options.diagnostic_options;
13141 if !diagnostic_options.workspace_diagnostics {
13142 return None;
13143 }
13144 Some(diagnostic_options.identifier.clone())
13145 }
13146 }
13147}
13148
13149fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13150 let CompletionSource::BufferWord {
13151 word_range,
13152 resolved,
13153 } = &mut completion.source
13154 else {
13155 return;
13156 };
13157 if *resolved {
13158 return;
13159 }
13160
13161 if completion.new_text
13162 != snapshot
13163 .text_for_range(word_range.clone())
13164 .collect::<String>()
13165 {
13166 return;
13167 }
13168
13169 let mut offset = 0;
13170 for chunk in snapshot.chunks(word_range.clone(), true) {
13171 let end_offset = offset + chunk.text.len();
13172 if let Some(highlight_id) = chunk.syntax_highlight_id {
13173 completion
13174 .label
13175 .runs
13176 .push((offset..end_offset, highlight_id));
13177 }
13178 offset = end_offset;
13179 }
13180 *resolved = true;
13181}
13182
13183impl EventEmitter<LspStoreEvent> for LspStore {}
13184
13185fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13186 hover
13187 .contents
13188 .retain(|hover_block| !hover_block.text.trim().is_empty());
13189 if hover.contents.is_empty() {
13190 None
13191 } else {
13192 Some(hover)
13193 }
13194}
13195
13196async fn populate_labels_for_completions(
13197 new_completions: Vec<CoreCompletion>,
13198 language: Option<Arc<Language>>,
13199 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13200) -> Vec<Completion> {
13201 let lsp_completions = new_completions
13202 .iter()
13203 .filter_map(|new_completion| {
13204 new_completion
13205 .source
13206 .lsp_completion(true)
13207 .map(|lsp_completion| lsp_completion.into_owned())
13208 })
13209 .collect::<Vec<_>>();
13210
13211 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13212 lsp_adapter
13213 .labels_for_completions(&lsp_completions, language)
13214 .await
13215 .log_err()
13216 .unwrap_or_default()
13217 } else {
13218 Vec::new()
13219 }
13220 .into_iter()
13221 .fuse();
13222
13223 let mut completions = Vec::new();
13224 for completion in new_completions {
13225 match completion.source.lsp_completion(true) {
13226 Some(lsp_completion) => {
13227 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13228
13229 let mut label = labels.next().flatten().unwrap_or_else(|| {
13230 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13231 });
13232 ensure_uniform_list_compatible_label(&mut label);
13233 completions.push(Completion {
13234 label,
13235 documentation,
13236 replace_range: completion.replace_range,
13237 new_text: completion.new_text,
13238 insert_text_mode: lsp_completion.insert_text_mode,
13239 source: completion.source,
13240 icon_path: None,
13241 confirm: None,
13242 match_start: None,
13243 snippet_deduplication_key: None,
13244 });
13245 }
13246 None => {
13247 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13248 ensure_uniform_list_compatible_label(&mut label);
13249 completions.push(Completion {
13250 label,
13251 documentation: None,
13252 replace_range: completion.replace_range,
13253 new_text: completion.new_text,
13254 source: completion.source,
13255 insert_text_mode: None,
13256 icon_path: None,
13257 confirm: None,
13258 match_start: None,
13259 snippet_deduplication_key: None,
13260 });
13261 }
13262 }
13263 }
13264 completions
13265}
13266
13267#[derive(Debug)]
13268pub enum LanguageServerToQuery {
13269 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13270 FirstCapable,
13271 /// Query a specific language server.
13272 Other(LanguageServerId),
13273}
13274
13275#[derive(Default)]
13276struct RenamePathsWatchedForServer {
13277 did_rename: Vec<RenameActionPredicate>,
13278 will_rename: Vec<RenameActionPredicate>,
13279}
13280
13281impl RenamePathsWatchedForServer {
13282 fn with_did_rename_patterns(
13283 mut self,
13284 did_rename: Option<&FileOperationRegistrationOptions>,
13285 ) -> Self {
13286 if let Some(did_rename) = did_rename {
13287 self.did_rename = did_rename
13288 .filters
13289 .iter()
13290 .filter_map(|filter| filter.try_into().log_err())
13291 .collect();
13292 }
13293 self
13294 }
13295 fn with_will_rename_patterns(
13296 mut self,
13297 will_rename: Option<&FileOperationRegistrationOptions>,
13298 ) -> Self {
13299 if let Some(will_rename) = will_rename {
13300 self.will_rename = will_rename
13301 .filters
13302 .iter()
13303 .filter_map(|filter| filter.try_into().log_err())
13304 .collect();
13305 }
13306 self
13307 }
13308
13309 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13310 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13311 }
13312 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13313 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13314 }
13315}
13316
13317impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13318 type Error = globset::Error;
13319 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13320 Ok(Self {
13321 kind: ops.pattern.matches.clone(),
13322 glob: GlobBuilder::new(&ops.pattern.glob)
13323 .case_insensitive(
13324 ops.pattern
13325 .options
13326 .as_ref()
13327 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13328 )
13329 .build()?
13330 .compile_matcher(),
13331 })
13332 }
13333}
13334struct RenameActionPredicate {
13335 glob: GlobMatcher,
13336 kind: Option<FileOperationPatternKind>,
13337}
13338
13339impl RenameActionPredicate {
13340 // Returns true if language server should be notified
13341 fn eval(&self, path: &str, is_dir: bool) -> bool {
13342 self.kind.as_ref().is_none_or(|kind| {
13343 let expected_kind = if is_dir {
13344 FileOperationPatternKind::Folder
13345 } else {
13346 FileOperationPatternKind::File
13347 };
13348 kind == &expected_kind
13349 }) && self.glob.is_match(path)
13350 }
13351}
13352
13353#[derive(Default)]
13354struct LanguageServerWatchedPaths {
13355 worktree_paths: HashMap<WorktreeId, GlobSet>,
13356 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13357}
13358
13359#[derive(Default)]
13360struct LanguageServerWatchedPathsBuilder {
13361 worktree_paths: HashMap<WorktreeId, GlobSet>,
13362 abs_paths: HashMap<Arc<Path>, GlobSet>,
13363}
13364
13365impl LanguageServerWatchedPathsBuilder {
13366 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13367 self.worktree_paths.insert(worktree_id, glob_set);
13368 }
13369 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13370 self.abs_paths.insert(path, glob_set);
13371 }
13372 fn build(
13373 self,
13374 fs: Arc<dyn Fs>,
13375 language_server_id: LanguageServerId,
13376 cx: &mut Context<LspStore>,
13377 ) -> LanguageServerWatchedPaths {
13378 let lsp_store = cx.weak_entity();
13379
13380 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13381 let abs_paths = self
13382 .abs_paths
13383 .into_iter()
13384 .map(|(abs_path, globset)| {
13385 let task = cx.spawn({
13386 let abs_path = abs_path.clone();
13387 let fs = fs.clone();
13388
13389 let lsp_store = lsp_store.clone();
13390 async move |_, cx| {
13391 maybe!(async move {
13392 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13393 while let Some(update) = push_updates.0.next().await {
13394 let action = lsp_store
13395 .update(cx, |this, _| {
13396 let Some(local) = this.as_local() else {
13397 return ControlFlow::Break(());
13398 };
13399 let Some(watcher) = local
13400 .language_server_watched_paths
13401 .get(&language_server_id)
13402 else {
13403 return ControlFlow::Break(());
13404 };
13405 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13406 "Watched abs path is not registered with a watcher",
13407 );
13408 let matching_entries = update
13409 .into_iter()
13410 .filter(|event| globs.is_match(&event.path))
13411 .collect::<Vec<_>>();
13412 this.lsp_notify_abs_paths_changed(
13413 language_server_id,
13414 matching_entries,
13415 );
13416 ControlFlow::Continue(())
13417 })
13418 .ok()?;
13419
13420 if action.is_break() {
13421 break;
13422 }
13423 }
13424 Some(())
13425 })
13426 .await;
13427 }
13428 });
13429 (abs_path, (globset, task))
13430 })
13431 .collect();
13432 LanguageServerWatchedPaths {
13433 worktree_paths: self.worktree_paths,
13434 abs_paths,
13435 }
13436 }
13437}
13438
13439struct LspBufferSnapshot {
13440 version: i32,
13441 snapshot: TextBufferSnapshot,
13442}
13443
13444/// A prompt requested by LSP server.
13445#[derive(Clone, Debug)]
13446pub struct LanguageServerPromptRequest {
13447 pub level: PromptLevel,
13448 pub message: String,
13449 pub actions: Vec<MessageActionItem>,
13450 pub lsp_name: String,
13451 pub(crate) response_channel: Sender<MessageActionItem>,
13452}
13453
13454impl LanguageServerPromptRequest {
13455 pub async fn respond(self, index: usize) -> Option<()> {
13456 if let Some(response) = self.actions.into_iter().nth(index) {
13457 self.response_channel.send(response).await.ok()
13458 } else {
13459 None
13460 }
13461 }
13462}
13463impl PartialEq for LanguageServerPromptRequest {
13464 fn eq(&self, other: &Self) -> bool {
13465 self.message == other.message && self.actions == other.actions
13466 }
13467}
13468
13469#[derive(Clone, Debug, PartialEq)]
13470pub enum LanguageServerLogType {
13471 Log(MessageType),
13472 Trace { verbose_info: Option<String> },
13473 Rpc { received: bool },
13474}
13475
13476impl LanguageServerLogType {
13477 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13478 match self {
13479 Self::Log(log_type) => {
13480 use proto::log_message::LogLevel;
13481 let level = match *log_type {
13482 MessageType::ERROR => LogLevel::Error,
13483 MessageType::WARNING => LogLevel::Warning,
13484 MessageType::INFO => LogLevel::Info,
13485 MessageType::LOG => LogLevel::Log,
13486 other => {
13487 log::warn!("Unknown lsp log message type: {other:?}");
13488 LogLevel::Log
13489 }
13490 };
13491 proto::language_server_log::LogType::Log(proto::LogMessage {
13492 level: level as i32,
13493 })
13494 }
13495 Self::Trace { verbose_info } => {
13496 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13497 verbose_info: verbose_info.to_owned(),
13498 })
13499 }
13500 Self::Rpc { received } => {
13501 let kind = if *received {
13502 proto::rpc_message::Kind::Received
13503 } else {
13504 proto::rpc_message::Kind::Sent
13505 };
13506 let kind = kind as i32;
13507 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13508 }
13509 }
13510 }
13511
13512 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13513 use proto::log_message::LogLevel;
13514 use proto::rpc_message;
13515 match log_type {
13516 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13517 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13518 LogLevel::Error => MessageType::ERROR,
13519 LogLevel::Warning => MessageType::WARNING,
13520 LogLevel::Info => MessageType::INFO,
13521 LogLevel::Log => MessageType::LOG,
13522 },
13523 ),
13524 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13525 verbose_info: trace_message.verbose_info,
13526 },
13527 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13528 received: match rpc_message::Kind::from_i32(message.kind)
13529 .unwrap_or(rpc_message::Kind::Received)
13530 {
13531 rpc_message::Kind::Received => true,
13532 rpc_message::Kind::Sent => false,
13533 },
13534 },
13535 }
13536 }
13537}
13538
13539pub struct WorkspaceRefreshTask {
13540 refresh_tx: mpsc::Sender<()>,
13541 progress_tx: mpsc::Sender<()>,
13542 #[allow(dead_code)]
13543 task: Task<()>,
13544}
13545
13546pub enum LanguageServerState {
13547 Starting {
13548 startup: Task<Option<Arc<LanguageServer>>>,
13549 /// List of language servers that will be added to the workspace once it's initialization completes.
13550 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13551 },
13552
13553 Running {
13554 adapter: Arc<CachedLspAdapter>,
13555 server: Arc<LanguageServer>,
13556 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13557 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13558 },
13559}
13560
13561impl LanguageServerState {
13562 fn add_workspace_folder(&self, uri: Uri) {
13563 match self {
13564 LanguageServerState::Starting {
13565 pending_workspace_folders,
13566 ..
13567 } => {
13568 pending_workspace_folders.lock().insert(uri);
13569 }
13570 LanguageServerState::Running { server, .. } => {
13571 server.add_workspace_folder(uri);
13572 }
13573 }
13574 }
13575 fn _remove_workspace_folder(&self, uri: Uri) {
13576 match self {
13577 LanguageServerState::Starting {
13578 pending_workspace_folders,
13579 ..
13580 } => {
13581 pending_workspace_folders.lock().remove(&uri);
13582 }
13583 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13584 }
13585 }
13586}
13587
13588impl std::fmt::Debug for LanguageServerState {
13589 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13590 match self {
13591 LanguageServerState::Starting { .. } => {
13592 f.debug_struct("LanguageServerState::Starting").finish()
13593 }
13594 LanguageServerState::Running { .. } => {
13595 f.debug_struct("LanguageServerState::Running").finish()
13596 }
13597 }
13598 }
13599}
13600
13601#[derive(Clone, Debug, Serialize)]
13602pub struct LanguageServerProgress {
13603 pub is_disk_based_diagnostics_progress: bool,
13604 pub is_cancellable: bool,
13605 pub title: Option<String>,
13606 pub message: Option<String>,
13607 pub percentage: Option<usize>,
13608 #[serde(skip_serializing)]
13609 pub last_update_at: Instant,
13610}
13611
13612#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13613pub struct DiagnosticSummary {
13614 pub error_count: usize,
13615 pub warning_count: usize,
13616}
13617
13618impl DiagnosticSummary {
13619 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13620 let mut this = Self {
13621 error_count: 0,
13622 warning_count: 0,
13623 };
13624
13625 for entry in diagnostics {
13626 if entry.diagnostic.is_primary {
13627 match entry.diagnostic.severity {
13628 DiagnosticSeverity::ERROR => this.error_count += 1,
13629 DiagnosticSeverity::WARNING => this.warning_count += 1,
13630 _ => {}
13631 }
13632 }
13633 }
13634
13635 this
13636 }
13637
13638 pub fn is_empty(&self) -> bool {
13639 self.error_count == 0 && self.warning_count == 0
13640 }
13641
13642 pub fn to_proto(
13643 self,
13644 language_server_id: LanguageServerId,
13645 path: &RelPath,
13646 ) -> proto::DiagnosticSummary {
13647 proto::DiagnosticSummary {
13648 path: path.to_proto(),
13649 language_server_id: language_server_id.0 as u64,
13650 error_count: self.error_count as u32,
13651 warning_count: self.warning_count as u32,
13652 }
13653 }
13654}
13655
13656#[derive(Clone, Debug)]
13657pub enum CompletionDocumentation {
13658 /// There is no documentation for this completion.
13659 Undocumented,
13660 /// A single line of documentation.
13661 SingleLine(SharedString),
13662 /// Multiple lines of plain text documentation.
13663 MultiLinePlainText(SharedString),
13664 /// Markdown documentation.
13665 MultiLineMarkdown(SharedString),
13666 /// Both single line and multiple lines of plain text documentation.
13667 SingleLineAndMultiLinePlainText {
13668 single_line: SharedString,
13669 plain_text: Option<SharedString>,
13670 },
13671}
13672
13673impl CompletionDocumentation {
13674 #[cfg(any(test, feature = "test-support"))]
13675 pub fn text(&self) -> SharedString {
13676 match self {
13677 CompletionDocumentation::Undocumented => "".into(),
13678 CompletionDocumentation::SingleLine(s) => s.clone(),
13679 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13680 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13681 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13682 single_line.clone()
13683 }
13684 }
13685 }
13686}
13687
13688impl From<lsp::Documentation> for CompletionDocumentation {
13689 fn from(docs: lsp::Documentation) -> Self {
13690 match docs {
13691 lsp::Documentation::String(text) => {
13692 if text.lines().count() <= 1 {
13693 CompletionDocumentation::SingleLine(text.into())
13694 } else {
13695 CompletionDocumentation::MultiLinePlainText(text.into())
13696 }
13697 }
13698
13699 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13700 lsp::MarkupKind::PlainText => {
13701 if value.lines().count() <= 1 {
13702 CompletionDocumentation::SingleLine(value.into())
13703 } else {
13704 CompletionDocumentation::MultiLinePlainText(value.into())
13705 }
13706 }
13707
13708 lsp::MarkupKind::Markdown => {
13709 CompletionDocumentation::MultiLineMarkdown(value.into())
13710 }
13711 },
13712 }
13713 }
13714}
13715
13716pub enum ResolvedHint {
13717 Resolved(InlayHint),
13718 Resolving(Shared<Task<()>>),
13719}
13720
13721fn glob_literal_prefix(glob: &Path) -> PathBuf {
13722 glob.components()
13723 .take_while(|component| match component {
13724 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13725 _ => true,
13726 })
13727 .collect()
13728}
13729
13730pub struct SshLspAdapter {
13731 name: LanguageServerName,
13732 binary: LanguageServerBinary,
13733 initialization_options: Option<String>,
13734 code_action_kinds: Option<Vec<CodeActionKind>>,
13735}
13736
13737impl SshLspAdapter {
13738 pub fn new(
13739 name: LanguageServerName,
13740 binary: LanguageServerBinary,
13741 initialization_options: Option<String>,
13742 code_action_kinds: Option<String>,
13743 ) -> Self {
13744 Self {
13745 name,
13746 binary,
13747 initialization_options,
13748 code_action_kinds: code_action_kinds
13749 .as_ref()
13750 .and_then(|c| serde_json::from_str(c).ok()),
13751 }
13752 }
13753}
13754
13755impl LspInstaller for SshLspAdapter {
13756 type BinaryVersion = ();
13757 async fn check_if_user_installed(
13758 &self,
13759 _: &dyn LspAdapterDelegate,
13760 _: Option<Toolchain>,
13761 _: &AsyncApp,
13762 ) -> Option<LanguageServerBinary> {
13763 Some(self.binary.clone())
13764 }
13765
13766 async fn cached_server_binary(
13767 &self,
13768 _: PathBuf,
13769 _: &dyn LspAdapterDelegate,
13770 ) -> Option<LanguageServerBinary> {
13771 None
13772 }
13773
13774 async fn fetch_latest_server_version(
13775 &self,
13776 _: &dyn LspAdapterDelegate,
13777 _: bool,
13778 _: &mut AsyncApp,
13779 ) -> Result<()> {
13780 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13781 }
13782
13783 async fn fetch_server_binary(
13784 &self,
13785 _: (),
13786 _: PathBuf,
13787 _: &dyn LspAdapterDelegate,
13788 ) -> Result<LanguageServerBinary> {
13789 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13790 }
13791}
13792
13793#[async_trait(?Send)]
13794impl LspAdapter for SshLspAdapter {
13795 fn name(&self) -> LanguageServerName {
13796 self.name.clone()
13797 }
13798
13799 async fn initialization_options(
13800 self: Arc<Self>,
13801 _: &Arc<dyn LspAdapterDelegate>,
13802 ) -> Result<Option<serde_json::Value>> {
13803 let Some(options) = &self.initialization_options else {
13804 return Ok(None);
13805 };
13806 let result = serde_json::from_str(options)?;
13807 Ok(result)
13808 }
13809
13810 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13811 self.code_action_kinds.clone()
13812 }
13813}
13814
13815pub fn language_server_settings<'a>(
13816 delegate: &'a dyn LspAdapterDelegate,
13817 language: &LanguageServerName,
13818 cx: &'a App,
13819) -> Option<&'a LspSettings> {
13820 language_server_settings_for(
13821 SettingsLocation {
13822 worktree_id: delegate.worktree_id(),
13823 path: RelPath::empty(),
13824 },
13825 language,
13826 cx,
13827 )
13828}
13829
13830pub fn language_server_settings_for<'a>(
13831 location: SettingsLocation<'a>,
13832 language: &LanguageServerName,
13833 cx: &'a App,
13834) -> Option<&'a LspSettings> {
13835 ProjectSettings::get(Some(location), cx).lsp.get(language)
13836}
13837
13838pub struct LocalLspAdapterDelegate {
13839 lsp_store: WeakEntity<LspStore>,
13840 worktree: worktree::Snapshot,
13841 fs: Arc<dyn Fs>,
13842 http_client: Arc<dyn HttpClient>,
13843 language_registry: Arc<LanguageRegistry>,
13844 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13845}
13846
13847impl LocalLspAdapterDelegate {
13848 pub fn new(
13849 language_registry: Arc<LanguageRegistry>,
13850 environment: &Entity<ProjectEnvironment>,
13851 lsp_store: WeakEntity<LspStore>,
13852 worktree: &Entity<Worktree>,
13853 http_client: Arc<dyn HttpClient>,
13854 fs: Arc<dyn Fs>,
13855 cx: &mut App,
13856 ) -> Arc<Self> {
13857 let load_shell_env_task =
13858 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13859
13860 Arc::new(Self {
13861 lsp_store,
13862 worktree: worktree.read(cx).snapshot(),
13863 fs,
13864 http_client,
13865 language_registry,
13866 load_shell_env_task,
13867 })
13868 }
13869
13870 fn from_local_lsp(
13871 local: &LocalLspStore,
13872 worktree: &Entity<Worktree>,
13873 cx: &mut App,
13874 ) -> Arc<Self> {
13875 Self::new(
13876 local.languages.clone(),
13877 &local.environment,
13878 local.weak.clone(),
13879 worktree,
13880 local.http_client.clone(),
13881 local.fs.clone(),
13882 cx,
13883 )
13884 }
13885}
13886
13887#[async_trait]
13888impl LspAdapterDelegate for LocalLspAdapterDelegate {
13889 fn show_notification(&self, message: &str, cx: &mut App) {
13890 self.lsp_store
13891 .update(cx, |_, cx| {
13892 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13893 })
13894 .ok();
13895 }
13896
13897 fn http_client(&self) -> Arc<dyn HttpClient> {
13898 self.http_client.clone()
13899 }
13900
13901 fn worktree_id(&self) -> WorktreeId {
13902 self.worktree.id()
13903 }
13904
13905 fn worktree_root_path(&self) -> &Path {
13906 self.worktree.abs_path().as_ref()
13907 }
13908
13909 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13910 self.worktree.resolve_executable_path(path)
13911 }
13912
13913 async fn shell_env(&self) -> HashMap<String, String> {
13914 let task = self.load_shell_env_task.clone();
13915 task.await.unwrap_or_default()
13916 }
13917
13918 async fn npm_package_installed_version(
13919 &self,
13920 package_name: &str,
13921 ) -> Result<Option<(PathBuf, String)>> {
13922 let local_package_directory = self.worktree_root_path();
13923 let node_modules_directory = local_package_directory.join("node_modules");
13924
13925 if let Some(version) =
13926 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13927 {
13928 return Ok(Some((node_modules_directory, version)));
13929 }
13930 let Some(npm) = self.which("npm".as_ref()).await else {
13931 log::warn!(
13932 "Failed to find npm executable for {:?}",
13933 local_package_directory
13934 );
13935 return Ok(None);
13936 };
13937
13938 let env = self.shell_env().await;
13939 let output = util::command::new_smol_command(&npm)
13940 .args(["root", "-g"])
13941 .envs(env)
13942 .current_dir(local_package_directory)
13943 .output()
13944 .await?;
13945 let global_node_modules =
13946 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13947
13948 if let Some(version) =
13949 read_package_installed_version(global_node_modules.clone(), package_name).await?
13950 {
13951 return Ok(Some((global_node_modules, version)));
13952 }
13953 return Ok(None);
13954 }
13955
13956 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13957 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13958 if self.fs.is_file(&worktree_abs_path).await {
13959 worktree_abs_path.pop();
13960 }
13961
13962 let env = self.shell_env().await;
13963
13964 let shell_path = env.get("PATH").cloned();
13965
13966 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13967 }
13968
13969 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13970 let mut working_dir = self.worktree_root_path().to_path_buf();
13971 if self.fs.is_file(&working_dir).await {
13972 working_dir.pop();
13973 }
13974 let output = util::command::new_smol_command(&command.path)
13975 .args(command.arguments)
13976 .envs(command.env.clone().unwrap_or_default())
13977 .current_dir(working_dir)
13978 .output()
13979 .await?;
13980
13981 anyhow::ensure!(
13982 output.status.success(),
13983 "{}, stdout: {:?}, stderr: {:?}",
13984 output.status,
13985 String::from_utf8_lossy(&output.stdout),
13986 String::from_utf8_lossy(&output.stderr)
13987 );
13988 Ok(())
13989 }
13990
13991 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13992 self.language_registry
13993 .update_lsp_binary_status(server_name, status);
13994 }
13995
13996 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13997 self.language_registry
13998 .all_lsp_adapters()
13999 .into_iter()
14000 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14001 .collect()
14002 }
14003
14004 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14005 let dir = self.language_registry.language_server_download_dir(name)?;
14006
14007 if !dir.exists() {
14008 smol::fs::create_dir_all(&dir)
14009 .await
14010 .context("failed to create container directory")
14011 .log_err()?;
14012 }
14013
14014 Some(dir)
14015 }
14016
14017 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14018 let entry = self
14019 .worktree
14020 .entry_for_path(path)
14021 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14022 let abs_path = self.worktree.absolutize(&entry.path);
14023 self.fs.load(&abs_path).await
14024 }
14025}
14026
14027async fn populate_labels_for_symbols(
14028 symbols: Vec<CoreSymbol>,
14029 language_registry: &Arc<LanguageRegistry>,
14030 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14031 output: &mut Vec<Symbol>,
14032) {
14033 #[allow(clippy::mutable_key_type)]
14034 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14035
14036 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14037 for symbol in symbols {
14038 let Some(file_name) = symbol.path.file_name() else {
14039 continue;
14040 };
14041 let language = language_registry
14042 .load_language_for_file_path(Path::new(file_name))
14043 .await
14044 .ok()
14045 .or_else(|| {
14046 unknown_paths.insert(file_name.into());
14047 None
14048 });
14049 symbols_by_language
14050 .entry(language)
14051 .or_default()
14052 .push(symbol);
14053 }
14054
14055 for unknown_path in unknown_paths {
14056 log::info!("no language found for symbol in file {unknown_path:?}");
14057 }
14058
14059 let mut label_params = Vec::new();
14060 for (language, mut symbols) in symbols_by_language {
14061 label_params.clear();
14062 label_params.extend(
14063 symbols
14064 .iter_mut()
14065 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14066 );
14067
14068 let mut labels = Vec::new();
14069 if let Some(language) = language {
14070 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14071 language_registry
14072 .lsp_adapters(&language.name())
14073 .first()
14074 .cloned()
14075 });
14076 if let Some(lsp_adapter) = lsp_adapter {
14077 labels = lsp_adapter
14078 .labels_for_symbols(&label_params, &language)
14079 .await
14080 .log_err()
14081 .unwrap_or_default();
14082 }
14083 }
14084
14085 for ((symbol, (name, _)), label) in symbols
14086 .into_iter()
14087 .zip(label_params.drain(..))
14088 .zip(labels.into_iter().chain(iter::repeat(None)))
14089 {
14090 output.push(Symbol {
14091 language_server_name: symbol.language_server_name,
14092 source_worktree_id: symbol.source_worktree_id,
14093 source_language_server_id: symbol.source_language_server_id,
14094 path: symbol.path,
14095 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14096 name,
14097 kind: symbol.kind,
14098 range: symbol.range,
14099 });
14100 }
14101 }
14102}
14103
14104fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14105 match server.capabilities().text_document_sync.as_ref()? {
14106 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14107 // Server wants didSave but didn't specify includeText.
14108 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14109 // Server doesn't want didSave at all.
14110 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14111 // Server provided SaveOptions.
14112 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14113 Some(save_options.include_text.unwrap_or(false))
14114 }
14115 },
14116 // We do not have any save info. Kind affects didChange only.
14117 lsp::TextDocumentSyncCapability::Kind(_) => None,
14118 }
14119}
14120
14121/// Completion items are displayed in a `UniformList`.
14122/// Usually, those items are single-line strings, but in LSP responses,
14123/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14124/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14125/// 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,
14126/// breaking the completions menu presentation.
14127///
14128/// 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.
14129fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14130 let mut new_text = String::with_capacity(label.text.len());
14131 let mut offset_map = vec![0; label.text.len() + 1];
14132 let mut last_char_was_space = false;
14133 let mut new_idx = 0;
14134 let chars = label.text.char_indices().fuse();
14135 let mut newlines_removed = false;
14136
14137 for (idx, c) in chars {
14138 offset_map[idx] = new_idx;
14139
14140 match c {
14141 '\n' if last_char_was_space => {
14142 newlines_removed = true;
14143 }
14144 '\t' | ' ' if last_char_was_space => {}
14145 '\n' if !last_char_was_space => {
14146 new_text.push(' ');
14147 new_idx += 1;
14148 last_char_was_space = true;
14149 newlines_removed = true;
14150 }
14151 ' ' | '\t' => {
14152 new_text.push(' ');
14153 new_idx += 1;
14154 last_char_was_space = true;
14155 }
14156 _ => {
14157 new_text.push(c);
14158 new_idx += c.len_utf8();
14159 last_char_was_space = false;
14160 }
14161 }
14162 }
14163 offset_map[label.text.len()] = new_idx;
14164
14165 // Only modify the label if newlines were removed.
14166 if !newlines_removed {
14167 return;
14168 }
14169
14170 let last_index = new_idx;
14171 let mut run_ranges_errors = Vec::new();
14172 label.runs.retain_mut(|(range, _)| {
14173 match offset_map.get(range.start) {
14174 Some(&start) => range.start = start,
14175 None => {
14176 run_ranges_errors.push(range.clone());
14177 return false;
14178 }
14179 }
14180
14181 match offset_map.get(range.end) {
14182 Some(&end) => range.end = end,
14183 None => {
14184 run_ranges_errors.push(range.clone());
14185 range.end = last_index;
14186 }
14187 }
14188 true
14189 });
14190 if !run_ranges_errors.is_empty() {
14191 log::error!(
14192 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14193 label.text
14194 );
14195 }
14196
14197 let mut wrong_filter_range = None;
14198 if label.filter_range == (0..label.text.len()) {
14199 label.filter_range = 0..new_text.len();
14200 } else {
14201 let mut original_filter_range = Some(label.filter_range.clone());
14202 match offset_map.get(label.filter_range.start) {
14203 Some(&start) => label.filter_range.start = start,
14204 None => {
14205 wrong_filter_range = original_filter_range.take();
14206 label.filter_range.start = last_index;
14207 }
14208 }
14209
14210 match offset_map.get(label.filter_range.end) {
14211 Some(&end) => label.filter_range.end = end,
14212 None => {
14213 wrong_filter_range = original_filter_range.take();
14214 label.filter_range.end = last_index;
14215 }
14216 }
14217 }
14218 if let Some(wrong_filter_range) = wrong_filter_range {
14219 log::error!(
14220 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14221 label.text
14222 );
14223 }
14224
14225 label.text = new_text;
14226}
14227
14228#[cfg(test)]
14229mod tests {
14230 use language::HighlightId;
14231
14232 use super::*;
14233
14234 #[test]
14235 fn test_glob_literal_prefix() {
14236 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14237 assert_eq!(
14238 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14239 Path::new("node_modules")
14240 );
14241 assert_eq!(
14242 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14243 Path::new("foo")
14244 );
14245 assert_eq!(
14246 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14247 Path::new("foo/bar/baz.js")
14248 );
14249
14250 #[cfg(target_os = "windows")]
14251 {
14252 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14253 assert_eq!(
14254 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14255 Path::new("node_modules")
14256 );
14257 assert_eq!(
14258 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14259 Path::new("foo")
14260 );
14261 assert_eq!(
14262 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14263 Path::new("foo/bar/baz.js")
14264 );
14265 }
14266 }
14267
14268 #[test]
14269 fn test_multi_len_chars_normalization() {
14270 let mut label = CodeLabel::new(
14271 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14272 0..6,
14273 vec![(0..6, HighlightId(1))],
14274 );
14275 ensure_uniform_list_compatible_label(&mut label);
14276 assert_eq!(
14277 label,
14278 CodeLabel::new(
14279 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14280 0..6,
14281 vec![(0..6, HighlightId(1))],
14282 )
14283 );
14284 }
14285}