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 settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
143
144#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
145pub enum ProgressToken {
146 Number(i32),
147 String(SharedString),
148}
149
150impl std::fmt::Display for ProgressToken {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 match self {
153 Self::Number(number) => write!(f, "{number}"),
154 Self::String(string) => write!(f, "{string}"),
155 }
156 }
157}
158
159impl ProgressToken {
160 fn from_lsp(value: lsp::NumberOrString) -> Self {
161 match value {
162 lsp::NumberOrString::Number(number) => Self::Number(number),
163 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
164 }
165 }
166
167 fn to_lsp(&self) -> lsp::NumberOrString {
168 match self {
169 Self::Number(number) => lsp::NumberOrString::Number(*number),
170 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
171 }
172 }
173
174 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
175 Some(match value.value? {
176 proto::progress_token::Value::Number(number) => Self::Number(number),
177 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
178 })
179 }
180
181 fn to_proto(&self) -> proto::ProgressToken {
182 proto::ProgressToken {
183 value: Some(match self {
184 Self::Number(number) => proto::progress_token::Value::Number(*number),
185 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
186 }),
187 }
188 }
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192pub enum FormatTrigger {
193 Save,
194 Manual,
195}
196
197pub enum LspFormatTarget {
198 Buffers,
199 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
200}
201
202pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
203
204impl FormatTrigger {
205 fn from_proto(value: i32) -> FormatTrigger {
206 match value {
207 0 => FormatTrigger::Save,
208 1 => FormatTrigger::Manual,
209 _ => FormatTrigger::Save,
210 }
211 }
212}
213
214#[derive(Clone)]
215struct UnifiedLanguageServer {
216 id: LanguageServerId,
217 project_roots: HashSet<Arc<RelPath>>,
218}
219
220#[derive(Clone, Hash, PartialEq, Eq)]
221struct LanguageServerSeed {
222 worktree_id: WorktreeId,
223 name: LanguageServerName,
224 toolchain: Option<Toolchain>,
225 settings: Arc<LspSettings>,
226}
227
228#[derive(Debug)]
229pub struct DocumentDiagnosticsUpdate<'a, D> {
230 pub diagnostics: D,
231 pub result_id: Option<String>,
232 pub server_id: LanguageServerId,
233 pub disk_based_sources: Cow<'a, [String]>,
234}
235
236pub struct DocumentDiagnostics {
237 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
238 document_abs_path: PathBuf,
239 version: Option<i32>,
240}
241
242#[derive(Default, Debug)]
243struct DynamicRegistrations {
244 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
245 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
246}
247
248pub struct LocalLspStore {
249 weak: WeakEntity<LspStore>,
250 worktree_store: Entity<WorktreeStore>,
251 toolchain_store: Entity<LocalToolchainStore>,
252 http_client: Arc<dyn HttpClient>,
253 environment: Entity<ProjectEnvironment>,
254 fs: Arc<dyn Fs>,
255 languages: Arc<LanguageRegistry>,
256 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
257 yarn: Entity<YarnPathStore>,
258 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
259 buffers_being_formatted: HashSet<BufferId>,
260 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
261 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
262 watched_manifest_filenames: HashSet<ManifestName>,
263 language_server_paths_watched_for_rename:
264 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
265 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
266 supplementary_language_servers:
267 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
268 prettier_store: Entity<PrettierStore>,
269 next_diagnostic_group_id: usize,
270 diagnostics: HashMap<
271 WorktreeId,
272 HashMap<
273 Arc<RelPath>,
274 Vec<(
275 LanguageServerId,
276 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
277 )>,
278 >,
279 >,
280 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
281 _subscription: gpui::Subscription,
282 lsp_tree: LanguageServerTree,
283 registered_buffers: HashMap<BufferId, usize>,
284 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
285 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
286}
287
288impl LocalLspStore {
289 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
290 pub fn running_language_server_for_id(
291 &self,
292 id: LanguageServerId,
293 ) -> Option<&Arc<LanguageServer>> {
294 let language_server_state = self.language_servers.get(&id)?;
295
296 match language_server_state {
297 LanguageServerState::Running { server, .. } => Some(server),
298 LanguageServerState::Starting { .. } => None,
299 }
300 }
301
302 fn get_or_insert_language_server(
303 &mut self,
304 worktree_handle: &Entity<Worktree>,
305 delegate: Arc<LocalLspAdapterDelegate>,
306 disposition: &Arc<LaunchDisposition>,
307 language_name: &LanguageName,
308 cx: &mut App,
309 ) -> LanguageServerId {
310 let key = LanguageServerSeed {
311 worktree_id: worktree_handle.read(cx).id(),
312 name: disposition.server_name.clone(),
313 settings: disposition.settings.clone(),
314 toolchain: disposition.toolchain.clone(),
315 };
316 if let Some(state) = self.language_server_ids.get_mut(&key) {
317 state.project_roots.insert(disposition.path.path.clone());
318 state.id
319 } else {
320 let adapter = self
321 .languages
322 .lsp_adapters(language_name)
323 .into_iter()
324 .find(|adapter| adapter.name() == disposition.server_name)
325 .expect("To find LSP adapter");
326 let new_language_server_id = self.start_language_server(
327 worktree_handle,
328 delegate,
329 adapter,
330 disposition.settings.clone(),
331 key.clone(),
332 cx,
333 );
334 if let Some(state) = self.language_server_ids.get_mut(&key) {
335 state.project_roots.insert(disposition.path.path.clone());
336 } else {
337 debug_assert!(
338 false,
339 "Expected `start_language_server` to ensure that `key` exists in a map"
340 );
341 }
342 new_language_server_id
343 }
344 }
345
346 fn start_language_server(
347 &mut self,
348 worktree_handle: &Entity<Worktree>,
349 delegate: Arc<LocalLspAdapterDelegate>,
350 adapter: Arc<CachedLspAdapter>,
351 settings: Arc<LspSettings>,
352 key: LanguageServerSeed,
353 cx: &mut App,
354 ) -> LanguageServerId {
355 let worktree = worktree_handle.read(cx);
356
357 let root_path = worktree.abs_path();
358 let toolchain = key.toolchain.clone();
359 let override_options = settings.initialization_options.clone();
360
361 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
362
363 let server_id = self.languages.next_language_server_id();
364 log::trace!(
365 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
366 adapter.name.0
367 );
368
369 let binary = self.get_language_server_binary(
370 adapter.clone(),
371 settings,
372 toolchain.clone(),
373 delegate.clone(),
374 true,
375 cx,
376 );
377 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
378
379 let pending_server = cx.spawn({
380 let adapter = adapter.clone();
381 let server_name = adapter.name.clone();
382 let stderr_capture = stderr_capture.clone();
383 #[cfg(any(test, feature = "test-support"))]
384 let lsp_store = self.weak.clone();
385 let pending_workspace_folders = pending_workspace_folders.clone();
386 async move |cx| {
387 let binary = binary.await?;
388 #[cfg(any(test, feature = "test-support"))]
389 if let Some(server) = lsp_store
390 .update(&mut cx.clone(), |this, cx| {
391 this.languages.create_fake_language_server(
392 server_id,
393 &server_name,
394 binary.clone(),
395 &mut cx.to_async(),
396 )
397 })
398 .ok()
399 .flatten()
400 {
401 return Ok(server);
402 }
403
404 let code_action_kinds = adapter.code_action_kinds();
405 lsp::LanguageServer::new(
406 stderr_capture,
407 server_id,
408 server_name,
409 binary,
410 &root_path,
411 code_action_kinds,
412 Some(pending_workspace_folders),
413 cx,
414 )
415 }
416 });
417
418 let startup = {
419 let server_name = adapter.name.0.clone();
420 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
421 let key = key.clone();
422 let adapter = adapter.clone();
423 let lsp_store = self.weak.clone();
424 let pending_workspace_folders = pending_workspace_folders.clone();
425
426 let pull_diagnostics = ProjectSettings::get_global(cx)
427 .diagnostics
428 .lsp_pull_diagnostics
429 .enabled;
430 cx.spawn(async move |cx| {
431 let result = async {
432 let language_server = pending_server.await?;
433
434 let workspace_config = Self::workspace_configuration_for_adapter(
435 adapter.adapter.clone(),
436 &delegate,
437 toolchain,
438 cx,
439 )
440 .await?;
441
442 let mut initialization_options = Self::initialization_options_for_adapter(
443 adapter.adapter.clone(),
444 &delegate,
445 )
446 .await?;
447
448 match (&mut initialization_options, override_options) {
449 (Some(initialization_options), Some(override_options)) => {
450 merge_json_value_into(override_options, initialization_options);
451 }
452 (None, override_options) => initialization_options = override_options,
453 _ => {}
454 }
455
456 let initialization_params = cx.update(|cx| {
457 let mut params =
458 language_server.default_initialize_params(pull_diagnostics, cx);
459 params.initialization_options = initialization_options;
460 adapter.adapter.prepare_initialize_params(params, cx)
461 })??;
462
463 Self::setup_lsp_messages(
464 lsp_store.clone(),
465 &language_server,
466 delegate.clone(),
467 adapter.clone(),
468 );
469
470 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
471 settings: workspace_config,
472 };
473 let language_server = cx
474 .update(|cx| {
475 language_server.initialize(
476 initialization_params,
477 Arc::new(did_change_configuration_params.clone()),
478 cx,
479 )
480 })?
481 .await
482 .inspect_err(|_| {
483 if let Some(lsp_store) = lsp_store.upgrade() {
484 lsp_store
485 .update(cx, |lsp_store, cx| {
486 lsp_store.cleanup_lsp_data(server_id);
487 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
488 })
489 .ok();
490 }
491 })?;
492
493 language_server.notify::<lsp::notification::DidChangeConfiguration>(
494 did_change_configuration_params,
495 )?;
496
497 anyhow::Ok(language_server)
498 }
499 .await;
500
501 match result {
502 Ok(server) => {
503 lsp_store
504 .update(cx, |lsp_store, cx| {
505 lsp_store.insert_newly_running_language_server(
506 adapter,
507 server.clone(),
508 server_id,
509 key,
510 pending_workspace_folders,
511 cx,
512 );
513 })
514 .ok();
515 stderr_capture.lock().take();
516 Some(server)
517 }
518
519 Err(err) => {
520 let log = stderr_capture.lock().take().unwrap_or_default();
521 delegate.update_status(
522 adapter.name(),
523 BinaryStatus::Failed {
524 error: if log.is_empty() {
525 format!("{err:#}")
526 } else {
527 format!("{err:#}\n-- stderr --\n{log}")
528 },
529 },
530 );
531 log::error!("Failed to start language server {server_name:?}: {err:?}");
532 if !log.is_empty() {
533 log::error!("server stderr: {log}");
534 }
535 None
536 }
537 }
538 })
539 };
540 let state = LanguageServerState::Starting {
541 startup,
542 pending_workspace_folders,
543 };
544
545 self.languages
546 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
547
548 self.language_servers.insert(server_id, state);
549 self.language_server_ids
550 .entry(key)
551 .or_insert(UnifiedLanguageServer {
552 id: server_id,
553 project_roots: Default::default(),
554 });
555 server_id
556 }
557
558 fn get_language_server_binary(
559 &self,
560 adapter: Arc<CachedLspAdapter>,
561 settings: Arc<LspSettings>,
562 toolchain: Option<Toolchain>,
563 delegate: Arc<dyn LspAdapterDelegate>,
564 allow_binary_download: bool,
565 cx: &mut App,
566 ) -> Task<Result<LanguageServerBinary>> {
567 if let Some(settings) = &settings.binary
568 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
569 {
570 let settings = settings.clone();
571
572 return cx.background_spawn(async move {
573 let mut env = delegate.shell_env().await;
574 env.extend(settings.env.unwrap_or_default());
575
576 Ok(LanguageServerBinary {
577 path: delegate.resolve_executable_path(path),
578 env: Some(env),
579 arguments: settings
580 .arguments
581 .unwrap_or_default()
582 .iter()
583 .map(Into::into)
584 .collect(),
585 })
586 });
587 }
588 let lsp_binary_options = LanguageServerBinaryOptions {
589 allow_path_lookup: !settings
590 .binary
591 .as_ref()
592 .and_then(|b| b.ignore_system_version)
593 .unwrap_or_default(),
594 allow_binary_download,
595 pre_release: settings
596 .fetch
597 .as_ref()
598 .and_then(|f| f.pre_release)
599 .unwrap_or(false),
600 };
601
602 cx.spawn(async move |cx| {
603 let (existing_binary, maybe_download_binary) = adapter
604 .clone()
605 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
606 .await
607 .await;
608
609 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
610
611 let mut binary = match (existing_binary, maybe_download_binary) {
612 (binary, None) => binary?,
613 (Err(_), Some(downloader)) => downloader.await?,
614 (Ok(existing_binary), Some(downloader)) => {
615 let mut download_timeout = cx
616 .background_executor()
617 .timer(SERVER_DOWNLOAD_TIMEOUT)
618 .fuse();
619 let mut downloader = downloader.fuse();
620 futures::select! {
621 _ = download_timeout => {
622 // Return existing binary and kick the existing work to the background.
623 cx.spawn(async move |_| downloader.await).detach();
624 Ok(existing_binary)
625 },
626 downloaded_or_existing_binary = downloader => {
627 // If download fails, this results in the existing binary.
628 downloaded_or_existing_binary
629 }
630 }?
631 }
632 };
633 let mut shell_env = delegate.shell_env().await;
634
635 shell_env.extend(binary.env.unwrap_or_default());
636
637 if let Some(settings) = settings.binary.as_ref() {
638 if let Some(arguments) = &settings.arguments {
639 binary.arguments = arguments.iter().map(Into::into).collect();
640 }
641 if let Some(env) = &settings.env {
642 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
643 }
644 }
645
646 binary.env = Some(shell_env);
647 Ok(binary)
648 })
649 }
650
651 fn setup_lsp_messages(
652 lsp_store: WeakEntity<LspStore>,
653 language_server: &LanguageServer,
654 delegate: Arc<dyn LspAdapterDelegate>,
655 adapter: Arc<CachedLspAdapter>,
656 ) {
657 let name = language_server.name();
658 let server_id = language_server.server_id();
659 language_server
660 .on_notification::<lsp::notification::PublishDiagnostics, _>({
661 let adapter = adapter.clone();
662 let this = lsp_store.clone();
663 move |mut params, cx| {
664 let adapter = adapter.clone();
665 if let Some(this) = this.upgrade() {
666 this.update(cx, |this, cx| {
667 {
668 let buffer = params
669 .uri
670 .to_file_path()
671 .map(|file_path| this.get_buffer(&file_path, cx))
672 .ok()
673 .flatten();
674 adapter.process_diagnostics(&mut params, server_id, buffer);
675 }
676
677 this.merge_lsp_diagnostics(
678 DiagnosticSourceKind::Pushed,
679 vec![DocumentDiagnosticsUpdate {
680 server_id,
681 diagnostics: params,
682 result_id: None,
683 disk_based_sources: Cow::Borrowed(
684 &adapter.disk_based_diagnostic_sources,
685 ),
686 }],
687 |_, diagnostic, cx| match diagnostic.source_kind {
688 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
689 adapter.retain_old_diagnostic(diagnostic, cx)
690 }
691 DiagnosticSourceKind::Pulled => true,
692 },
693 cx,
694 )
695 .log_err();
696 })
697 .ok();
698 }
699 }
700 })
701 .detach();
702 language_server
703 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
704 let adapter = adapter.adapter.clone();
705 let delegate = delegate.clone();
706 let this = lsp_store.clone();
707 move |params, cx| {
708 let adapter = adapter.clone();
709 let delegate = delegate.clone();
710 let this = this.clone();
711 let mut cx = cx.clone();
712 async move {
713 let toolchain_for_id = this
714 .update(&mut cx, |this, _| {
715 this.as_local()?.language_server_ids.iter().find_map(
716 |(seed, value)| {
717 (value.id == server_id).then(|| seed.toolchain.clone())
718 },
719 )
720 })?
721 .context("Expected the LSP store to be in a local mode")?;
722 let workspace_config = Self::workspace_configuration_for_adapter(
723 adapter.clone(),
724 &delegate,
725 toolchain_for_id,
726 &mut cx,
727 )
728 .await?;
729
730 Ok(params
731 .items
732 .into_iter()
733 .map(|item| {
734 if let Some(section) = &item.section {
735 workspace_config
736 .get(section)
737 .cloned()
738 .unwrap_or(serde_json::Value::Null)
739 } else {
740 workspace_config.clone()
741 }
742 })
743 .collect())
744 }
745 }
746 })
747 .detach();
748
749 language_server
750 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
751 let this = lsp_store.clone();
752 move |_, cx| {
753 let this = this.clone();
754 let cx = cx.clone();
755 async move {
756 let Some(server) =
757 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
758 else {
759 return Ok(None);
760 };
761 let root = server.workspace_folders();
762 Ok(Some(
763 root.into_iter()
764 .map(|uri| WorkspaceFolder {
765 uri,
766 name: Default::default(),
767 })
768 .collect(),
769 ))
770 }
771 }
772 })
773 .detach();
774 // Even though we don't have handling for these requests, respond to them to
775 // avoid stalling any language server like `gopls` which waits for a response
776 // to these requests when initializing.
777 language_server
778 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
779 let this = lsp_store.clone();
780 move |params, cx| {
781 let this = this.clone();
782 let mut cx = cx.clone();
783 async move {
784 this.update(&mut cx, |this, _| {
785 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
786 {
787 status
788 .progress_tokens
789 .insert(ProgressToken::from_lsp(params.token));
790 }
791 })?;
792
793 Ok(())
794 }
795 }
796 })
797 .detach();
798
799 language_server
800 .on_request::<lsp::request::RegisterCapability, _, _>({
801 let lsp_store = lsp_store.clone();
802 move |params, cx| {
803 let lsp_store = lsp_store.clone();
804 let mut cx = cx.clone();
805 async move {
806 lsp_store
807 .update(&mut cx, |lsp_store, cx| {
808 if lsp_store.as_local().is_some() {
809 match lsp_store
810 .register_server_capabilities(server_id, params, cx)
811 {
812 Ok(()) => {}
813 Err(e) => {
814 log::error!(
815 "Failed to register server capabilities: {e:#}"
816 );
817 }
818 };
819 }
820 })
821 .ok();
822 Ok(())
823 }
824 }
825 })
826 .detach();
827
828 language_server
829 .on_request::<lsp::request::UnregisterCapability, _, _>({
830 let lsp_store = lsp_store.clone();
831 move |params, cx| {
832 let lsp_store = lsp_store.clone();
833 let mut cx = cx.clone();
834 async move {
835 lsp_store
836 .update(&mut cx, |lsp_store, cx| {
837 if lsp_store.as_local().is_some() {
838 match lsp_store
839 .unregister_server_capabilities(server_id, params, cx)
840 {
841 Ok(()) => {}
842 Err(e) => {
843 log::error!(
844 "Failed to unregister server capabilities: {e:#}"
845 );
846 }
847 }
848 }
849 })
850 .ok();
851 Ok(())
852 }
853 }
854 })
855 .detach();
856
857 language_server
858 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
859 let this = lsp_store.clone();
860 move |params, cx| {
861 let mut cx = cx.clone();
862 let this = this.clone();
863 async move {
864 LocalLspStore::on_lsp_workspace_edit(
865 this.clone(),
866 params,
867 server_id,
868 &mut cx,
869 )
870 .await
871 }
872 }
873 })
874 .detach();
875
876 language_server
877 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
878 let lsp_store = lsp_store.clone();
879 let request_id = Arc::new(AtomicUsize::new(0));
880 move |(), cx| {
881 let lsp_store = lsp_store.clone();
882 let request_id = request_id.clone();
883 let mut cx = cx.clone();
884 async move {
885 lsp_store
886 .update(&mut cx, |lsp_store, cx| {
887 let request_id =
888 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
889 cx.emit(LspStoreEvent::RefreshInlayHints {
890 server_id,
891 request_id,
892 });
893 lsp_store
894 .downstream_client
895 .as_ref()
896 .map(|(client, project_id)| {
897 client.send(proto::RefreshInlayHints {
898 project_id: *project_id,
899 server_id: server_id.to_proto(),
900 request_id: request_id.map(|id| id as u64),
901 })
902 })
903 })?
904 .transpose()?;
905 Ok(())
906 }
907 }
908 })
909 .detach();
910
911 language_server
912 .on_request::<lsp::request::CodeLensRefresh, _, _>({
913 let this = lsp_store.clone();
914 move |(), cx| {
915 let this = this.clone();
916 let mut cx = cx.clone();
917 async move {
918 this.update(&mut cx, |this, cx| {
919 cx.emit(LspStoreEvent::RefreshCodeLens);
920 this.downstream_client.as_ref().map(|(client, project_id)| {
921 client.send(proto::RefreshCodeLens {
922 project_id: *project_id,
923 })
924 })
925 })?
926 .transpose()?;
927 Ok(())
928 }
929 }
930 })
931 .detach();
932
933 language_server
934 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
935 let this = lsp_store.clone();
936 move |(), cx| {
937 let this = this.clone();
938 let mut cx = cx.clone();
939 async move {
940 this.update(&mut cx, |lsp_store, _| {
941 lsp_store.pull_workspace_diagnostics(server_id);
942 lsp_store
943 .downstream_client
944 .as_ref()
945 .map(|(client, project_id)| {
946 client.send(proto::PullWorkspaceDiagnostics {
947 project_id: *project_id,
948 server_id: server_id.to_proto(),
949 })
950 })
951 })?
952 .transpose()?;
953 Ok(())
954 }
955 }
956 })
957 .detach();
958
959 language_server
960 .on_request::<lsp::request::ShowMessageRequest, _, _>({
961 let this = lsp_store.clone();
962 let name = name.to_string();
963 move |params, cx| {
964 let this = this.clone();
965 let name = name.to_string();
966 let mut cx = cx.clone();
967 async move {
968 let actions = params.actions.unwrap_or_default();
969 let (tx, rx) = smol::channel::bounded(1);
970 let request = LanguageServerPromptRequest {
971 level: match params.typ {
972 lsp::MessageType::ERROR => PromptLevel::Critical,
973 lsp::MessageType::WARNING => PromptLevel::Warning,
974 _ => PromptLevel::Info,
975 },
976 message: params.message,
977 actions,
978 response_channel: tx,
979 lsp_name: name.clone(),
980 };
981
982 let did_update = this
983 .update(&mut cx, |_, cx| {
984 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
985 })
986 .is_ok();
987 if did_update {
988 let response = rx.recv().await.ok();
989 Ok(response)
990 } else {
991 Ok(None)
992 }
993 }
994 }
995 })
996 .detach();
997 language_server
998 .on_notification::<lsp::notification::ShowMessage, _>({
999 let this = lsp_store.clone();
1000 let name = name.to_string();
1001 move |params, cx| {
1002 let this = this.clone();
1003 let name = name.to_string();
1004 let mut cx = cx.clone();
1005
1006 let (tx, _) = smol::channel::bounded(1);
1007 let request = LanguageServerPromptRequest {
1008 level: match params.typ {
1009 lsp::MessageType::ERROR => PromptLevel::Critical,
1010 lsp::MessageType::WARNING => PromptLevel::Warning,
1011 _ => PromptLevel::Info,
1012 },
1013 message: params.message,
1014 actions: vec![],
1015 response_channel: tx,
1016 lsp_name: name,
1017 };
1018
1019 let _ = this.update(&mut cx, |_, cx| {
1020 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1021 });
1022 }
1023 })
1024 .detach();
1025
1026 let disk_based_diagnostics_progress_token =
1027 adapter.disk_based_diagnostics_progress_token.clone();
1028
1029 language_server
1030 .on_notification::<lsp::notification::Progress, _>({
1031 let this = lsp_store.clone();
1032 move |params, cx| {
1033 if let Some(this) = this.upgrade() {
1034 this.update(cx, |this, cx| {
1035 this.on_lsp_progress(
1036 params,
1037 server_id,
1038 disk_based_diagnostics_progress_token.clone(),
1039 cx,
1040 );
1041 })
1042 .ok();
1043 }
1044 }
1045 })
1046 .detach();
1047
1048 language_server
1049 .on_notification::<lsp::notification::LogMessage, _>({
1050 let this = lsp_store.clone();
1051 move |params, cx| {
1052 if let Some(this) = this.upgrade() {
1053 this.update(cx, |_, cx| {
1054 cx.emit(LspStoreEvent::LanguageServerLog(
1055 server_id,
1056 LanguageServerLogType::Log(params.typ),
1057 params.message,
1058 ));
1059 })
1060 .ok();
1061 }
1062 }
1063 })
1064 .detach();
1065
1066 language_server
1067 .on_notification::<lsp::notification::LogTrace, _>({
1068 let this = lsp_store.clone();
1069 move |params, cx| {
1070 let mut cx = cx.clone();
1071 if let Some(this) = this.upgrade() {
1072 this.update(&mut cx, |_, cx| {
1073 cx.emit(LspStoreEvent::LanguageServerLog(
1074 server_id,
1075 LanguageServerLogType::Trace {
1076 verbose_info: params.verbose,
1077 },
1078 params.message,
1079 ));
1080 })
1081 .ok();
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1088 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1089 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1090 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1091 }
1092
1093 fn shutdown_language_servers_on_quit(
1094 &mut self,
1095 _: &mut Context<LspStore>,
1096 ) -> impl Future<Output = ()> + use<> {
1097 let shutdown_futures = self
1098 .language_servers
1099 .drain()
1100 .map(|(_, server_state)| Self::shutdown_server(server_state))
1101 .collect::<Vec<_>>();
1102
1103 async move {
1104 join_all(shutdown_futures).await;
1105 }
1106 }
1107
1108 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1109 match server_state {
1110 LanguageServerState::Running { server, .. } => {
1111 if let Some(shutdown) = server.shutdown() {
1112 shutdown.await;
1113 }
1114 }
1115 LanguageServerState::Starting { startup, .. } => {
1116 if let Some(server) = startup.await
1117 && let Some(shutdown) = server.shutdown()
1118 {
1119 shutdown.await;
1120 }
1121 }
1122 }
1123 Ok(())
1124 }
1125
1126 fn language_servers_for_worktree(
1127 &self,
1128 worktree_id: WorktreeId,
1129 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1130 self.language_server_ids
1131 .iter()
1132 .filter_map(move |(seed, state)| {
1133 if seed.worktree_id != worktree_id {
1134 return None;
1135 }
1136
1137 if let Some(LanguageServerState::Running { server, .. }) =
1138 self.language_servers.get(&state.id)
1139 {
1140 Some(server)
1141 } else {
1142 None
1143 }
1144 })
1145 }
1146
1147 fn language_server_ids_for_project_path(
1148 &self,
1149 project_path: ProjectPath,
1150 language: &Language,
1151 cx: &mut App,
1152 ) -> Vec<LanguageServerId> {
1153 let Some(worktree) = self
1154 .worktree_store
1155 .read(cx)
1156 .worktree_for_id(project_path.worktree_id, cx)
1157 else {
1158 return Vec::new();
1159 };
1160 let delegate: Arc<dyn ManifestDelegate> =
1161 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1162
1163 self.lsp_tree
1164 .get(
1165 project_path,
1166 language.name(),
1167 language.manifest(),
1168 &delegate,
1169 cx,
1170 )
1171 .collect::<Vec<_>>()
1172 }
1173
1174 fn language_server_ids_for_buffer(
1175 &self,
1176 buffer: &Buffer,
1177 cx: &mut App,
1178 ) -> Vec<LanguageServerId> {
1179 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1180 let worktree_id = file.worktree_id(cx);
1181
1182 let path: Arc<RelPath> = file
1183 .path()
1184 .parent()
1185 .map(Arc::from)
1186 .unwrap_or_else(|| file.path().clone());
1187 let worktree_path = ProjectPath { worktree_id, path };
1188 self.language_server_ids_for_project_path(worktree_path, language, cx)
1189 } else {
1190 Vec::new()
1191 }
1192 }
1193
1194 fn language_servers_for_buffer<'a>(
1195 &'a self,
1196 buffer: &'a Buffer,
1197 cx: &'a mut App,
1198 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1199 self.language_server_ids_for_buffer(buffer, cx)
1200 .into_iter()
1201 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1202 LanguageServerState::Running {
1203 adapter, server, ..
1204 } => Some((adapter, server)),
1205 _ => None,
1206 })
1207 }
1208
1209 async fn execute_code_action_kind_locally(
1210 lsp_store: WeakEntity<LspStore>,
1211 mut buffers: Vec<Entity<Buffer>>,
1212 kind: CodeActionKind,
1213 push_to_history: bool,
1214 cx: &mut AsyncApp,
1215 ) -> anyhow::Result<ProjectTransaction> {
1216 // Do not allow multiple concurrent code actions requests for the
1217 // same buffer.
1218 lsp_store.update(cx, |this, cx| {
1219 let this = this.as_local_mut().unwrap();
1220 buffers.retain(|buffer| {
1221 this.buffers_being_formatted
1222 .insert(buffer.read(cx).remote_id())
1223 });
1224 })?;
1225 let _cleanup = defer({
1226 let this = lsp_store.clone();
1227 let mut cx = cx.clone();
1228 let buffers = &buffers;
1229 move || {
1230 this.update(&mut cx, |this, cx| {
1231 let this = this.as_local_mut().unwrap();
1232 for buffer in buffers {
1233 this.buffers_being_formatted
1234 .remove(&buffer.read(cx).remote_id());
1235 }
1236 })
1237 .ok();
1238 }
1239 });
1240 let mut project_transaction = ProjectTransaction::default();
1241
1242 for buffer in &buffers {
1243 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1244 buffer.update(cx, |buffer, cx| {
1245 lsp_store
1246 .as_local()
1247 .unwrap()
1248 .language_servers_for_buffer(buffer, cx)
1249 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1250 .collect::<Vec<_>>()
1251 })
1252 })?;
1253 for (_, language_server) in adapters_and_servers.iter() {
1254 let actions = Self::get_server_code_actions_from_action_kinds(
1255 &lsp_store,
1256 language_server.server_id(),
1257 vec![kind.clone()],
1258 buffer,
1259 cx,
1260 )
1261 .await?;
1262 Self::execute_code_actions_on_server(
1263 &lsp_store,
1264 language_server,
1265 actions,
1266 push_to_history,
1267 &mut project_transaction,
1268 cx,
1269 )
1270 .await?;
1271 }
1272 }
1273 Ok(project_transaction)
1274 }
1275
1276 async fn format_locally(
1277 lsp_store: WeakEntity<LspStore>,
1278 mut buffers: Vec<FormattableBuffer>,
1279 push_to_history: bool,
1280 trigger: FormatTrigger,
1281 logger: zlog::Logger,
1282 cx: &mut AsyncApp,
1283 ) -> anyhow::Result<ProjectTransaction> {
1284 // Do not allow multiple concurrent formatting requests for the
1285 // same buffer.
1286 lsp_store.update(cx, |this, cx| {
1287 let this = this.as_local_mut().unwrap();
1288 buffers.retain(|buffer| {
1289 this.buffers_being_formatted
1290 .insert(buffer.handle.read(cx).remote_id())
1291 });
1292 })?;
1293
1294 let _cleanup = defer({
1295 let this = lsp_store.clone();
1296 let mut cx = cx.clone();
1297 let buffers = &buffers;
1298 move || {
1299 this.update(&mut cx, |this, cx| {
1300 let this = this.as_local_mut().unwrap();
1301 for buffer in buffers {
1302 this.buffers_being_formatted
1303 .remove(&buffer.handle.read(cx).remote_id());
1304 }
1305 })
1306 .ok();
1307 }
1308 });
1309
1310 let mut project_transaction = ProjectTransaction::default();
1311
1312 for buffer in &buffers {
1313 zlog::debug!(
1314 logger =>
1315 "formatting buffer '{:?}'",
1316 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1317 );
1318 // Create an empty transaction to hold all of the formatting edits.
1319 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1320 // ensure no transactions created while formatting are
1321 // grouped with the previous transaction in the history
1322 // based on the transaction group interval
1323 buffer.finalize_last_transaction();
1324 buffer
1325 .start_transaction()
1326 .context("transaction already open")?;
1327 buffer.end_transaction(cx);
1328 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1329 buffer.finalize_last_transaction();
1330 anyhow::Ok(transaction_id)
1331 })??;
1332
1333 let result = Self::format_buffer_locally(
1334 lsp_store.clone(),
1335 buffer,
1336 formatting_transaction_id,
1337 trigger,
1338 logger,
1339 cx,
1340 )
1341 .await;
1342
1343 buffer.handle.update(cx, |buffer, cx| {
1344 let Some(formatting_transaction) =
1345 buffer.get_transaction(formatting_transaction_id).cloned()
1346 else {
1347 zlog::warn!(logger => "no formatting transaction");
1348 return;
1349 };
1350 if formatting_transaction.edit_ids.is_empty() {
1351 zlog::debug!(logger => "no changes made while formatting");
1352 buffer.forget_transaction(formatting_transaction_id);
1353 return;
1354 }
1355 if !push_to_history {
1356 zlog::trace!(logger => "forgetting format transaction");
1357 buffer.forget_transaction(formatting_transaction.id);
1358 }
1359 project_transaction
1360 .0
1361 .insert(cx.entity(), formatting_transaction);
1362 })?;
1363
1364 result?;
1365 }
1366
1367 Ok(project_transaction)
1368 }
1369
1370 async fn format_buffer_locally(
1371 lsp_store: WeakEntity<LspStore>,
1372 buffer: &FormattableBuffer,
1373 formatting_transaction_id: clock::Lamport,
1374 trigger: FormatTrigger,
1375 logger: zlog::Logger,
1376 cx: &mut AsyncApp,
1377 ) -> Result<()> {
1378 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1379 buffer.handle.update(cx, |buffer, cx| {
1380 let adapters_and_servers = lsp_store
1381 .as_local()
1382 .unwrap()
1383 .language_servers_for_buffer(buffer, cx)
1384 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1385 .collect::<Vec<_>>();
1386 let settings =
1387 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1388 .into_owned();
1389 (adapters_and_servers, settings)
1390 })
1391 })?;
1392
1393 /// Apply edits to the buffer that will become part of the formatting transaction.
1394 /// Fails if the buffer has been edited since the start of that transaction.
1395 fn extend_formatting_transaction(
1396 buffer: &FormattableBuffer,
1397 formatting_transaction_id: text::TransactionId,
1398 cx: &mut AsyncApp,
1399 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1400 ) -> anyhow::Result<()> {
1401 buffer.handle.update(cx, |buffer, cx| {
1402 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1403 if last_transaction_id != Some(formatting_transaction_id) {
1404 anyhow::bail!("Buffer edited while formatting. Aborting")
1405 }
1406 buffer.start_transaction();
1407 operation(buffer, cx);
1408 if let Some(transaction_id) = buffer.end_transaction(cx) {
1409 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1410 }
1411 Ok(())
1412 })?
1413 }
1414
1415 // handle whitespace formatting
1416 if settings.remove_trailing_whitespace_on_save {
1417 zlog::trace!(logger => "removing trailing whitespace");
1418 let diff = buffer
1419 .handle
1420 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1421 .await;
1422 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1423 buffer.apply_diff(diff, cx);
1424 })?;
1425 }
1426
1427 if settings.ensure_final_newline_on_save {
1428 zlog::trace!(logger => "ensuring final newline");
1429 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1430 buffer.ensure_final_newline(cx);
1431 })?;
1432 }
1433
1434 // Formatter for `code_actions_on_format` that runs before
1435 // the rest of the formatters
1436 let mut code_actions_on_format_formatters = None;
1437 let should_run_code_actions_on_format = !matches!(
1438 (trigger, &settings.format_on_save),
1439 (FormatTrigger::Save, &FormatOnSave::Off)
1440 );
1441 if should_run_code_actions_on_format {
1442 let have_code_actions_to_run_on_format = settings
1443 .code_actions_on_format
1444 .values()
1445 .any(|enabled| *enabled);
1446 if have_code_actions_to_run_on_format {
1447 zlog::trace!(logger => "going to run code actions on format");
1448 code_actions_on_format_formatters = Some(
1449 settings
1450 .code_actions_on_format
1451 .iter()
1452 .filter_map(|(action, enabled)| enabled.then_some(action))
1453 .cloned()
1454 .map(Formatter::CodeAction)
1455 .collect::<Vec<_>>(),
1456 );
1457 }
1458 }
1459
1460 let formatters = match (trigger, &settings.format_on_save) {
1461 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1462 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1463 settings.formatter.as_ref()
1464 }
1465 };
1466
1467 let formatters = code_actions_on_format_formatters
1468 .iter()
1469 .flatten()
1470 .chain(formatters);
1471
1472 for formatter in formatters {
1473 let formatter = if formatter == &Formatter::Auto {
1474 if settings.prettier.allowed {
1475 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1476 &Formatter::Prettier
1477 } else {
1478 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1479 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1480 }
1481 } else {
1482 formatter
1483 };
1484 match formatter {
1485 Formatter::Auto => unreachable!("Auto resolved above"),
1486 Formatter::Prettier => {
1487 let logger = zlog::scoped!(logger => "prettier");
1488 zlog::trace!(logger => "formatting");
1489 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1490
1491 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1492 lsp_store.prettier_store().unwrap().downgrade()
1493 })?;
1494 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1495 .await
1496 .transpose()?;
1497 let Some(diff) = diff else {
1498 zlog::trace!(logger => "No changes");
1499 continue;
1500 };
1501
1502 extend_formatting_transaction(
1503 buffer,
1504 formatting_transaction_id,
1505 cx,
1506 |buffer, cx| {
1507 buffer.apply_diff(diff, cx);
1508 },
1509 )?;
1510 }
1511 Formatter::External { command, arguments } => {
1512 let logger = zlog::scoped!(logger => "command");
1513 zlog::trace!(logger => "formatting");
1514 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1515
1516 let diff = Self::format_via_external_command(
1517 buffer,
1518 command.as_ref(),
1519 arguments.as_deref(),
1520 cx,
1521 )
1522 .await
1523 .with_context(|| {
1524 format!("Failed to format buffer via external command: {}", command)
1525 })?;
1526 let Some(diff) = diff else {
1527 zlog::trace!(logger => "No changes");
1528 continue;
1529 };
1530
1531 extend_formatting_transaction(
1532 buffer,
1533 formatting_transaction_id,
1534 cx,
1535 |buffer, cx| {
1536 buffer.apply_diff(diff, cx);
1537 },
1538 )?;
1539 }
1540 Formatter::LanguageServer(specifier) => {
1541 let logger = zlog::scoped!(logger => "language-server");
1542 zlog::trace!(logger => "formatting");
1543 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1544
1545 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1546 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1547 continue;
1548 };
1549
1550 let language_server = match specifier {
1551 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1552 adapters_and_servers.iter().find_map(|(adapter, server)| {
1553 if adapter.name.0.as_ref() == name {
1554 Some(server.clone())
1555 } else {
1556 None
1557 }
1558 })
1559 }
1560 settings::LanguageServerFormatterSpecifier::Current => {
1561 adapters_and_servers.first().map(|e| e.1.clone())
1562 }
1563 };
1564
1565 let Some(language_server) = language_server else {
1566 log::debug!(
1567 "No language server found to format buffer '{:?}'. Skipping",
1568 buffer_path_abs.as_path().to_string_lossy()
1569 );
1570 continue;
1571 };
1572
1573 zlog::trace!(
1574 logger =>
1575 "Formatting buffer '{:?}' using language server '{:?}'",
1576 buffer_path_abs.as_path().to_string_lossy(),
1577 language_server.name()
1578 );
1579
1580 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1581 zlog::trace!(logger => "formatting ranges");
1582 Self::format_ranges_via_lsp(
1583 &lsp_store,
1584 &buffer.handle,
1585 ranges,
1586 buffer_path_abs,
1587 &language_server,
1588 &settings,
1589 cx,
1590 )
1591 .await
1592 .context("Failed to format ranges via language server")?
1593 } else {
1594 zlog::trace!(logger => "formatting full");
1595 Self::format_via_lsp(
1596 &lsp_store,
1597 &buffer.handle,
1598 buffer_path_abs,
1599 &language_server,
1600 &settings,
1601 cx,
1602 )
1603 .await
1604 .context("failed to format via language server")?
1605 };
1606
1607 if edits.is_empty() {
1608 zlog::trace!(logger => "No changes");
1609 continue;
1610 }
1611 extend_formatting_transaction(
1612 buffer,
1613 formatting_transaction_id,
1614 cx,
1615 |buffer, cx| {
1616 buffer.edit(edits, None, cx);
1617 },
1618 )?;
1619 }
1620 Formatter::CodeAction(code_action_name) => {
1621 let logger = zlog::scoped!(logger => "code-actions");
1622 zlog::trace!(logger => "formatting");
1623 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1624
1625 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1626 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1627 continue;
1628 };
1629
1630 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1631 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1632
1633 let mut actions_and_servers = Vec::new();
1634
1635 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1636 let actions_result = Self::get_server_code_actions_from_action_kinds(
1637 &lsp_store,
1638 language_server.server_id(),
1639 vec![code_action_kind.clone()],
1640 &buffer.handle,
1641 cx,
1642 )
1643 .await
1644 .with_context(|| {
1645 format!(
1646 "Failed to resolve code action {:?} with language server {}",
1647 code_action_kind,
1648 language_server.name()
1649 )
1650 });
1651 let Ok(actions) = actions_result else {
1652 // note: it may be better to set result to the error and break formatters here
1653 // but for now we try to execute the actions that we can resolve and skip the rest
1654 zlog::error!(
1655 logger =>
1656 "Failed to resolve code action {:?} with language server {}",
1657 code_action_kind,
1658 language_server.name()
1659 );
1660 continue;
1661 };
1662 for action in actions {
1663 actions_and_servers.push((action, index));
1664 }
1665 }
1666
1667 if actions_and_servers.is_empty() {
1668 zlog::warn!(logger => "No code actions were resolved, continuing");
1669 continue;
1670 }
1671
1672 'actions: for (mut action, server_index) in actions_and_servers {
1673 let server = &adapters_and_servers[server_index].1;
1674
1675 let describe_code_action = |action: &CodeAction| {
1676 format!(
1677 "code action '{}' with title \"{}\" on server {}",
1678 action
1679 .lsp_action
1680 .action_kind()
1681 .unwrap_or("unknown".into())
1682 .as_str(),
1683 action.lsp_action.title(),
1684 server.name(),
1685 )
1686 };
1687
1688 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1689
1690 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1691 zlog::error!(
1692 logger =>
1693 "Failed to resolve {}. Error: {}",
1694 describe_code_action(&action),
1695 err
1696 );
1697 continue;
1698 }
1699
1700 if let Some(edit) = action.lsp_action.edit().cloned() {
1701 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1702 // but filters out and logs warnings for code actions that require unreasonably
1703 // difficult handling on our part, such as:
1704 // - applying edits that call commands
1705 // which can result in arbitrary workspace edits being sent from the server that
1706 // have no way of being tied back to the command that initiated them (i.e. we
1707 // can't know which edits are part of the format request, or if the server is done sending
1708 // actions in response to the command)
1709 // - actions that create/delete/modify/rename files other than the one we are formatting
1710 // as we then would need to handle such changes correctly in the local history as well
1711 // as the remote history through the ProjectTransaction
1712 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1713 // Supporting these actions is not impossible, but not supported as of yet.
1714 if edit.changes.is_none() && edit.document_changes.is_none() {
1715 zlog::trace!(
1716 logger =>
1717 "No changes for code action. Skipping {}",
1718 describe_code_action(&action),
1719 );
1720 continue;
1721 }
1722
1723 let mut operations = Vec::new();
1724 if let Some(document_changes) = edit.document_changes {
1725 match document_changes {
1726 lsp::DocumentChanges::Edits(edits) => operations.extend(
1727 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1728 ),
1729 lsp::DocumentChanges::Operations(ops) => operations = ops,
1730 }
1731 } else if let Some(changes) = edit.changes {
1732 operations.extend(changes.into_iter().map(|(uri, edits)| {
1733 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1734 text_document:
1735 lsp::OptionalVersionedTextDocumentIdentifier {
1736 uri,
1737 version: None,
1738 },
1739 edits: edits.into_iter().map(Edit::Plain).collect(),
1740 })
1741 }));
1742 }
1743
1744 let mut edits = Vec::with_capacity(operations.len());
1745
1746 if operations.is_empty() {
1747 zlog::trace!(
1748 logger =>
1749 "No changes for code action. Skipping {}",
1750 describe_code_action(&action),
1751 );
1752 continue;
1753 }
1754 for operation in operations {
1755 let op = match operation {
1756 lsp::DocumentChangeOperation::Edit(op) => op,
1757 lsp::DocumentChangeOperation::Op(_) => {
1758 zlog::warn!(
1759 logger =>
1760 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1761 describe_code_action(&action),
1762 );
1763 continue 'actions;
1764 }
1765 };
1766 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1767 zlog::warn!(
1768 logger =>
1769 "Failed to convert URI '{:?}' to file path. Skipping {}",
1770 &op.text_document.uri,
1771 describe_code_action(&action),
1772 );
1773 continue 'actions;
1774 };
1775 if &file_path != buffer_path_abs {
1776 zlog::warn!(
1777 logger =>
1778 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1779 file_path,
1780 buffer_path_abs,
1781 describe_code_action(&action),
1782 );
1783 continue 'actions;
1784 }
1785
1786 let mut lsp_edits = Vec::new();
1787 for edit in op.edits {
1788 match edit {
1789 Edit::Plain(edit) => {
1790 if !lsp_edits.contains(&edit) {
1791 lsp_edits.push(edit);
1792 }
1793 }
1794 Edit::Annotated(edit) => {
1795 if !lsp_edits.contains(&edit.text_edit) {
1796 lsp_edits.push(edit.text_edit);
1797 }
1798 }
1799 Edit::Snippet(_) => {
1800 zlog::warn!(
1801 logger =>
1802 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1803 describe_code_action(&action),
1804 );
1805 continue 'actions;
1806 }
1807 }
1808 }
1809 let edits_result = lsp_store
1810 .update(cx, |lsp_store, cx| {
1811 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1812 &buffer.handle,
1813 lsp_edits,
1814 server.server_id(),
1815 op.text_document.version,
1816 cx,
1817 )
1818 })?
1819 .await;
1820 let Ok(resolved_edits) = edits_result else {
1821 zlog::warn!(
1822 logger =>
1823 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1824 buffer_path_abs.as_path(),
1825 describe_code_action(&action),
1826 );
1827 continue 'actions;
1828 };
1829 edits.extend(resolved_edits);
1830 }
1831
1832 if edits.is_empty() {
1833 zlog::warn!(logger => "No edits resolved from LSP");
1834 continue;
1835 }
1836
1837 extend_formatting_transaction(
1838 buffer,
1839 formatting_transaction_id,
1840 cx,
1841 |buffer, cx| {
1842 zlog::info!(
1843 "Applying edits {edits:?}. Content: {:?}",
1844 buffer.text()
1845 );
1846 buffer.edit(edits, None, cx);
1847 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1848 },
1849 )?;
1850 }
1851
1852 if let Some(command) = action.lsp_action.command() {
1853 zlog::warn!(
1854 logger =>
1855 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1856 &command.command,
1857 );
1858
1859 // bail early if command is invalid
1860 let server_capabilities = server.capabilities();
1861 let available_commands = server_capabilities
1862 .execute_command_provider
1863 .as_ref()
1864 .map(|options| options.commands.as_slice())
1865 .unwrap_or_default();
1866 if !available_commands.contains(&command.command) {
1867 zlog::warn!(
1868 logger =>
1869 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1870 command.command,
1871 server.name(),
1872 );
1873 continue;
1874 }
1875
1876 // noop so we just ensure buffer hasn't been edited since resolving code actions
1877 extend_formatting_transaction(
1878 buffer,
1879 formatting_transaction_id,
1880 cx,
1881 |_, _| {},
1882 )?;
1883 zlog::info!(logger => "Executing command {}", &command.command);
1884
1885 lsp_store.update(cx, |this, _| {
1886 this.as_local_mut()
1887 .unwrap()
1888 .last_workspace_edits_by_language_server
1889 .remove(&server.server_id());
1890 })?;
1891
1892 let execute_command_result = server
1893 .request::<lsp::request::ExecuteCommand>(
1894 lsp::ExecuteCommandParams {
1895 command: command.command.clone(),
1896 arguments: command.arguments.clone().unwrap_or_default(),
1897 ..Default::default()
1898 },
1899 )
1900 .await
1901 .into_response();
1902
1903 if execute_command_result.is_err() {
1904 zlog::error!(
1905 logger =>
1906 "Failed to execute command '{}' as part of {}",
1907 &command.command,
1908 describe_code_action(&action),
1909 );
1910 continue 'actions;
1911 }
1912
1913 let mut project_transaction_command =
1914 lsp_store.update(cx, |this, _| {
1915 this.as_local_mut()
1916 .unwrap()
1917 .last_workspace_edits_by_language_server
1918 .remove(&server.server_id())
1919 .unwrap_or_default()
1920 })?;
1921
1922 if let Some(transaction) =
1923 project_transaction_command.0.remove(&buffer.handle)
1924 {
1925 zlog::trace!(
1926 logger =>
1927 "Successfully captured {} edits that resulted from command {}",
1928 transaction.edit_ids.len(),
1929 &command.command,
1930 );
1931 let transaction_id_project_transaction = transaction.id;
1932 buffer.handle.update(cx, |buffer, _| {
1933 // it may have been removed from history if push_to_history was
1934 // false in deserialize_workspace_edit. If so push it so we
1935 // can merge it with the format transaction
1936 // and pop the combined transaction off the history stack
1937 // later if push_to_history is false
1938 if buffer.get_transaction(transaction.id).is_none() {
1939 buffer.push_transaction(transaction, Instant::now());
1940 }
1941 buffer.merge_transactions(
1942 transaction_id_project_transaction,
1943 formatting_transaction_id,
1944 );
1945 })?;
1946 }
1947
1948 if !project_transaction_command.0.is_empty() {
1949 let mut extra_buffers = String::new();
1950 for buffer in project_transaction_command.0.keys() {
1951 buffer
1952 .read_with(cx, |b, cx| {
1953 if let Some(path) = b.project_path(cx) {
1954 if !extra_buffers.is_empty() {
1955 extra_buffers.push_str(", ");
1956 }
1957 extra_buffers.push_str(path.path.as_unix_str());
1958 }
1959 })
1960 .ok();
1961 }
1962 zlog::warn!(
1963 logger =>
1964 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1965 &command.command,
1966 extra_buffers,
1967 );
1968 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1969 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1970 // add it so it's included, and merge it into the format transaction when its created later
1971 }
1972 }
1973 }
1974 }
1975 }
1976 }
1977
1978 Ok(())
1979 }
1980
1981 pub async fn format_ranges_via_lsp(
1982 this: &WeakEntity<LspStore>,
1983 buffer_handle: &Entity<Buffer>,
1984 ranges: &[Range<Anchor>],
1985 abs_path: &Path,
1986 language_server: &Arc<LanguageServer>,
1987 settings: &LanguageSettings,
1988 cx: &mut AsyncApp,
1989 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1990 let capabilities = &language_server.capabilities();
1991 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1992 if range_formatting_provider == Some(&OneOf::Left(false)) {
1993 anyhow::bail!(
1994 "{} language server does not support range formatting",
1995 language_server.name()
1996 );
1997 }
1998
1999 let uri = file_path_to_lsp_url(abs_path)?;
2000 let text_document = lsp::TextDocumentIdentifier::new(uri);
2001
2002 let lsp_edits = {
2003 let mut lsp_ranges = Vec::new();
2004 this.update(cx, |_this, cx| {
2005 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2006 // not have been sent to the language server. This seems like a fairly systemic
2007 // issue, though, the resolution probably is not specific to formatting.
2008 //
2009 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2010 // LSP.
2011 let snapshot = buffer_handle.read(cx).snapshot();
2012 for range in ranges {
2013 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2014 }
2015 anyhow::Ok(())
2016 })??;
2017
2018 let mut edits = None;
2019 for range in lsp_ranges {
2020 if let Some(mut edit) = language_server
2021 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2022 text_document: text_document.clone(),
2023 range,
2024 options: lsp_command::lsp_formatting_options(settings),
2025 work_done_progress_params: Default::default(),
2026 })
2027 .await
2028 .into_response()?
2029 {
2030 edits.get_or_insert_with(Vec::new).append(&mut edit);
2031 }
2032 }
2033 edits
2034 };
2035
2036 if let Some(lsp_edits) = lsp_edits {
2037 this.update(cx, |this, cx| {
2038 this.as_local_mut().unwrap().edits_from_lsp(
2039 buffer_handle,
2040 lsp_edits,
2041 language_server.server_id(),
2042 None,
2043 cx,
2044 )
2045 })?
2046 .await
2047 } else {
2048 Ok(Vec::with_capacity(0))
2049 }
2050 }
2051
2052 async fn format_via_lsp(
2053 this: &WeakEntity<LspStore>,
2054 buffer: &Entity<Buffer>,
2055 abs_path: &Path,
2056 language_server: &Arc<LanguageServer>,
2057 settings: &LanguageSettings,
2058 cx: &mut AsyncApp,
2059 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2060 let logger = zlog::scoped!("lsp_format");
2061 zlog::debug!(logger => "Formatting via LSP");
2062
2063 let uri = file_path_to_lsp_url(abs_path)?;
2064 let text_document = lsp::TextDocumentIdentifier::new(uri);
2065 let capabilities = &language_server.capabilities();
2066
2067 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2068 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2069
2070 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2071 let _timer = zlog::time!(logger => "format-full");
2072 language_server
2073 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2074 text_document,
2075 options: lsp_command::lsp_formatting_options(settings),
2076 work_done_progress_params: Default::default(),
2077 })
2078 .await
2079 .into_response()?
2080 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2081 let _timer = zlog::time!(logger => "format-range");
2082 let buffer_start = lsp::Position::new(0, 0);
2083 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2084 language_server
2085 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2086 text_document: text_document.clone(),
2087 range: lsp::Range::new(buffer_start, buffer_end),
2088 options: lsp_command::lsp_formatting_options(settings),
2089 work_done_progress_params: Default::default(),
2090 })
2091 .await
2092 .into_response()?
2093 } else {
2094 None
2095 };
2096
2097 if let Some(lsp_edits) = lsp_edits {
2098 this.update(cx, |this, cx| {
2099 this.as_local_mut().unwrap().edits_from_lsp(
2100 buffer,
2101 lsp_edits,
2102 language_server.server_id(),
2103 None,
2104 cx,
2105 )
2106 })?
2107 .await
2108 } else {
2109 Ok(Vec::with_capacity(0))
2110 }
2111 }
2112
2113 async fn format_via_external_command(
2114 buffer: &FormattableBuffer,
2115 command: &str,
2116 arguments: Option<&[String]>,
2117 cx: &mut AsyncApp,
2118 ) -> Result<Option<Diff>> {
2119 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2120 let file = File::from_dyn(buffer.file())?;
2121 let worktree = file.worktree.read(cx);
2122 let mut worktree_path = worktree.abs_path().to_path_buf();
2123 if worktree.root_entry()?.is_file() {
2124 worktree_path.pop();
2125 }
2126 Some(worktree_path)
2127 })?;
2128
2129 let mut child = util::command::new_smol_command(command);
2130
2131 if let Some(buffer_env) = buffer.env.as_ref() {
2132 child.envs(buffer_env);
2133 }
2134
2135 if let Some(working_dir_path) = working_dir_path {
2136 child.current_dir(working_dir_path);
2137 }
2138
2139 if let Some(arguments) = arguments {
2140 child.args(arguments.iter().map(|arg| {
2141 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2142 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2143 } else {
2144 arg.replace("{buffer_path}", "Untitled")
2145 }
2146 }));
2147 }
2148
2149 let mut child = child
2150 .stdin(smol::process::Stdio::piped())
2151 .stdout(smol::process::Stdio::piped())
2152 .stderr(smol::process::Stdio::piped())
2153 .spawn()?;
2154
2155 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2156 let text = buffer
2157 .handle
2158 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2159 for chunk in text.chunks() {
2160 stdin.write_all(chunk.as_bytes()).await?;
2161 }
2162 stdin.flush().await?;
2163
2164 let output = child.output().await?;
2165 anyhow::ensure!(
2166 output.status.success(),
2167 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2168 output.status.code(),
2169 String::from_utf8_lossy(&output.stdout),
2170 String::from_utf8_lossy(&output.stderr),
2171 );
2172
2173 let stdout = String::from_utf8(output.stdout)?;
2174 Ok(Some(
2175 buffer
2176 .handle
2177 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2178 .await,
2179 ))
2180 }
2181
2182 async fn try_resolve_code_action(
2183 lang_server: &LanguageServer,
2184 action: &mut CodeAction,
2185 ) -> anyhow::Result<()> {
2186 match &mut action.lsp_action {
2187 LspAction::Action(lsp_action) => {
2188 if !action.resolved
2189 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2190 && lsp_action.data.is_some()
2191 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2192 {
2193 *lsp_action = Box::new(
2194 lang_server
2195 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2196 .await
2197 .into_response()?,
2198 );
2199 }
2200 }
2201 LspAction::CodeLens(lens) => {
2202 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2203 *lens = lang_server
2204 .request::<lsp::request::CodeLensResolve>(lens.clone())
2205 .await
2206 .into_response()?;
2207 }
2208 }
2209 LspAction::Command(_) => {}
2210 }
2211
2212 action.resolved = true;
2213 anyhow::Ok(())
2214 }
2215
2216 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2217 let buffer = buffer_handle.read(cx);
2218
2219 let file = buffer.file().cloned();
2220
2221 let Some(file) = File::from_dyn(file.as_ref()) else {
2222 return;
2223 };
2224 if !file.is_local() {
2225 return;
2226 }
2227 let path = ProjectPath::from_file(file, cx);
2228 let worktree_id = file.worktree_id(cx);
2229 let language = buffer.language().cloned();
2230
2231 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2232 for (server_id, diagnostics) in
2233 diagnostics.get(file.path()).cloned().unwrap_or_default()
2234 {
2235 self.update_buffer_diagnostics(
2236 buffer_handle,
2237 server_id,
2238 None,
2239 None,
2240 diagnostics,
2241 Vec::new(),
2242 cx,
2243 )
2244 .log_err();
2245 }
2246 }
2247 let Some(language) = language else {
2248 return;
2249 };
2250 let Some(snapshot) = self
2251 .worktree_store
2252 .read(cx)
2253 .worktree_for_id(worktree_id, cx)
2254 .map(|worktree| worktree.read(cx).snapshot())
2255 else {
2256 return;
2257 };
2258 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2259
2260 for server_id in
2261 self.lsp_tree
2262 .get(path, language.name(), language.manifest(), &delegate, cx)
2263 {
2264 let server = self
2265 .language_servers
2266 .get(&server_id)
2267 .and_then(|server_state| {
2268 if let LanguageServerState::Running { server, .. } = server_state {
2269 Some(server.clone())
2270 } else {
2271 None
2272 }
2273 });
2274 let server = match server {
2275 Some(server) => server,
2276 None => continue,
2277 };
2278
2279 buffer_handle.update(cx, |buffer, cx| {
2280 buffer.set_completion_triggers(
2281 server.server_id(),
2282 server
2283 .capabilities()
2284 .completion_provider
2285 .as_ref()
2286 .and_then(|provider| {
2287 provider
2288 .trigger_characters
2289 .as_ref()
2290 .map(|characters| characters.iter().cloned().collect())
2291 })
2292 .unwrap_or_default(),
2293 cx,
2294 );
2295 });
2296 }
2297 }
2298
2299 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2300 buffer.update(cx, |buffer, cx| {
2301 let Some(language) = buffer.language() else {
2302 return;
2303 };
2304 let path = ProjectPath {
2305 worktree_id: old_file.worktree_id(cx),
2306 path: old_file.path.clone(),
2307 };
2308 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2309 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2310 buffer.set_completion_triggers(server_id, Default::default(), cx);
2311 }
2312 });
2313 }
2314
2315 fn update_buffer_diagnostics(
2316 &mut self,
2317 buffer: &Entity<Buffer>,
2318 server_id: LanguageServerId,
2319 result_id: Option<String>,
2320 version: Option<i32>,
2321 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2322 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2323 cx: &mut Context<LspStore>,
2324 ) -> Result<()> {
2325 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2326 Ordering::Equal
2327 .then_with(|| b.is_primary.cmp(&a.is_primary))
2328 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2329 .then_with(|| a.severity.cmp(&b.severity))
2330 .then_with(|| a.message.cmp(&b.message))
2331 }
2332
2333 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2334 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2335 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2336
2337 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2338 Ordering::Equal
2339 .then_with(|| a.range.start.cmp(&b.range.start))
2340 .then_with(|| b.range.end.cmp(&a.range.end))
2341 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2342 });
2343
2344 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2345
2346 let edits_since_save = std::cell::LazyCell::new(|| {
2347 let saved_version = buffer.read(cx).saved_version();
2348 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2349 });
2350
2351 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2352
2353 for (new_diagnostic, entry) in diagnostics {
2354 let start;
2355 let end;
2356 if new_diagnostic && entry.diagnostic.is_disk_based {
2357 // Some diagnostics are based on files on disk instead of buffers'
2358 // current contents. Adjust these diagnostics' ranges to reflect
2359 // any unsaved edits.
2360 // Do not alter the reused ones though, as their coordinates were stored as anchors
2361 // and were properly adjusted on reuse.
2362 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2363 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2364 } else {
2365 start = entry.range.start;
2366 end = entry.range.end;
2367 }
2368
2369 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2370 ..snapshot.clip_point_utf16(end, Bias::Right);
2371
2372 // Expand empty ranges by one codepoint
2373 if range.start == range.end {
2374 // This will be go to the next boundary when being clipped
2375 range.end.column += 1;
2376 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2377 if range.start == range.end && range.end.column > 0 {
2378 range.start.column -= 1;
2379 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2380 }
2381 }
2382
2383 sanitized_diagnostics.push(DiagnosticEntry {
2384 range,
2385 diagnostic: entry.diagnostic,
2386 });
2387 }
2388 drop(edits_since_save);
2389
2390 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2391 buffer.update(cx, |buffer, cx| {
2392 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2393 self.buffer_pull_diagnostics_result_ids
2394 .entry(server_id)
2395 .or_default()
2396 .insert(abs_path, result_id);
2397 }
2398
2399 buffer.update_diagnostics(server_id, set, cx)
2400 });
2401
2402 Ok(())
2403 }
2404
2405 fn register_language_server_for_invisible_worktree(
2406 &mut self,
2407 worktree: &Entity<Worktree>,
2408 language_server_id: LanguageServerId,
2409 cx: &mut App,
2410 ) {
2411 let worktree = worktree.read(cx);
2412 let worktree_id = worktree.id();
2413 debug_assert!(!worktree.is_visible());
2414 let Some(mut origin_seed) = self
2415 .language_server_ids
2416 .iter()
2417 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2418 else {
2419 return;
2420 };
2421 origin_seed.worktree_id = worktree_id;
2422 self.language_server_ids
2423 .entry(origin_seed)
2424 .or_insert_with(|| UnifiedLanguageServer {
2425 id: language_server_id,
2426 project_roots: Default::default(),
2427 });
2428 }
2429
2430 fn register_buffer_with_language_servers(
2431 &mut self,
2432 buffer_handle: &Entity<Buffer>,
2433 only_register_servers: HashSet<LanguageServerSelector>,
2434 cx: &mut Context<LspStore>,
2435 ) {
2436 let buffer = buffer_handle.read(cx);
2437 let buffer_id = buffer.remote_id();
2438
2439 let Some(file) = File::from_dyn(buffer.file()) else {
2440 return;
2441 };
2442 if !file.is_local() {
2443 return;
2444 }
2445
2446 let abs_path = file.abs_path(cx);
2447 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2448 return;
2449 };
2450 let initial_snapshot = buffer.text_snapshot();
2451 let worktree_id = file.worktree_id(cx);
2452
2453 let Some(language) = buffer.language().cloned() else {
2454 return;
2455 };
2456 let path: Arc<RelPath> = file
2457 .path()
2458 .parent()
2459 .map(Arc::from)
2460 .unwrap_or_else(|| file.path().clone());
2461 let Some(worktree) = self
2462 .worktree_store
2463 .read(cx)
2464 .worktree_for_id(worktree_id, cx)
2465 else {
2466 return;
2467 };
2468 let language_name = language.name();
2469 let (reused, delegate, servers) = self
2470 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2471 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2472 .unwrap_or_else(|| {
2473 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2474 let delegate: Arc<dyn ManifestDelegate> =
2475 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2476
2477 let servers = self
2478 .lsp_tree
2479 .walk(
2480 ProjectPath { worktree_id, path },
2481 language.name(),
2482 language.manifest(),
2483 &delegate,
2484 cx,
2485 )
2486 .collect::<Vec<_>>();
2487 (false, lsp_delegate, servers)
2488 });
2489 let servers_and_adapters = servers
2490 .into_iter()
2491 .filter_map(|server_node| {
2492 if reused && server_node.server_id().is_none() {
2493 return None;
2494 }
2495 if !only_register_servers.is_empty() {
2496 if let Some(server_id) = server_node.server_id()
2497 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2498 {
2499 return None;
2500 }
2501 if let Some(name) = server_node.name()
2502 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2503 {
2504 return None;
2505 }
2506 }
2507
2508 let server_id = server_node.server_id_or_init(|disposition| {
2509 let path = &disposition.path;
2510
2511 {
2512 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2513
2514 let server_id = self.get_or_insert_language_server(
2515 &worktree,
2516 delegate.clone(),
2517 disposition,
2518 &language_name,
2519 cx,
2520 );
2521
2522 if let Some(state) = self.language_servers.get(&server_id)
2523 && let Ok(uri) = uri
2524 {
2525 state.add_workspace_folder(uri);
2526 };
2527 server_id
2528 }
2529 })?;
2530 let server_state = self.language_servers.get(&server_id)?;
2531 if let LanguageServerState::Running {
2532 server, adapter, ..
2533 } = server_state
2534 {
2535 Some((server.clone(), adapter.clone()))
2536 } else {
2537 None
2538 }
2539 })
2540 .collect::<Vec<_>>();
2541 for (server, adapter) in servers_and_adapters {
2542 buffer_handle.update(cx, |buffer, cx| {
2543 buffer.set_completion_triggers(
2544 server.server_id(),
2545 server
2546 .capabilities()
2547 .completion_provider
2548 .as_ref()
2549 .and_then(|provider| {
2550 provider
2551 .trigger_characters
2552 .as_ref()
2553 .map(|characters| characters.iter().cloned().collect())
2554 })
2555 .unwrap_or_default(),
2556 cx,
2557 );
2558 });
2559
2560 let snapshot = LspBufferSnapshot {
2561 version: 0,
2562 snapshot: initial_snapshot.clone(),
2563 };
2564
2565 let mut registered = false;
2566 self.buffer_snapshots
2567 .entry(buffer_id)
2568 .or_default()
2569 .entry(server.server_id())
2570 .or_insert_with(|| {
2571 registered = true;
2572 server.register_buffer(
2573 uri.clone(),
2574 adapter.language_id(&language.name()),
2575 0,
2576 initial_snapshot.text(),
2577 );
2578
2579 vec![snapshot]
2580 });
2581
2582 self.buffers_opened_in_servers
2583 .entry(buffer_id)
2584 .or_default()
2585 .insert(server.server_id());
2586 if registered {
2587 cx.emit(LspStoreEvent::LanguageServerUpdate {
2588 language_server_id: server.server_id(),
2589 name: None,
2590 message: proto::update_language_server::Variant::RegisteredForBuffer(
2591 proto::RegisteredForBuffer {
2592 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2593 buffer_id: buffer_id.to_proto(),
2594 },
2595 ),
2596 });
2597 }
2598 }
2599 }
2600
2601 fn reuse_existing_language_server<'lang_name>(
2602 &self,
2603 server_tree: &LanguageServerTree,
2604 worktree: &Entity<Worktree>,
2605 language_name: &'lang_name LanguageName,
2606 cx: &mut App,
2607 ) -> Option<(
2608 Arc<LocalLspAdapterDelegate>,
2609 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2610 )> {
2611 if worktree.read(cx).is_visible() {
2612 return None;
2613 }
2614
2615 let worktree_store = self.worktree_store.read(cx);
2616 let servers = server_tree
2617 .instances
2618 .iter()
2619 .filter(|(worktree_id, _)| {
2620 worktree_store
2621 .worktree_for_id(**worktree_id, cx)
2622 .is_some_and(|worktree| worktree.read(cx).is_visible())
2623 })
2624 .flat_map(|(worktree_id, servers)| {
2625 servers
2626 .roots
2627 .iter()
2628 .flat_map(|(_, language_servers)| language_servers)
2629 .map(move |(_, (server_node, server_languages))| {
2630 (worktree_id, server_node, server_languages)
2631 })
2632 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2633 .map(|(worktree_id, server_node, _)| {
2634 (
2635 *worktree_id,
2636 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2637 )
2638 })
2639 })
2640 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2641 acc.entry(worktree_id)
2642 .or_insert_with(Vec::new)
2643 .push(server_node);
2644 acc
2645 })
2646 .into_values()
2647 .max_by_key(|servers| servers.len())?;
2648
2649 let worktree_id = worktree.read(cx).id();
2650 let apply = move |tree: &mut LanguageServerTree| {
2651 for server_node in &servers {
2652 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2653 }
2654 servers
2655 };
2656
2657 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2658 Some((delegate, apply))
2659 }
2660
2661 pub(crate) fn unregister_old_buffer_from_language_servers(
2662 &mut self,
2663 buffer: &Entity<Buffer>,
2664 old_file: &File,
2665 cx: &mut App,
2666 ) {
2667 let old_path = match old_file.as_local() {
2668 Some(local) => local.abs_path(cx),
2669 None => return,
2670 };
2671
2672 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2673 debug_panic!("{old_path:?} is not parseable as an URI");
2674 return;
2675 };
2676 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2677 }
2678
2679 pub(crate) fn unregister_buffer_from_language_servers(
2680 &mut self,
2681 buffer: &Entity<Buffer>,
2682 file_url: &lsp::Uri,
2683 cx: &mut App,
2684 ) {
2685 buffer.update(cx, |buffer, cx| {
2686 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2687
2688 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2689 language_server.unregister_buffer(file_url.clone());
2690 }
2691 });
2692 }
2693
2694 fn buffer_snapshot_for_lsp_version(
2695 &mut self,
2696 buffer: &Entity<Buffer>,
2697 server_id: LanguageServerId,
2698 version: Option<i32>,
2699 cx: &App,
2700 ) -> Result<TextBufferSnapshot> {
2701 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2702
2703 if let Some(version) = version {
2704 let buffer_id = buffer.read(cx).remote_id();
2705 let snapshots = if let Some(snapshots) = self
2706 .buffer_snapshots
2707 .get_mut(&buffer_id)
2708 .and_then(|m| m.get_mut(&server_id))
2709 {
2710 snapshots
2711 } else if version == 0 {
2712 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2713 // We detect this case and treat it as if the version was `None`.
2714 return Ok(buffer.read(cx).text_snapshot());
2715 } else {
2716 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2717 };
2718
2719 let found_snapshot = snapshots
2720 .binary_search_by_key(&version, |e| e.version)
2721 .map(|ix| snapshots[ix].snapshot.clone())
2722 .map_err(|_| {
2723 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2724 })?;
2725
2726 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2727 Ok(found_snapshot)
2728 } else {
2729 Ok((buffer.read(cx)).text_snapshot())
2730 }
2731 }
2732
2733 async fn get_server_code_actions_from_action_kinds(
2734 lsp_store: &WeakEntity<LspStore>,
2735 language_server_id: LanguageServerId,
2736 code_action_kinds: Vec<lsp::CodeActionKind>,
2737 buffer: &Entity<Buffer>,
2738 cx: &mut AsyncApp,
2739 ) -> Result<Vec<CodeAction>> {
2740 let actions = lsp_store
2741 .update(cx, move |this, cx| {
2742 let request = GetCodeActions {
2743 range: text::Anchor::MIN..text::Anchor::MAX,
2744 kinds: Some(code_action_kinds),
2745 };
2746 let server = LanguageServerToQuery::Other(language_server_id);
2747 this.request_lsp(buffer.clone(), server, request, cx)
2748 })?
2749 .await?;
2750 Ok(actions)
2751 }
2752
2753 pub async fn execute_code_actions_on_server(
2754 lsp_store: &WeakEntity<LspStore>,
2755 language_server: &Arc<LanguageServer>,
2756
2757 actions: Vec<CodeAction>,
2758 push_to_history: bool,
2759 project_transaction: &mut ProjectTransaction,
2760 cx: &mut AsyncApp,
2761 ) -> anyhow::Result<()> {
2762 for mut action in actions {
2763 Self::try_resolve_code_action(language_server, &mut action)
2764 .await
2765 .context("resolving a formatting code action")?;
2766
2767 if let Some(edit) = action.lsp_action.edit() {
2768 if edit.changes.is_none() && edit.document_changes.is_none() {
2769 continue;
2770 }
2771
2772 let new = Self::deserialize_workspace_edit(
2773 lsp_store.upgrade().context("project dropped")?,
2774 edit.clone(),
2775 push_to_history,
2776 language_server.clone(),
2777 cx,
2778 )
2779 .await?;
2780 project_transaction.0.extend(new.0);
2781 }
2782
2783 if let Some(command) = action.lsp_action.command() {
2784 let server_capabilities = language_server.capabilities();
2785 let available_commands = server_capabilities
2786 .execute_command_provider
2787 .as_ref()
2788 .map(|options| options.commands.as_slice())
2789 .unwrap_or_default();
2790 if available_commands.contains(&command.command) {
2791 lsp_store.update(cx, |lsp_store, _| {
2792 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2793 mode.last_workspace_edits_by_language_server
2794 .remove(&language_server.server_id());
2795 }
2796 })?;
2797
2798 language_server
2799 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2800 command: command.command.clone(),
2801 arguments: command.arguments.clone().unwrap_or_default(),
2802 ..Default::default()
2803 })
2804 .await
2805 .into_response()
2806 .context("execute command")?;
2807
2808 lsp_store.update(cx, |this, _| {
2809 if let LspStoreMode::Local(mode) = &mut this.mode {
2810 project_transaction.0.extend(
2811 mode.last_workspace_edits_by_language_server
2812 .remove(&language_server.server_id())
2813 .unwrap_or_default()
2814 .0,
2815 )
2816 }
2817 })?;
2818 } else {
2819 log::warn!(
2820 "Cannot execute a command {} not listed in the language server capabilities",
2821 command.command
2822 )
2823 }
2824 }
2825 }
2826 Ok(())
2827 }
2828
2829 pub async fn deserialize_text_edits(
2830 this: Entity<LspStore>,
2831 buffer_to_edit: Entity<Buffer>,
2832 edits: Vec<lsp::TextEdit>,
2833 push_to_history: bool,
2834 _: Arc<CachedLspAdapter>,
2835 language_server: Arc<LanguageServer>,
2836 cx: &mut AsyncApp,
2837 ) -> Result<Option<Transaction>> {
2838 let edits = this
2839 .update(cx, |this, cx| {
2840 this.as_local_mut().unwrap().edits_from_lsp(
2841 &buffer_to_edit,
2842 edits,
2843 language_server.server_id(),
2844 None,
2845 cx,
2846 )
2847 })?
2848 .await?;
2849
2850 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2851 buffer.finalize_last_transaction();
2852 buffer.start_transaction();
2853 for (range, text) in edits {
2854 buffer.edit([(range, text)], None, cx);
2855 }
2856
2857 if buffer.end_transaction(cx).is_some() {
2858 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2859 if !push_to_history {
2860 buffer.forget_transaction(transaction.id);
2861 }
2862 Some(transaction)
2863 } else {
2864 None
2865 }
2866 })?;
2867
2868 Ok(transaction)
2869 }
2870
2871 #[allow(clippy::type_complexity)]
2872 pub(crate) fn edits_from_lsp(
2873 &mut self,
2874 buffer: &Entity<Buffer>,
2875 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2876 server_id: LanguageServerId,
2877 version: Option<i32>,
2878 cx: &mut Context<LspStore>,
2879 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2880 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2881 cx.background_spawn(async move {
2882 let snapshot = snapshot?;
2883 let mut lsp_edits = lsp_edits
2884 .into_iter()
2885 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2886 .collect::<Vec<_>>();
2887
2888 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2889
2890 let mut lsp_edits = lsp_edits.into_iter().peekable();
2891 let mut edits = Vec::new();
2892 while let Some((range, mut new_text)) = lsp_edits.next() {
2893 // Clip invalid ranges provided by the language server.
2894 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2895 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2896
2897 // Combine any LSP edits that are adjacent.
2898 //
2899 // Also, combine LSP edits that are separated from each other by only
2900 // a newline. This is important because for some code actions,
2901 // Rust-analyzer rewrites the entire buffer via a series of edits that
2902 // are separated by unchanged newline characters.
2903 //
2904 // In order for the diffing logic below to work properly, any edits that
2905 // cancel each other out must be combined into one.
2906 while let Some((next_range, next_text)) = lsp_edits.peek() {
2907 if next_range.start.0 > range.end {
2908 if next_range.start.0.row > range.end.row + 1
2909 || next_range.start.0.column > 0
2910 || snapshot.clip_point_utf16(
2911 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2912 Bias::Left,
2913 ) > range.end
2914 {
2915 break;
2916 }
2917 new_text.push('\n');
2918 }
2919 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2920 new_text.push_str(next_text);
2921 lsp_edits.next();
2922 }
2923
2924 // For multiline edits, perform a diff of the old and new text so that
2925 // we can identify the changes more precisely, preserving the locations
2926 // of any anchors positioned in the unchanged regions.
2927 if range.end.row > range.start.row {
2928 let offset = range.start.to_offset(&snapshot);
2929 let old_text = snapshot.text_for_range(range).collect::<String>();
2930 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2931 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2932 (
2933 snapshot.anchor_after(offset + range.start)
2934 ..snapshot.anchor_before(offset + range.end),
2935 replacement,
2936 )
2937 }));
2938 } else if range.end == range.start {
2939 let anchor = snapshot.anchor_after(range.start);
2940 edits.push((anchor..anchor, new_text.into()));
2941 } else {
2942 let edit_start = snapshot.anchor_after(range.start);
2943 let edit_end = snapshot.anchor_before(range.end);
2944 edits.push((edit_start..edit_end, new_text.into()));
2945 }
2946 }
2947
2948 Ok(edits)
2949 })
2950 }
2951
2952 pub(crate) async fn deserialize_workspace_edit(
2953 this: Entity<LspStore>,
2954 edit: lsp::WorkspaceEdit,
2955 push_to_history: bool,
2956 language_server: Arc<LanguageServer>,
2957 cx: &mut AsyncApp,
2958 ) -> Result<ProjectTransaction> {
2959 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2960
2961 let mut operations = Vec::new();
2962 if let Some(document_changes) = edit.document_changes {
2963 match document_changes {
2964 lsp::DocumentChanges::Edits(edits) => {
2965 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2966 }
2967 lsp::DocumentChanges::Operations(ops) => operations = ops,
2968 }
2969 } else if let Some(changes) = edit.changes {
2970 operations.extend(changes.into_iter().map(|(uri, edits)| {
2971 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2972 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2973 uri,
2974 version: None,
2975 },
2976 edits: edits.into_iter().map(Edit::Plain).collect(),
2977 })
2978 }));
2979 }
2980
2981 let mut project_transaction = ProjectTransaction::default();
2982 for operation in operations {
2983 match operation {
2984 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2985 let abs_path = op
2986 .uri
2987 .to_file_path()
2988 .map_err(|()| anyhow!("can't convert URI to path"))?;
2989
2990 if let Some(parent_path) = abs_path.parent() {
2991 fs.create_dir(parent_path).await?;
2992 }
2993 if abs_path.ends_with("/") {
2994 fs.create_dir(&abs_path).await?;
2995 } else {
2996 fs.create_file(
2997 &abs_path,
2998 op.options
2999 .map(|options| fs::CreateOptions {
3000 overwrite: options.overwrite.unwrap_or(false),
3001 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3002 })
3003 .unwrap_or_default(),
3004 )
3005 .await?;
3006 }
3007 }
3008
3009 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3010 let source_abs_path = op
3011 .old_uri
3012 .to_file_path()
3013 .map_err(|()| anyhow!("can't convert URI to path"))?;
3014 let target_abs_path = op
3015 .new_uri
3016 .to_file_path()
3017 .map_err(|()| anyhow!("can't convert URI to path"))?;
3018 fs.rename(
3019 &source_abs_path,
3020 &target_abs_path,
3021 op.options
3022 .map(|options| fs::RenameOptions {
3023 overwrite: options.overwrite.unwrap_or(false),
3024 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3025 })
3026 .unwrap_or_default(),
3027 )
3028 .await?;
3029 }
3030
3031 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3032 let abs_path = op
3033 .uri
3034 .to_file_path()
3035 .map_err(|()| anyhow!("can't convert URI to path"))?;
3036 let options = op
3037 .options
3038 .map(|options| fs::RemoveOptions {
3039 recursive: options.recursive.unwrap_or(false),
3040 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3041 })
3042 .unwrap_or_default();
3043 if abs_path.ends_with("/") {
3044 fs.remove_dir(&abs_path, options).await?;
3045 } else {
3046 fs.remove_file(&abs_path, options).await?;
3047 }
3048 }
3049
3050 lsp::DocumentChangeOperation::Edit(op) => {
3051 let buffer_to_edit = this
3052 .update(cx, |this, cx| {
3053 this.open_local_buffer_via_lsp(
3054 op.text_document.uri.clone(),
3055 language_server.server_id(),
3056 cx,
3057 )
3058 })?
3059 .await?;
3060
3061 let edits = this
3062 .update(cx, |this, cx| {
3063 let path = buffer_to_edit.read(cx).project_path(cx);
3064 let active_entry = this.active_entry;
3065 let is_active_entry = path.is_some_and(|project_path| {
3066 this.worktree_store
3067 .read(cx)
3068 .entry_for_path(&project_path, cx)
3069 .is_some_and(|entry| Some(entry.id) == active_entry)
3070 });
3071 let local = this.as_local_mut().unwrap();
3072
3073 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3074 for edit in op.edits {
3075 match edit {
3076 Edit::Plain(edit) => {
3077 if !edits.contains(&edit) {
3078 edits.push(edit)
3079 }
3080 }
3081 Edit::Annotated(edit) => {
3082 if !edits.contains(&edit.text_edit) {
3083 edits.push(edit.text_edit)
3084 }
3085 }
3086 Edit::Snippet(edit) => {
3087 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3088 else {
3089 continue;
3090 };
3091
3092 if is_active_entry {
3093 snippet_edits.push((edit.range, snippet));
3094 } else {
3095 // Since this buffer is not focused, apply a normal edit.
3096 let new_edit = TextEdit {
3097 range: edit.range,
3098 new_text: snippet.text,
3099 };
3100 if !edits.contains(&new_edit) {
3101 edits.push(new_edit);
3102 }
3103 }
3104 }
3105 }
3106 }
3107 if !snippet_edits.is_empty() {
3108 let buffer_id = buffer_to_edit.read(cx).remote_id();
3109 let version = if let Some(buffer_version) = op.text_document.version
3110 {
3111 local
3112 .buffer_snapshot_for_lsp_version(
3113 &buffer_to_edit,
3114 language_server.server_id(),
3115 Some(buffer_version),
3116 cx,
3117 )
3118 .ok()
3119 .map(|snapshot| snapshot.version)
3120 } else {
3121 Some(buffer_to_edit.read(cx).saved_version().clone())
3122 };
3123
3124 let most_recent_edit =
3125 version.and_then(|version| version.most_recent());
3126 // Check if the edit that triggered that edit has been made by this participant.
3127
3128 if let Some(most_recent_edit) = most_recent_edit {
3129 cx.emit(LspStoreEvent::SnippetEdit {
3130 buffer_id,
3131 edits: snippet_edits,
3132 most_recent_edit,
3133 });
3134 }
3135 }
3136
3137 local.edits_from_lsp(
3138 &buffer_to_edit,
3139 edits,
3140 language_server.server_id(),
3141 op.text_document.version,
3142 cx,
3143 )
3144 })?
3145 .await?;
3146
3147 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3148 buffer.finalize_last_transaction();
3149 buffer.start_transaction();
3150 for (range, text) in edits {
3151 buffer.edit([(range, text)], None, cx);
3152 }
3153
3154 buffer.end_transaction(cx).and_then(|transaction_id| {
3155 if push_to_history {
3156 buffer.finalize_last_transaction();
3157 buffer.get_transaction(transaction_id).cloned()
3158 } else {
3159 buffer.forget_transaction(transaction_id)
3160 }
3161 })
3162 })?;
3163 if let Some(transaction) = transaction {
3164 project_transaction.0.insert(buffer_to_edit, transaction);
3165 }
3166 }
3167 }
3168 }
3169
3170 Ok(project_transaction)
3171 }
3172
3173 async fn on_lsp_workspace_edit(
3174 this: WeakEntity<LspStore>,
3175 params: lsp::ApplyWorkspaceEditParams,
3176 server_id: LanguageServerId,
3177 cx: &mut AsyncApp,
3178 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3179 let this = this.upgrade().context("project project closed")?;
3180 let language_server = this
3181 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3182 .context("language server not found")?;
3183 let transaction = Self::deserialize_workspace_edit(
3184 this.clone(),
3185 params.edit,
3186 true,
3187 language_server.clone(),
3188 cx,
3189 )
3190 .await
3191 .log_err();
3192 this.update(cx, |this, _| {
3193 if let Some(transaction) = transaction {
3194 this.as_local_mut()
3195 .unwrap()
3196 .last_workspace_edits_by_language_server
3197 .insert(server_id, transaction);
3198 }
3199 })?;
3200 Ok(lsp::ApplyWorkspaceEditResponse {
3201 applied: true,
3202 failed_change: None,
3203 failure_reason: None,
3204 })
3205 }
3206
3207 fn remove_worktree(
3208 &mut self,
3209 id_to_remove: WorktreeId,
3210 cx: &mut Context<LspStore>,
3211 ) -> Vec<LanguageServerId> {
3212 self.diagnostics.remove(&id_to_remove);
3213 self.prettier_store.update(cx, |prettier_store, cx| {
3214 prettier_store.remove_worktree(id_to_remove, cx);
3215 });
3216
3217 let mut servers_to_remove = BTreeSet::default();
3218 let mut servers_to_preserve = HashSet::default();
3219 for (seed, state) in &self.language_server_ids {
3220 if seed.worktree_id == id_to_remove {
3221 servers_to_remove.insert(state.id);
3222 } else {
3223 servers_to_preserve.insert(state.id);
3224 }
3225 }
3226 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3227 self.language_server_ids
3228 .retain(|_, state| !servers_to_remove.contains(&state.id));
3229 for server_id_to_remove in &servers_to_remove {
3230 self.language_server_watched_paths
3231 .remove(server_id_to_remove);
3232 self.language_server_paths_watched_for_rename
3233 .remove(server_id_to_remove);
3234 self.last_workspace_edits_by_language_server
3235 .remove(server_id_to_remove);
3236 self.language_servers.remove(server_id_to_remove);
3237 self.buffer_pull_diagnostics_result_ids
3238 .remove(server_id_to_remove);
3239 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3240 buffer_servers.remove(server_id_to_remove);
3241 }
3242 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3243 }
3244 servers_to_remove.into_iter().collect()
3245 }
3246
3247 fn rebuild_watched_paths_inner<'a>(
3248 &'a self,
3249 language_server_id: LanguageServerId,
3250 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3251 cx: &mut Context<LspStore>,
3252 ) -> LanguageServerWatchedPathsBuilder {
3253 let worktrees = self
3254 .worktree_store
3255 .read(cx)
3256 .worktrees()
3257 .filter_map(|worktree| {
3258 self.language_servers_for_worktree(worktree.read(cx).id())
3259 .find(|server| server.server_id() == language_server_id)
3260 .map(|_| worktree)
3261 })
3262 .collect::<Vec<_>>();
3263
3264 let mut worktree_globs = HashMap::default();
3265 let mut abs_globs = HashMap::default();
3266 log::trace!(
3267 "Processing new watcher paths for language server with id {}",
3268 language_server_id
3269 );
3270
3271 for watcher in watchers {
3272 if let Some((worktree, literal_prefix, pattern)) =
3273 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3274 {
3275 worktree.update(cx, |worktree, _| {
3276 if let Some((tree, glob)) =
3277 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3278 {
3279 tree.add_path_prefix_to_scan(literal_prefix);
3280 worktree_globs
3281 .entry(tree.id())
3282 .or_insert_with(GlobSetBuilder::new)
3283 .add(glob);
3284 }
3285 });
3286 } else {
3287 let (path, pattern) = match &watcher.glob_pattern {
3288 lsp::GlobPattern::String(s) => {
3289 let watcher_path = SanitizedPath::new(s);
3290 let path = glob_literal_prefix(watcher_path.as_path());
3291 let pattern = watcher_path
3292 .as_path()
3293 .strip_prefix(&path)
3294 .map(|p| p.to_string_lossy().into_owned())
3295 .unwrap_or_else(|e| {
3296 debug_panic!(
3297 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3298 s,
3299 path.display(),
3300 e
3301 );
3302 watcher_path.as_path().to_string_lossy().into_owned()
3303 });
3304 (path, pattern)
3305 }
3306 lsp::GlobPattern::Relative(rp) => {
3307 let Ok(mut base_uri) = match &rp.base_uri {
3308 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3309 lsp::OneOf::Right(base_uri) => base_uri,
3310 }
3311 .to_file_path() else {
3312 continue;
3313 };
3314
3315 let path = glob_literal_prefix(Path::new(&rp.pattern));
3316 let pattern = Path::new(&rp.pattern)
3317 .strip_prefix(&path)
3318 .map(|p| p.to_string_lossy().into_owned())
3319 .unwrap_or_else(|e| {
3320 debug_panic!(
3321 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3322 rp.pattern,
3323 path.display(),
3324 e
3325 );
3326 rp.pattern.clone()
3327 });
3328 base_uri.push(path);
3329 (base_uri, pattern)
3330 }
3331 };
3332
3333 if let Some(glob) = Glob::new(&pattern).log_err() {
3334 if !path
3335 .components()
3336 .any(|c| matches!(c, path::Component::Normal(_)))
3337 {
3338 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3339 // rather than adding a new watcher for `/`.
3340 for worktree in &worktrees {
3341 worktree_globs
3342 .entry(worktree.read(cx).id())
3343 .or_insert_with(GlobSetBuilder::new)
3344 .add(glob.clone());
3345 }
3346 } else {
3347 abs_globs
3348 .entry(path.into())
3349 .or_insert_with(GlobSetBuilder::new)
3350 .add(glob);
3351 }
3352 }
3353 }
3354 }
3355
3356 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3357 for (worktree_id, builder) in worktree_globs {
3358 if let Ok(globset) = builder.build() {
3359 watch_builder.watch_worktree(worktree_id, globset);
3360 }
3361 }
3362 for (abs_path, builder) in abs_globs {
3363 if let Ok(globset) = builder.build() {
3364 watch_builder.watch_abs_path(abs_path, globset);
3365 }
3366 }
3367 watch_builder
3368 }
3369
3370 fn worktree_and_path_for_file_watcher(
3371 worktrees: &[Entity<Worktree>],
3372 watcher: &FileSystemWatcher,
3373 cx: &App,
3374 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3375 worktrees.iter().find_map(|worktree| {
3376 let tree = worktree.read(cx);
3377 let worktree_root_path = tree.abs_path();
3378 let path_style = tree.path_style();
3379 match &watcher.glob_pattern {
3380 lsp::GlobPattern::String(s) => {
3381 let watcher_path = SanitizedPath::new(s);
3382 let relative = watcher_path
3383 .as_path()
3384 .strip_prefix(&worktree_root_path)
3385 .ok()?;
3386 let literal_prefix = glob_literal_prefix(relative);
3387 Some((
3388 worktree.clone(),
3389 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3390 relative.to_string_lossy().into_owned(),
3391 ))
3392 }
3393 lsp::GlobPattern::Relative(rp) => {
3394 let base_uri = match &rp.base_uri {
3395 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3396 lsp::OneOf::Right(base_uri) => base_uri,
3397 }
3398 .to_file_path()
3399 .ok()?;
3400 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3401 let mut literal_prefix = relative.to_owned();
3402 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3403 Some((
3404 worktree.clone(),
3405 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3406 rp.pattern.clone(),
3407 ))
3408 }
3409 }
3410 })
3411 }
3412
3413 fn rebuild_watched_paths(
3414 &mut self,
3415 language_server_id: LanguageServerId,
3416 cx: &mut Context<LspStore>,
3417 ) {
3418 let Some(registrations) = self
3419 .language_server_dynamic_registrations
3420 .get(&language_server_id)
3421 else {
3422 return;
3423 };
3424
3425 let watch_builder = self.rebuild_watched_paths_inner(
3426 language_server_id,
3427 registrations.did_change_watched_files.values().flatten(),
3428 cx,
3429 );
3430 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3431 self.language_server_watched_paths
3432 .insert(language_server_id, watcher);
3433
3434 cx.notify();
3435 }
3436
3437 fn on_lsp_did_change_watched_files(
3438 &mut self,
3439 language_server_id: LanguageServerId,
3440 registration_id: &str,
3441 params: DidChangeWatchedFilesRegistrationOptions,
3442 cx: &mut Context<LspStore>,
3443 ) {
3444 let registrations = self
3445 .language_server_dynamic_registrations
3446 .entry(language_server_id)
3447 .or_default();
3448
3449 registrations
3450 .did_change_watched_files
3451 .insert(registration_id.to_string(), params.watchers);
3452
3453 self.rebuild_watched_paths(language_server_id, cx);
3454 }
3455
3456 fn on_lsp_unregister_did_change_watched_files(
3457 &mut self,
3458 language_server_id: LanguageServerId,
3459 registration_id: &str,
3460 cx: &mut Context<LspStore>,
3461 ) {
3462 let registrations = self
3463 .language_server_dynamic_registrations
3464 .entry(language_server_id)
3465 .or_default();
3466
3467 if registrations
3468 .did_change_watched_files
3469 .remove(registration_id)
3470 .is_some()
3471 {
3472 log::info!(
3473 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3474 language_server_id,
3475 registration_id
3476 );
3477 } else {
3478 log::warn!(
3479 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3480 language_server_id,
3481 registration_id
3482 );
3483 }
3484
3485 self.rebuild_watched_paths(language_server_id, cx);
3486 }
3487
3488 async fn initialization_options_for_adapter(
3489 adapter: Arc<dyn LspAdapter>,
3490 delegate: &Arc<dyn LspAdapterDelegate>,
3491 ) -> Result<Option<serde_json::Value>> {
3492 let Some(mut initialization_config) =
3493 adapter.clone().initialization_options(delegate).await?
3494 else {
3495 return Ok(None);
3496 };
3497
3498 for other_adapter in delegate.registered_lsp_adapters() {
3499 if other_adapter.name() == adapter.name() {
3500 continue;
3501 }
3502 if let Ok(Some(target_config)) = other_adapter
3503 .clone()
3504 .additional_initialization_options(adapter.name(), delegate)
3505 .await
3506 {
3507 merge_json_value_into(target_config.clone(), &mut initialization_config);
3508 }
3509 }
3510
3511 Ok(Some(initialization_config))
3512 }
3513
3514 async fn workspace_configuration_for_adapter(
3515 adapter: Arc<dyn LspAdapter>,
3516 delegate: &Arc<dyn LspAdapterDelegate>,
3517 toolchain: Option<Toolchain>,
3518 cx: &mut AsyncApp,
3519 ) -> Result<serde_json::Value> {
3520 let mut workspace_config = adapter
3521 .clone()
3522 .workspace_configuration(delegate, toolchain, cx)
3523 .await?;
3524
3525 for other_adapter in delegate.registered_lsp_adapters() {
3526 if other_adapter.name() == adapter.name() {
3527 continue;
3528 }
3529 if let Ok(Some(target_config)) = other_adapter
3530 .clone()
3531 .additional_workspace_configuration(adapter.name(), delegate, cx)
3532 .await
3533 {
3534 merge_json_value_into(target_config.clone(), &mut workspace_config);
3535 }
3536 }
3537
3538 Ok(workspace_config)
3539 }
3540
3541 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3542 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3543 Some(server.clone())
3544 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3545 Some(Arc::clone(server))
3546 } else {
3547 None
3548 }
3549 }
3550}
3551
3552fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3553 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3554 cx.emit(LspStoreEvent::LanguageServerUpdate {
3555 language_server_id: server.server_id(),
3556 name: Some(server.name()),
3557 message: proto::update_language_server::Variant::MetadataUpdated(
3558 proto::ServerMetadataUpdated {
3559 capabilities: Some(capabilities),
3560 },
3561 ),
3562 });
3563 }
3564}
3565
3566#[derive(Debug)]
3567pub struct FormattableBuffer {
3568 handle: Entity<Buffer>,
3569 abs_path: Option<PathBuf>,
3570 env: Option<HashMap<String, String>>,
3571 ranges: Option<Vec<Range<Anchor>>>,
3572}
3573
3574pub struct RemoteLspStore {
3575 upstream_client: Option<AnyProtoClient>,
3576 upstream_project_id: u64,
3577}
3578
3579pub(crate) enum LspStoreMode {
3580 Local(LocalLspStore), // ssh host and collab host
3581 Remote(RemoteLspStore), // collab guest
3582}
3583
3584impl LspStoreMode {
3585 fn is_local(&self) -> bool {
3586 matches!(self, LspStoreMode::Local(_))
3587 }
3588}
3589
3590pub struct LspStore {
3591 mode: LspStoreMode,
3592 last_formatting_failure: Option<String>,
3593 downstream_client: Option<(AnyProtoClient, u64)>,
3594 nonce: u128,
3595 buffer_store: Entity<BufferStore>,
3596 worktree_store: Entity<WorktreeStore>,
3597 pub languages: Arc<LanguageRegistry>,
3598 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3599 active_entry: Option<ProjectEntryId>,
3600 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3601 _maintain_buffer_languages: Task<()>,
3602 diagnostic_summaries:
3603 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3604 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3605 lsp_data: HashMap<BufferId, BufferLspData>,
3606 next_hint_id: Arc<AtomicUsize>,
3607}
3608
3609#[derive(Debug)]
3610pub struct BufferLspData {
3611 buffer_version: Global,
3612 document_colors: Option<DocumentColorData>,
3613 code_lens: Option<CodeLensData>,
3614 inlay_hints: BufferInlayHints,
3615 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3616 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3617}
3618
3619#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3620struct LspKey {
3621 request_type: TypeId,
3622 server_queried: Option<LanguageServerId>,
3623}
3624
3625impl BufferLspData {
3626 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3627 Self {
3628 buffer_version: buffer.read(cx).version(),
3629 document_colors: None,
3630 code_lens: None,
3631 inlay_hints: BufferInlayHints::new(buffer, cx),
3632 lsp_requests: HashMap::default(),
3633 chunk_lsp_requests: HashMap::default(),
3634 }
3635 }
3636
3637 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3638 if let Some(document_colors) = &mut self.document_colors {
3639 document_colors.colors.remove(&for_server);
3640 document_colors.cache_version += 1;
3641 }
3642
3643 if let Some(code_lens) = &mut self.code_lens {
3644 code_lens.lens.remove(&for_server);
3645 }
3646
3647 self.inlay_hints.remove_server_data(for_server);
3648 }
3649
3650 #[cfg(any(test, feature = "test-support"))]
3651 pub fn inlay_hints(&self) -> &BufferInlayHints {
3652 &self.inlay_hints
3653 }
3654}
3655
3656#[derive(Debug, Default, Clone)]
3657pub struct DocumentColors {
3658 pub colors: HashSet<DocumentColor>,
3659 pub cache_version: Option<usize>,
3660}
3661
3662type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3663type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3664
3665#[derive(Debug, Default)]
3666struct DocumentColorData {
3667 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3668 cache_version: usize,
3669 colors_update: Option<(Global, DocumentColorTask)>,
3670}
3671
3672#[derive(Debug, Default)]
3673struct CodeLensData {
3674 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3675 update: Option<(Global, CodeLensTask)>,
3676}
3677
3678#[derive(Debug)]
3679pub enum LspStoreEvent {
3680 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3681 LanguageServerRemoved(LanguageServerId),
3682 LanguageServerUpdate {
3683 language_server_id: LanguageServerId,
3684 name: Option<LanguageServerName>,
3685 message: proto::update_language_server::Variant,
3686 },
3687 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3688 LanguageServerPrompt(LanguageServerPromptRequest),
3689 LanguageDetected {
3690 buffer: Entity<Buffer>,
3691 new_language: Option<Arc<Language>>,
3692 },
3693 Notification(String),
3694 RefreshInlayHints {
3695 server_id: LanguageServerId,
3696 request_id: Option<usize>,
3697 },
3698 RefreshCodeLens,
3699 DiagnosticsUpdated {
3700 server_id: LanguageServerId,
3701 paths: Vec<ProjectPath>,
3702 },
3703 DiskBasedDiagnosticsStarted {
3704 language_server_id: LanguageServerId,
3705 },
3706 DiskBasedDiagnosticsFinished {
3707 language_server_id: LanguageServerId,
3708 },
3709 SnippetEdit {
3710 buffer_id: BufferId,
3711 edits: Vec<(lsp::Range, Snippet)>,
3712 most_recent_edit: clock::Lamport,
3713 },
3714}
3715
3716#[derive(Clone, Debug, Serialize)]
3717pub struct LanguageServerStatus {
3718 pub name: LanguageServerName,
3719 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3720 pub has_pending_diagnostic_updates: bool,
3721 progress_tokens: HashSet<ProgressToken>,
3722 pub worktree: Option<WorktreeId>,
3723}
3724
3725#[derive(Clone, Debug)]
3726struct CoreSymbol {
3727 pub language_server_name: LanguageServerName,
3728 pub source_worktree_id: WorktreeId,
3729 pub source_language_server_id: LanguageServerId,
3730 pub path: SymbolLocation,
3731 pub name: String,
3732 pub kind: lsp::SymbolKind,
3733 pub range: Range<Unclipped<PointUtf16>>,
3734}
3735
3736#[derive(Clone, Debug, PartialEq, Eq)]
3737pub enum SymbolLocation {
3738 InProject(ProjectPath),
3739 OutsideProject {
3740 abs_path: Arc<Path>,
3741 signature: [u8; 32],
3742 },
3743}
3744
3745impl SymbolLocation {
3746 fn file_name(&self) -> Option<&str> {
3747 match self {
3748 Self::InProject(path) => path.path.file_name(),
3749 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3750 }
3751 }
3752}
3753
3754impl LspStore {
3755 pub fn init(client: &AnyProtoClient) {
3756 client.add_entity_request_handler(Self::handle_lsp_query);
3757 client.add_entity_message_handler(Self::handle_lsp_query_response);
3758 client.add_entity_request_handler(Self::handle_restart_language_servers);
3759 client.add_entity_request_handler(Self::handle_stop_language_servers);
3760 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3761 client.add_entity_message_handler(Self::handle_start_language_server);
3762 client.add_entity_message_handler(Self::handle_update_language_server);
3763 client.add_entity_message_handler(Self::handle_language_server_log);
3764 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3765 client.add_entity_request_handler(Self::handle_format_buffers);
3766 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3767 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3768 client.add_entity_request_handler(Self::handle_apply_code_action);
3769 client.add_entity_request_handler(Self::handle_get_project_symbols);
3770 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3771 client.add_entity_request_handler(Self::handle_get_color_presentation);
3772 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3773 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3774 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3775 client.add_entity_request_handler(Self::handle_on_type_formatting);
3776 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3777 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3778 client.add_entity_request_handler(Self::handle_rename_project_entry);
3779 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3780 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3781 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3782 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3783 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3784 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3785 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3786
3787 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3788 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3789 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3790 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3791 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3792 client.add_entity_request_handler(
3793 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3794 );
3795 client.add_entity_request_handler(
3796 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3797 );
3798 client.add_entity_request_handler(
3799 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3800 );
3801 }
3802
3803 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3804 match &self.mode {
3805 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3806 _ => None,
3807 }
3808 }
3809
3810 pub fn as_local(&self) -> Option<&LocalLspStore> {
3811 match &self.mode {
3812 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3813 _ => None,
3814 }
3815 }
3816
3817 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3818 match &mut self.mode {
3819 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3820 _ => None,
3821 }
3822 }
3823
3824 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3825 match &self.mode {
3826 LspStoreMode::Remote(RemoteLspStore {
3827 upstream_client: Some(upstream_client),
3828 upstream_project_id,
3829 ..
3830 }) => Some((upstream_client.clone(), *upstream_project_id)),
3831
3832 LspStoreMode::Remote(RemoteLspStore {
3833 upstream_client: None,
3834 ..
3835 }) => None,
3836 LspStoreMode::Local(_) => None,
3837 }
3838 }
3839
3840 pub fn new_local(
3841 buffer_store: Entity<BufferStore>,
3842 worktree_store: Entity<WorktreeStore>,
3843 prettier_store: Entity<PrettierStore>,
3844 toolchain_store: Entity<LocalToolchainStore>,
3845 environment: Entity<ProjectEnvironment>,
3846 manifest_tree: Entity<ManifestTree>,
3847 languages: Arc<LanguageRegistry>,
3848 http_client: Arc<dyn HttpClient>,
3849 fs: Arc<dyn Fs>,
3850 cx: &mut Context<Self>,
3851 ) -> Self {
3852 let yarn = YarnPathStore::new(fs.clone(), cx);
3853 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3854 .detach();
3855 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3856 .detach();
3857 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3858 .detach();
3859 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3860 .detach();
3861 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3862 .detach();
3863 subscribe_to_binary_statuses(&languages, cx).detach();
3864
3865 let _maintain_workspace_config = {
3866 let (sender, receiver) = watch::channel();
3867 (Self::maintain_workspace_config(receiver, cx), sender)
3868 };
3869
3870 Self {
3871 mode: LspStoreMode::Local(LocalLspStore {
3872 weak: cx.weak_entity(),
3873 worktree_store: worktree_store.clone(),
3874
3875 supplementary_language_servers: Default::default(),
3876 languages: languages.clone(),
3877 language_server_ids: Default::default(),
3878 language_servers: Default::default(),
3879 last_workspace_edits_by_language_server: Default::default(),
3880 language_server_watched_paths: Default::default(),
3881 language_server_paths_watched_for_rename: Default::default(),
3882 language_server_dynamic_registrations: Default::default(),
3883 buffers_being_formatted: Default::default(),
3884 buffer_snapshots: Default::default(),
3885 prettier_store,
3886 environment,
3887 http_client,
3888 fs,
3889 yarn,
3890 next_diagnostic_group_id: Default::default(),
3891 diagnostics: Default::default(),
3892 _subscription: cx.on_app_quit(|this, cx| {
3893 this.as_local_mut()
3894 .unwrap()
3895 .shutdown_language_servers_on_quit(cx)
3896 }),
3897 lsp_tree: LanguageServerTree::new(
3898 manifest_tree,
3899 languages.clone(),
3900 toolchain_store.clone(),
3901 ),
3902 toolchain_store,
3903 registered_buffers: HashMap::default(),
3904 buffers_opened_in_servers: HashMap::default(),
3905 buffer_pull_diagnostics_result_ids: HashMap::default(),
3906 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3907 .manifest_file_names(),
3908 }),
3909 last_formatting_failure: None,
3910 downstream_client: None,
3911 buffer_store,
3912 worktree_store,
3913 languages: languages.clone(),
3914 language_server_statuses: Default::default(),
3915 nonce: StdRng::from_os_rng().random(),
3916 diagnostic_summaries: HashMap::default(),
3917 lsp_server_capabilities: HashMap::default(),
3918 lsp_data: HashMap::default(),
3919 next_hint_id: Arc::default(),
3920 active_entry: None,
3921 _maintain_workspace_config,
3922 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3923 }
3924 }
3925
3926 fn send_lsp_proto_request<R: LspCommand>(
3927 &self,
3928 buffer: Entity<Buffer>,
3929 client: AnyProtoClient,
3930 upstream_project_id: u64,
3931 request: R,
3932 cx: &mut Context<LspStore>,
3933 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3934 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3935 return Task::ready(Ok(R::Response::default()));
3936 }
3937 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3938 cx.spawn(async move |this, cx| {
3939 let response = client.request(message).await?;
3940 let this = this.upgrade().context("project dropped")?;
3941 request
3942 .response_from_proto(response, this, buffer, cx.clone())
3943 .await
3944 })
3945 }
3946
3947 pub(super) fn new_remote(
3948 buffer_store: Entity<BufferStore>,
3949 worktree_store: Entity<WorktreeStore>,
3950 languages: Arc<LanguageRegistry>,
3951 upstream_client: AnyProtoClient,
3952 project_id: u64,
3953 cx: &mut Context<Self>,
3954 ) -> Self {
3955 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3956 .detach();
3957 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3958 .detach();
3959 subscribe_to_binary_statuses(&languages, cx).detach();
3960 let _maintain_workspace_config = {
3961 let (sender, receiver) = watch::channel();
3962 (Self::maintain_workspace_config(receiver, cx), sender)
3963 };
3964 Self {
3965 mode: LspStoreMode::Remote(RemoteLspStore {
3966 upstream_client: Some(upstream_client),
3967 upstream_project_id: project_id,
3968 }),
3969 downstream_client: None,
3970 last_formatting_failure: None,
3971 buffer_store,
3972 worktree_store,
3973 languages: languages.clone(),
3974 language_server_statuses: Default::default(),
3975 nonce: StdRng::from_os_rng().random(),
3976 diagnostic_summaries: HashMap::default(),
3977 lsp_server_capabilities: HashMap::default(),
3978 next_hint_id: Arc::default(),
3979 lsp_data: HashMap::default(),
3980 active_entry: None,
3981
3982 _maintain_workspace_config,
3983 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3984 }
3985 }
3986
3987 fn on_buffer_store_event(
3988 &mut self,
3989 _: Entity<BufferStore>,
3990 event: &BufferStoreEvent,
3991 cx: &mut Context<Self>,
3992 ) {
3993 match event {
3994 BufferStoreEvent::BufferAdded(buffer) => {
3995 self.on_buffer_added(buffer, cx).log_err();
3996 }
3997 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3998 let buffer_id = buffer.read(cx).remote_id();
3999 if let Some(local) = self.as_local_mut()
4000 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4001 {
4002 local.reset_buffer(buffer, old_file, cx);
4003
4004 if local.registered_buffers.contains_key(&buffer_id) {
4005 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4006 }
4007 }
4008
4009 self.detect_language_for_buffer(buffer, cx);
4010 if let Some(local) = self.as_local_mut() {
4011 local.initialize_buffer(buffer, cx);
4012 if local.registered_buffers.contains_key(&buffer_id) {
4013 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4014 }
4015 }
4016 }
4017 _ => {}
4018 }
4019 }
4020
4021 fn on_worktree_store_event(
4022 &mut self,
4023 _: Entity<WorktreeStore>,
4024 event: &WorktreeStoreEvent,
4025 cx: &mut Context<Self>,
4026 ) {
4027 match event {
4028 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4029 if !worktree.read(cx).is_local() {
4030 return;
4031 }
4032 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4033 worktree::Event::UpdatedEntries(changes) => {
4034 this.update_local_worktree_language_servers(&worktree, changes, cx);
4035 }
4036 worktree::Event::UpdatedGitRepositories(_)
4037 | worktree::Event::DeletedEntry(_) => {}
4038 })
4039 .detach()
4040 }
4041 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4042 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4043 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4044 }
4045 WorktreeStoreEvent::WorktreeReleased(..)
4046 | WorktreeStoreEvent::WorktreeOrderChanged
4047 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4048 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4049 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4050 }
4051 }
4052
4053 fn on_prettier_store_event(
4054 &mut self,
4055 _: Entity<PrettierStore>,
4056 event: &PrettierStoreEvent,
4057 cx: &mut Context<Self>,
4058 ) {
4059 match event {
4060 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4061 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4062 }
4063 PrettierStoreEvent::LanguageServerAdded {
4064 new_server_id,
4065 name,
4066 prettier_server,
4067 } => {
4068 self.register_supplementary_language_server(
4069 *new_server_id,
4070 name.clone(),
4071 prettier_server.clone(),
4072 cx,
4073 );
4074 }
4075 }
4076 }
4077
4078 fn on_toolchain_store_event(
4079 &mut self,
4080 _: Entity<LocalToolchainStore>,
4081 event: &ToolchainStoreEvent,
4082 _: &mut Context<Self>,
4083 ) {
4084 if let ToolchainStoreEvent::ToolchainActivated = event {
4085 self.request_workspace_config_refresh()
4086 }
4087 }
4088
4089 fn request_workspace_config_refresh(&mut self) {
4090 *self._maintain_workspace_config.1.borrow_mut() = ();
4091 }
4092
4093 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4094 self.as_local().map(|local| local.prettier_store.clone())
4095 }
4096
4097 fn on_buffer_event(
4098 &mut self,
4099 buffer: Entity<Buffer>,
4100 event: &language::BufferEvent,
4101 cx: &mut Context<Self>,
4102 ) {
4103 match event {
4104 language::BufferEvent::Edited => {
4105 self.on_buffer_edited(buffer, cx);
4106 }
4107
4108 language::BufferEvent::Saved => {
4109 self.on_buffer_saved(buffer, cx);
4110 }
4111
4112 _ => {}
4113 }
4114 }
4115
4116 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4117 buffer
4118 .read(cx)
4119 .set_language_registry(self.languages.clone());
4120
4121 cx.subscribe(buffer, |this, buffer, event, cx| {
4122 this.on_buffer_event(buffer, event, cx);
4123 })
4124 .detach();
4125
4126 self.detect_language_for_buffer(buffer, cx);
4127 if let Some(local) = self.as_local_mut() {
4128 local.initialize_buffer(buffer, cx);
4129 }
4130
4131 Ok(())
4132 }
4133
4134 pub(crate) fn register_buffer_with_language_servers(
4135 &mut self,
4136 buffer: &Entity<Buffer>,
4137 only_register_servers: HashSet<LanguageServerSelector>,
4138 ignore_refcounts: bool,
4139 cx: &mut Context<Self>,
4140 ) -> OpenLspBufferHandle {
4141 let buffer_id = buffer.read(cx).remote_id();
4142 let handle = cx.new(|_| buffer.clone());
4143 if let Some(local) = self.as_local_mut() {
4144 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4145 if !ignore_refcounts {
4146 *refcount += 1;
4147 }
4148
4149 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4150 // 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
4151 // 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
4152 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4153 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4154 return handle;
4155 };
4156 if !file.is_local() {
4157 return handle;
4158 }
4159
4160 if ignore_refcounts || *refcount == 1 {
4161 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4162 }
4163 if !ignore_refcounts {
4164 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4165 let refcount = {
4166 let local = lsp_store.as_local_mut().unwrap();
4167 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4168 debug_panic!("bad refcounting");
4169 return;
4170 };
4171
4172 *refcount -= 1;
4173 *refcount
4174 };
4175 if refcount == 0 {
4176 lsp_store.lsp_data.remove(&buffer_id);
4177 let local = lsp_store.as_local_mut().unwrap();
4178 local.registered_buffers.remove(&buffer_id);
4179 local.buffers_opened_in_servers.remove(&buffer_id);
4180 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4181 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4182 }
4183 }
4184 })
4185 .detach();
4186 }
4187 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4188 let buffer_id = buffer.read(cx).remote_id().to_proto();
4189 cx.background_spawn(async move {
4190 upstream_client
4191 .request(proto::RegisterBufferWithLanguageServers {
4192 project_id: upstream_project_id,
4193 buffer_id,
4194 only_servers: only_register_servers
4195 .into_iter()
4196 .map(|selector| {
4197 let selector = match selector {
4198 LanguageServerSelector::Id(language_server_id) => {
4199 proto::language_server_selector::Selector::ServerId(
4200 language_server_id.to_proto(),
4201 )
4202 }
4203 LanguageServerSelector::Name(language_server_name) => {
4204 proto::language_server_selector::Selector::Name(
4205 language_server_name.to_string(),
4206 )
4207 }
4208 };
4209 proto::LanguageServerSelector {
4210 selector: Some(selector),
4211 }
4212 })
4213 .collect(),
4214 })
4215 .await
4216 })
4217 .detach();
4218 } else {
4219 // Our remote connection got closed
4220 }
4221 handle
4222 }
4223
4224 fn maintain_buffer_languages(
4225 languages: Arc<LanguageRegistry>,
4226 cx: &mut Context<Self>,
4227 ) -> Task<()> {
4228 let mut subscription = languages.subscribe();
4229 let mut prev_reload_count = languages.reload_count();
4230 cx.spawn(async move |this, cx| {
4231 while let Some(()) = subscription.next().await {
4232 if let Some(this) = this.upgrade() {
4233 // If the language registry has been reloaded, then remove and
4234 // re-assign the languages on all open buffers.
4235 let reload_count = languages.reload_count();
4236 if reload_count > prev_reload_count {
4237 prev_reload_count = reload_count;
4238 this.update(cx, |this, cx| {
4239 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4240 for buffer in buffer_store.buffers() {
4241 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4242 {
4243 buffer
4244 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4245 if let Some(local) = this.as_local_mut() {
4246 local.reset_buffer(&buffer, &f, cx);
4247
4248 if local
4249 .registered_buffers
4250 .contains_key(&buffer.read(cx).remote_id())
4251 && let Some(file_url) =
4252 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4253 {
4254 local.unregister_buffer_from_language_servers(
4255 &buffer, &file_url, cx,
4256 );
4257 }
4258 }
4259 }
4260 }
4261 });
4262 })
4263 .ok();
4264 }
4265
4266 this.update(cx, |this, cx| {
4267 let mut plain_text_buffers = Vec::new();
4268 let mut buffers_with_unknown_injections = Vec::new();
4269 for handle in this.buffer_store.read(cx).buffers() {
4270 let buffer = handle.read(cx);
4271 if buffer.language().is_none()
4272 || buffer.language() == Some(&*language::PLAIN_TEXT)
4273 {
4274 plain_text_buffers.push(handle);
4275 } else if buffer.contains_unknown_injections() {
4276 buffers_with_unknown_injections.push(handle);
4277 }
4278 }
4279
4280 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4281 // and reused later in the invisible worktrees.
4282 plain_text_buffers.sort_by_key(|buffer| {
4283 Reverse(
4284 File::from_dyn(buffer.read(cx).file())
4285 .map(|file| file.worktree.read(cx).is_visible()),
4286 )
4287 });
4288
4289 for buffer in plain_text_buffers {
4290 this.detect_language_for_buffer(&buffer, cx);
4291 if let Some(local) = this.as_local_mut() {
4292 local.initialize_buffer(&buffer, cx);
4293 if local
4294 .registered_buffers
4295 .contains_key(&buffer.read(cx).remote_id())
4296 {
4297 local.register_buffer_with_language_servers(
4298 &buffer,
4299 HashSet::default(),
4300 cx,
4301 );
4302 }
4303 }
4304 }
4305
4306 for buffer in buffers_with_unknown_injections {
4307 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4308 }
4309 })
4310 .ok();
4311 }
4312 }
4313 })
4314 }
4315
4316 fn detect_language_for_buffer(
4317 &mut self,
4318 buffer_handle: &Entity<Buffer>,
4319 cx: &mut Context<Self>,
4320 ) -> Option<language::AvailableLanguage> {
4321 // If the buffer has a language, set it and start the language server if we haven't already.
4322 let buffer = buffer_handle.read(cx);
4323 let file = buffer.file()?;
4324
4325 let content = buffer.as_rope();
4326 let available_language = self.languages.language_for_file(file, Some(content), cx);
4327 if let Some(available_language) = &available_language {
4328 if let Some(Ok(Ok(new_language))) = self
4329 .languages
4330 .load_language(available_language)
4331 .now_or_never()
4332 {
4333 self.set_language_for_buffer(buffer_handle, new_language, cx);
4334 }
4335 } else {
4336 cx.emit(LspStoreEvent::LanguageDetected {
4337 buffer: buffer_handle.clone(),
4338 new_language: None,
4339 });
4340 }
4341
4342 available_language
4343 }
4344
4345 pub(crate) fn set_language_for_buffer(
4346 &mut self,
4347 buffer_entity: &Entity<Buffer>,
4348 new_language: Arc<Language>,
4349 cx: &mut Context<Self>,
4350 ) {
4351 let buffer = buffer_entity.read(cx);
4352 let buffer_file = buffer.file().cloned();
4353 let buffer_id = buffer.remote_id();
4354 if let Some(local_store) = self.as_local_mut()
4355 && local_store.registered_buffers.contains_key(&buffer_id)
4356 && let Some(abs_path) =
4357 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4358 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4359 {
4360 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4361 }
4362 buffer_entity.update(cx, |buffer, cx| {
4363 if buffer
4364 .language()
4365 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4366 {
4367 buffer.set_language(Some(new_language.clone()), cx);
4368 }
4369 });
4370
4371 let settings =
4372 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4373 let buffer_file = File::from_dyn(buffer_file.as_ref());
4374
4375 let worktree_id = if let Some(file) = buffer_file {
4376 let worktree = file.worktree.clone();
4377
4378 if let Some(local) = self.as_local_mut()
4379 && local.registered_buffers.contains_key(&buffer_id)
4380 {
4381 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4382 }
4383 Some(worktree.read(cx).id())
4384 } else {
4385 None
4386 };
4387
4388 if settings.prettier.allowed
4389 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4390 {
4391 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4392 if let Some(prettier_store) = prettier_store {
4393 prettier_store.update(cx, |prettier_store, cx| {
4394 prettier_store.install_default_prettier(
4395 worktree_id,
4396 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4397 cx,
4398 )
4399 })
4400 }
4401 }
4402
4403 cx.emit(LspStoreEvent::LanguageDetected {
4404 buffer: buffer_entity.clone(),
4405 new_language: Some(new_language),
4406 })
4407 }
4408
4409 pub fn buffer_store(&self) -> Entity<BufferStore> {
4410 self.buffer_store.clone()
4411 }
4412
4413 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4414 self.active_entry = active_entry;
4415 }
4416
4417 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4418 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4419 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4420 {
4421 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4422 summaries
4423 .iter()
4424 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4425 });
4426 if let Some(summary) = summaries.next() {
4427 client
4428 .send(proto::UpdateDiagnosticSummary {
4429 project_id: downstream_project_id,
4430 worktree_id: worktree.id().to_proto(),
4431 summary: Some(summary),
4432 more_summaries: summaries.collect(),
4433 })
4434 .log_err();
4435 }
4436 }
4437 }
4438
4439 fn is_capable_for_proto_request<R>(
4440 &self,
4441 buffer: &Entity<Buffer>,
4442 request: &R,
4443 cx: &App,
4444 ) -> bool
4445 where
4446 R: LspCommand,
4447 {
4448 self.check_if_capable_for_proto_request(
4449 buffer,
4450 |capabilities| {
4451 request.check_capabilities(AdapterServerCapabilities {
4452 server_capabilities: capabilities.clone(),
4453 code_action_kinds: None,
4454 })
4455 },
4456 cx,
4457 )
4458 }
4459
4460 fn check_if_capable_for_proto_request<F>(
4461 &self,
4462 buffer: &Entity<Buffer>,
4463 check: F,
4464 cx: &App,
4465 ) -> bool
4466 where
4467 F: FnMut(&lsp::ServerCapabilities) -> bool,
4468 {
4469 let Some(language) = buffer.read(cx).language().cloned() else {
4470 return false;
4471 };
4472 let relevant_language_servers = self
4473 .languages
4474 .lsp_adapters(&language.name())
4475 .into_iter()
4476 .map(|lsp_adapter| lsp_adapter.name())
4477 .collect::<HashSet<_>>();
4478 self.language_server_statuses
4479 .iter()
4480 .filter_map(|(server_id, server_status)| {
4481 relevant_language_servers
4482 .contains(&server_status.name)
4483 .then_some(server_id)
4484 })
4485 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4486 .any(check)
4487 }
4488
4489 fn all_capable_for_proto_request<F>(
4490 &self,
4491 buffer: &Entity<Buffer>,
4492 mut check: F,
4493 cx: &App,
4494 ) -> Vec<lsp::LanguageServerId>
4495 where
4496 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4497 {
4498 let Some(language) = buffer.read(cx).language().cloned() else {
4499 return Vec::default();
4500 };
4501 let relevant_language_servers = self
4502 .languages
4503 .lsp_adapters(&language.name())
4504 .into_iter()
4505 .map(|lsp_adapter| lsp_adapter.name())
4506 .collect::<HashSet<_>>();
4507 self.language_server_statuses
4508 .iter()
4509 .filter_map(|(server_id, server_status)| {
4510 relevant_language_servers
4511 .contains(&server_status.name)
4512 .then_some((server_id, &server_status.name))
4513 })
4514 .filter_map(|(server_id, server_name)| {
4515 self.lsp_server_capabilities
4516 .get(server_id)
4517 .map(|c| (server_id, server_name, c))
4518 })
4519 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4520 .map(|(server_id, _, _)| *server_id)
4521 .collect()
4522 }
4523
4524 pub fn request_lsp<R>(
4525 &mut self,
4526 buffer: Entity<Buffer>,
4527 server: LanguageServerToQuery,
4528 request: R,
4529 cx: &mut Context<Self>,
4530 ) -> Task<Result<R::Response>>
4531 where
4532 R: LspCommand,
4533 <R::LspRequest as lsp::request::Request>::Result: Send,
4534 <R::LspRequest as lsp::request::Request>::Params: Send,
4535 {
4536 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4537 return self.send_lsp_proto_request(
4538 buffer,
4539 upstream_client,
4540 upstream_project_id,
4541 request,
4542 cx,
4543 );
4544 }
4545
4546 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4547 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4548 local
4549 .language_servers_for_buffer(buffer, cx)
4550 .find(|(_, server)| {
4551 request.check_capabilities(server.adapter_server_capabilities())
4552 })
4553 .map(|(_, server)| server.clone())
4554 }),
4555 LanguageServerToQuery::Other(id) => self
4556 .language_server_for_local_buffer(buffer, id, cx)
4557 .and_then(|(_, server)| {
4558 request
4559 .check_capabilities(server.adapter_server_capabilities())
4560 .then(|| Arc::clone(server))
4561 }),
4562 }) else {
4563 return Task::ready(Ok(Default::default()));
4564 };
4565
4566 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4567
4568 let Some(file) = file else {
4569 return Task::ready(Ok(Default::default()));
4570 };
4571
4572 let lsp_params = match request.to_lsp_params_or_response(
4573 &file.abs_path(cx),
4574 buffer.read(cx),
4575 &language_server,
4576 cx,
4577 ) {
4578 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4579 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4580 Err(err) => {
4581 let message = format!(
4582 "{} via {} failed: {}",
4583 request.display_name(),
4584 language_server.name(),
4585 err
4586 );
4587 // rust-analyzer likes to error with this when its still loading up
4588 if !message.ends_with("content modified") {
4589 log::warn!("{message}");
4590 }
4591 return Task::ready(Err(anyhow!(message)));
4592 }
4593 };
4594
4595 let status = request.status();
4596 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4597 return Task::ready(Ok(Default::default()));
4598 }
4599 cx.spawn(async move |this, cx| {
4600 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4601
4602 let id = lsp_request.id();
4603 let _cleanup = if status.is_some() {
4604 cx.update(|cx| {
4605 this.update(cx, |this, cx| {
4606 this.on_lsp_work_start(
4607 language_server.server_id(),
4608 ProgressToken::Number(id),
4609 LanguageServerProgress {
4610 is_disk_based_diagnostics_progress: false,
4611 is_cancellable: false,
4612 title: None,
4613 message: status.clone(),
4614 percentage: None,
4615 last_update_at: cx.background_executor().now(),
4616 },
4617 cx,
4618 );
4619 })
4620 })
4621 .log_err();
4622
4623 Some(defer(|| {
4624 cx.update(|cx| {
4625 this.update(cx, |this, cx| {
4626 this.on_lsp_work_end(
4627 language_server.server_id(),
4628 ProgressToken::Number(id),
4629 cx,
4630 );
4631 })
4632 })
4633 .log_err();
4634 }))
4635 } else {
4636 None
4637 };
4638
4639 let result = lsp_request.await.into_response();
4640
4641 let response = result.map_err(|err| {
4642 let message = format!(
4643 "{} via {} failed: {}",
4644 request.display_name(),
4645 language_server.name(),
4646 err
4647 );
4648 // rust-analyzer likes to error with this when its still loading up
4649 if !message.ends_with("content modified") {
4650 log::warn!("{message}");
4651 }
4652 anyhow::anyhow!(message)
4653 })?;
4654
4655 request
4656 .response_from_lsp(
4657 response,
4658 this.upgrade().context("no app context")?,
4659 buffer,
4660 language_server.server_id(),
4661 cx.clone(),
4662 )
4663 .await
4664 })
4665 }
4666
4667 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4668 let mut language_formatters_to_check = Vec::new();
4669 for buffer in self.buffer_store.read(cx).buffers() {
4670 let buffer = buffer.read(cx);
4671 let buffer_file = File::from_dyn(buffer.file());
4672 let buffer_language = buffer.language();
4673 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4674 if buffer_language.is_some() {
4675 language_formatters_to_check.push((
4676 buffer_file.map(|f| f.worktree_id(cx)),
4677 settings.into_owned(),
4678 ));
4679 }
4680 }
4681
4682 self.request_workspace_config_refresh();
4683
4684 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4685 prettier_store.update(cx, |prettier_store, cx| {
4686 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4687 })
4688 }
4689
4690 cx.notify();
4691 }
4692
4693 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4694 let buffer_store = self.buffer_store.clone();
4695 let Some(local) = self.as_local_mut() else {
4696 return;
4697 };
4698 let mut adapters = BTreeMap::default();
4699 let get_adapter = {
4700 let languages = local.languages.clone();
4701 let environment = local.environment.clone();
4702 let weak = local.weak.clone();
4703 let worktree_store = local.worktree_store.clone();
4704 let http_client = local.http_client.clone();
4705 let fs = local.fs.clone();
4706 move |worktree_id, cx: &mut App| {
4707 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4708 Some(LocalLspAdapterDelegate::new(
4709 languages.clone(),
4710 &environment,
4711 weak.clone(),
4712 &worktree,
4713 http_client.clone(),
4714 fs.clone(),
4715 cx,
4716 ))
4717 }
4718 };
4719
4720 let mut messages_to_report = Vec::new();
4721 let (new_tree, to_stop) = {
4722 let mut rebase = local.lsp_tree.rebase();
4723 let buffers = buffer_store
4724 .read(cx)
4725 .buffers()
4726 .filter_map(|buffer| {
4727 let raw_buffer = buffer.read(cx);
4728 if !local
4729 .registered_buffers
4730 .contains_key(&raw_buffer.remote_id())
4731 {
4732 return None;
4733 }
4734 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4735 let language = raw_buffer.language().cloned()?;
4736 Some((file, language, raw_buffer.remote_id()))
4737 })
4738 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4739 for (file, language, buffer_id) in buffers {
4740 let worktree_id = file.worktree_id(cx);
4741 let Some(worktree) = local
4742 .worktree_store
4743 .read(cx)
4744 .worktree_for_id(worktree_id, cx)
4745 else {
4746 continue;
4747 };
4748
4749 if let Some((_, apply)) = local.reuse_existing_language_server(
4750 rebase.server_tree(),
4751 &worktree,
4752 &language.name(),
4753 cx,
4754 ) {
4755 (apply)(rebase.server_tree());
4756 } else if let Some(lsp_delegate) = adapters
4757 .entry(worktree_id)
4758 .or_insert_with(|| get_adapter(worktree_id, cx))
4759 .clone()
4760 {
4761 let delegate =
4762 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4763 let path = file
4764 .path()
4765 .parent()
4766 .map(Arc::from)
4767 .unwrap_or_else(|| file.path().clone());
4768 let worktree_path = ProjectPath { worktree_id, path };
4769 let abs_path = file.abs_path(cx);
4770 let nodes = rebase
4771 .walk(
4772 worktree_path,
4773 language.name(),
4774 language.manifest(),
4775 delegate.clone(),
4776 cx,
4777 )
4778 .collect::<Vec<_>>();
4779 for node in nodes {
4780 let server_id = node.server_id_or_init(|disposition| {
4781 let path = &disposition.path;
4782 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4783 let key = LanguageServerSeed {
4784 worktree_id,
4785 name: disposition.server_name.clone(),
4786 settings: disposition.settings.clone(),
4787 toolchain: local.toolchain_store.read(cx).active_toolchain(
4788 path.worktree_id,
4789 &path.path,
4790 language.name(),
4791 ),
4792 };
4793 local.language_server_ids.remove(&key);
4794
4795 let server_id = local.get_or_insert_language_server(
4796 &worktree,
4797 lsp_delegate.clone(),
4798 disposition,
4799 &language.name(),
4800 cx,
4801 );
4802 if let Some(state) = local.language_servers.get(&server_id)
4803 && let Ok(uri) = uri
4804 {
4805 state.add_workspace_folder(uri);
4806 };
4807 server_id
4808 });
4809
4810 if let Some(language_server_id) = server_id {
4811 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4812 language_server_id,
4813 name: node.name(),
4814 message:
4815 proto::update_language_server::Variant::RegisteredForBuffer(
4816 proto::RegisteredForBuffer {
4817 buffer_abs_path: abs_path
4818 .to_string_lossy()
4819 .into_owned(),
4820 buffer_id: buffer_id.to_proto(),
4821 },
4822 ),
4823 });
4824 }
4825 }
4826 } else {
4827 continue;
4828 }
4829 }
4830 rebase.finish()
4831 };
4832 for message in messages_to_report {
4833 cx.emit(message);
4834 }
4835 local.lsp_tree = new_tree;
4836 for (id, _) in to_stop {
4837 self.stop_local_language_server(id, cx).detach();
4838 }
4839 }
4840
4841 pub fn apply_code_action(
4842 &self,
4843 buffer_handle: Entity<Buffer>,
4844 mut action: CodeAction,
4845 push_to_history: bool,
4846 cx: &mut Context<Self>,
4847 ) -> Task<Result<ProjectTransaction>> {
4848 if let Some((upstream_client, project_id)) = self.upstream_client() {
4849 let request = proto::ApplyCodeAction {
4850 project_id,
4851 buffer_id: buffer_handle.read(cx).remote_id().into(),
4852 action: Some(Self::serialize_code_action(&action)),
4853 };
4854 let buffer_store = self.buffer_store();
4855 cx.spawn(async move |_, cx| {
4856 let response = upstream_client
4857 .request(request)
4858 .await?
4859 .transaction
4860 .context("missing transaction")?;
4861
4862 buffer_store
4863 .update(cx, |buffer_store, cx| {
4864 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4865 })?
4866 .await
4867 })
4868 } else if self.mode.is_local() {
4869 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4870 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4871 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4872 }) else {
4873 return Task::ready(Ok(ProjectTransaction::default()));
4874 };
4875 cx.spawn(async move |this, cx| {
4876 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4877 .await
4878 .context("resolving a code action")?;
4879 if let Some(edit) = action.lsp_action.edit()
4880 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4881 return LocalLspStore::deserialize_workspace_edit(
4882 this.upgrade().context("no app present")?,
4883 edit.clone(),
4884 push_to_history,
4885
4886 lang_server.clone(),
4887 cx,
4888 )
4889 .await;
4890 }
4891
4892 if let Some(command) = action.lsp_action.command() {
4893 let server_capabilities = lang_server.capabilities();
4894 let available_commands = server_capabilities
4895 .execute_command_provider
4896 .as_ref()
4897 .map(|options| options.commands.as_slice())
4898 .unwrap_or_default();
4899 if available_commands.contains(&command.command) {
4900 this.update(cx, |this, _| {
4901 this.as_local_mut()
4902 .unwrap()
4903 .last_workspace_edits_by_language_server
4904 .remove(&lang_server.server_id());
4905 })?;
4906
4907 let _result = lang_server
4908 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4909 command: command.command.clone(),
4910 arguments: command.arguments.clone().unwrap_or_default(),
4911 ..lsp::ExecuteCommandParams::default()
4912 })
4913 .await.into_response()
4914 .context("execute command")?;
4915
4916 return this.update(cx, |this, _| {
4917 this.as_local_mut()
4918 .unwrap()
4919 .last_workspace_edits_by_language_server
4920 .remove(&lang_server.server_id())
4921 .unwrap_or_default()
4922 });
4923 } else {
4924 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4925 }
4926 }
4927
4928 Ok(ProjectTransaction::default())
4929 })
4930 } else {
4931 Task::ready(Err(anyhow!("no upstream client and not local")))
4932 }
4933 }
4934
4935 pub fn apply_code_action_kind(
4936 &mut self,
4937 buffers: HashSet<Entity<Buffer>>,
4938 kind: CodeActionKind,
4939 push_to_history: bool,
4940 cx: &mut Context<Self>,
4941 ) -> Task<anyhow::Result<ProjectTransaction>> {
4942 if self.as_local().is_some() {
4943 cx.spawn(async move |lsp_store, cx| {
4944 let buffers = buffers.into_iter().collect::<Vec<_>>();
4945 let result = LocalLspStore::execute_code_action_kind_locally(
4946 lsp_store.clone(),
4947 buffers,
4948 kind,
4949 push_to_history,
4950 cx,
4951 )
4952 .await;
4953 lsp_store.update(cx, |lsp_store, _| {
4954 lsp_store.update_last_formatting_failure(&result);
4955 })?;
4956 result
4957 })
4958 } else if let Some((client, project_id)) = self.upstream_client() {
4959 let buffer_store = self.buffer_store();
4960 cx.spawn(async move |lsp_store, cx| {
4961 let result = client
4962 .request(proto::ApplyCodeActionKind {
4963 project_id,
4964 kind: kind.as_str().to_owned(),
4965 buffer_ids: buffers
4966 .iter()
4967 .map(|buffer| {
4968 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4969 })
4970 .collect::<Result<_>>()?,
4971 })
4972 .await
4973 .and_then(|result| result.transaction.context("missing transaction"));
4974 lsp_store.update(cx, |lsp_store, _| {
4975 lsp_store.update_last_formatting_failure(&result);
4976 })?;
4977
4978 let transaction_response = result?;
4979 buffer_store
4980 .update(cx, |buffer_store, cx| {
4981 buffer_store.deserialize_project_transaction(
4982 transaction_response,
4983 push_to_history,
4984 cx,
4985 )
4986 })?
4987 .await
4988 })
4989 } else {
4990 Task::ready(Ok(ProjectTransaction::default()))
4991 }
4992 }
4993
4994 pub fn resolved_hint(
4995 &mut self,
4996 buffer_id: BufferId,
4997 id: InlayId,
4998 cx: &mut Context<Self>,
4999 ) -> Option<ResolvedHint> {
5000 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5001
5002 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5003 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5004 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5005 let (server_id, resolve_data) = match &hint.resolve_state {
5006 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5007 ResolveState::Resolving => {
5008 return Some(ResolvedHint::Resolving(
5009 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5010 ));
5011 }
5012 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5013 };
5014
5015 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5016 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5017 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5018 id,
5019 cx.spawn(async move |lsp_store, cx| {
5020 let resolved_hint = resolve_task.await;
5021 lsp_store
5022 .update(cx, |lsp_store, _| {
5023 if let Some(old_inlay_hint) = lsp_store
5024 .lsp_data
5025 .get_mut(&buffer_id)
5026 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5027 {
5028 match resolved_hint {
5029 Ok(resolved_hint) => {
5030 *old_inlay_hint = resolved_hint;
5031 }
5032 Err(e) => {
5033 old_inlay_hint.resolve_state =
5034 ResolveState::CanResolve(server_id, resolve_data);
5035 log::error!("Inlay hint resolve failed: {e:#}");
5036 }
5037 }
5038 }
5039 })
5040 .ok();
5041 })
5042 .shared(),
5043 );
5044 debug_assert!(
5045 previous_task.is_none(),
5046 "Did not change hint's resolve state after spawning its resolve"
5047 );
5048 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5049 None
5050 }
5051
5052 fn resolve_inlay_hint(
5053 &self,
5054 mut hint: InlayHint,
5055 buffer: Entity<Buffer>,
5056 server_id: LanguageServerId,
5057 cx: &mut Context<Self>,
5058 ) -> Task<anyhow::Result<InlayHint>> {
5059 if let Some((upstream_client, project_id)) = self.upstream_client() {
5060 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5061 {
5062 hint.resolve_state = ResolveState::Resolved;
5063 return Task::ready(Ok(hint));
5064 }
5065 let request = proto::ResolveInlayHint {
5066 project_id,
5067 buffer_id: buffer.read(cx).remote_id().into(),
5068 language_server_id: server_id.0 as u64,
5069 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5070 };
5071 cx.background_spawn(async move {
5072 let response = upstream_client
5073 .request(request)
5074 .await
5075 .context("inlay hints proto request")?;
5076 match response.hint {
5077 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5078 .context("inlay hints proto resolve response conversion"),
5079 None => Ok(hint),
5080 }
5081 })
5082 } else {
5083 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5084 self.language_server_for_local_buffer(buffer, server_id, cx)
5085 .map(|(_, server)| server.clone())
5086 }) else {
5087 return Task::ready(Ok(hint));
5088 };
5089 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5090 return Task::ready(Ok(hint));
5091 }
5092 let buffer_snapshot = buffer.read(cx).snapshot();
5093 cx.spawn(async move |_, cx| {
5094 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5095 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5096 );
5097 let resolved_hint = resolve_task
5098 .await
5099 .into_response()
5100 .context("inlay hint resolve LSP request")?;
5101 let resolved_hint = InlayHints::lsp_to_project_hint(
5102 resolved_hint,
5103 &buffer,
5104 server_id,
5105 ResolveState::Resolved,
5106 false,
5107 cx,
5108 )
5109 .await?;
5110 Ok(resolved_hint)
5111 })
5112 }
5113 }
5114
5115 pub fn resolve_color_presentation(
5116 &mut self,
5117 mut color: DocumentColor,
5118 buffer: Entity<Buffer>,
5119 server_id: LanguageServerId,
5120 cx: &mut Context<Self>,
5121 ) -> Task<Result<DocumentColor>> {
5122 if color.resolved {
5123 return Task::ready(Ok(color));
5124 }
5125
5126 if let Some((upstream_client, project_id)) = self.upstream_client() {
5127 let start = color.lsp_range.start;
5128 let end = color.lsp_range.end;
5129 let request = proto::GetColorPresentation {
5130 project_id,
5131 server_id: server_id.to_proto(),
5132 buffer_id: buffer.read(cx).remote_id().into(),
5133 color: Some(proto::ColorInformation {
5134 red: color.color.red,
5135 green: color.color.green,
5136 blue: color.color.blue,
5137 alpha: color.color.alpha,
5138 lsp_range_start: Some(proto::PointUtf16 {
5139 row: start.line,
5140 column: start.character,
5141 }),
5142 lsp_range_end: Some(proto::PointUtf16 {
5143 row: end.line,
5144 column: end.character,
5145 }),
5146 }),
5147 };
5148 cx.background_spawn(async move {
5149 let response = upstream_client
5150 .request(request)
5151 .await
5152 .context("color presentation proto request")?;
5153 color.resolved = true;
5154 color.color_presentations = response
5155 .presentations
5156 .into_iter()
5157 .map(|presentation| ColorPresentation {
5158 label: SharedString::from(presentation.label),
5159 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5160 additional_text_edits: presentation
5161 .additional_text_edits
5162 .into_iter()
5163 .filter_map(deserialize_lsp_edit)
5164 .collect(),
5165 })
5166 .collect();
5167 Ok(color)
5168 })
5169 } else {
5170 let path = match buffer
5171 .update(cx, |buffer, cx| {
5172 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5173 })
5174 .context("buffer with the missing path")
5175 {
5176 Ok(path) => path,
5177 Err(e) => return Task::ready(Err(e)),
5178 };
5179 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5180 self.language_server_for_local_buffer(buffer, server_id, cx)
5181 .map(|(_, server)| server.clone())
5182 }) else {
5183 return Task::ready(Ok(color));
5184 };
5185 cx.background_spawn(async move {
5186 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5187 lsp::ColorPresentationParams {
5188 text_document: make_text_document_identifier(&path)?,
5189 color: color.color,
5190 range: color.lsp_range,
5191 work_done_progress_params: Default::default(),
5192 partial_result_params: Default::default(),
5193 },
5194 );
5195 color.color_presentations = resolve_task
5196 .await
5197 .into_response()
5198 .context("color presentation resolve LSP request")?
5199 .into_iter()
5200 .map(|presentation| ColorPresentation {
5201 label: SharedString::from(presentation.label),
5202 text_edit: presentation.text_edit,
5203 additional_text_edits: presentation
5204 .additional_text_edits
5205 .unwrap_or_default(),
5206 })
5207 .collect();
5208 color.resolved = true;
5209 Ok(color)
5210 })
5211 }
5212 }
5213
5214 pub(crate) fn linked_edits(
5215 &mut self,
5216 buffer: &Entity<Buffer>,
5217 position: Anchor,
5218 cx: &mut Context<Self>,
5219 ) -> Task<Result<Vec<Range<Anchor>>>> {
5220 let snapshot = buffer.read(cx).snapshot();
5221 let scope = snapshot.language_scope_at(position);
5222 let Some(server_id) = self
5223 .as_local()
5224 .and_then(|local| {
5225 buffer.update(cx, |buffer, cx| {
5226 local
5227 .language_servers_for_buffer(buffer, cx)
5228 .filter(|(_, server)| {
5229 LinkedEditingRange::check_server_capabilities(server.capabilities())
5230 })
5231 .filter(|(adapter, _)| {
5232 scope
5233 .as_ref()
5234 .map(|scope| scope.language_allowed(&adapter.name))
5235 .unwrap_or(true)
5236 })
5237 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5238 .next()
5239 })
5240 })
5241 .or_else(|| {
5242 self.upstream_client()
5243 .is_some()
5244 .then_some(LanguageServerToQuery::FirstCapable)
5245 })
5246 .filter(|_| {
5247 maybe!({
5248 let language = buffer.read(cx).language_at(position)?;
5249 Some(
5250 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5251 .linked_edits,
5252 )
5253 }) == Some(true)
5254 })
5255 else {
5256 return Task::ready(Ok(Vec::new()));
5257 };
5258
5259 self.request_lsp(
5260 buffer.clone(),
5261 server_id,
5262 LinkedEditingRange { position },
5263 cx,
5264 )
5265 }
5266
5267 fn apply_on_type_formatting(
5268 &mut self,
5269 buffer: Entity<Buffer>,
5270 position: Anchor,
5271 trigger: String,
5272 cx: &mut Context<Self>,
5273 ) -> Task<Result<Option<Transaction>>> {
5274 if let Some((client, project_id)) = self.upstream_client() {
5275 if !self.check_if_capable_for_proto_request(
5276 &buffer,
5277 |capabilities| {
5278 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5279 },
5280 cx,
5281 ) {
5282 return Task::ready(Ok(None));
5283 }
5284 let request = proto::OnTypeFormatting {
5285 project_id,
5286 buffer_id: buffer.read(cx).remote_id().into(),
5287 position: Some(serialize_anchor(&position)),
5288 trigger,
5289 version: serialize_version(&buffer.read(cx).version()),
5290 };
5291 cx.background_spawn(async move {
5292 client
5293 .request(request)
5294 .await?
5295 .transaction
5296 .map(language::proto::deserialize_transaction)
5297 .transpose()
5298 })
5299 } else if let Some(local) = self.as_local_mut() {
5300 let buffer_id = buffer.read(cx).remote_id();
5301 local.buffers_being_formatted.insert(buffer_id);
5302 cx.spawn(async move |this, cx| {
5303 let _cleanup = defer({
5304 let this = this.clone();
5305 let mut cx = cx.clone();
5306 move || {
5307 this.update(&mut cx, |this, _| {
5308 if let Some(local) = this.as_local_mut() {
5309 local.buffers_being_formatted.remove(&buffer_id);
5310 }
5311 })
5312 .ok();
5313 }
5314 });
5315
5316 buffer
5317 .update(cx, |buffer, _| {
5318 buffer.wait_for_edits(Some(position.timestamp))
5319 })?
5320 .await?;
5321 this.update(cx, |this, cx| {
5322 let position = position.to_point_utf16(buffer.read(cx));
5323 this.on_type_format(buffer, position, trigger, false, cx)
5324 })?
5325 .await
5326 })
5327 } else {
5328 Task::ready(Err(anyhow!("No upstream client or local language server")))
5329 }
5330 }
5331
5332 pub fn on_type_format<T: ToPointUtf16>(
5333 &mut self,
5334 buffer: Entity<Buffer>,
5335 position: T,
5336 trigger: String,
5337 push_to_history: bool,
5338 cx: &mut Context<Self>,
5339 ) -> Task<Result<Option<Transaction>>> {
5340 let position = position.to_point_utf16(buffer.read(cx));
5341 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5342 }
5343
5344 fn on_type_format_impl(
5345 &mut self,
5346 buffer: Entity<Buffer>,
5347 position: PointUtf16,
5348 trigger: String,
5349 push_to_history: bool,
5350 cx: &mut Context<Self>,
5351 ) -> Task<Result<Option<Transaction>>> {
5352 let options = buffer.update(cx, |buffer, cx| {
5353 lsp_command::lsp_formatting_options(
5354 language_settings(
5355 buffer.language_at(position).map(|l| l.name()),
5356 buffer.file(),
5357 cx,
5358 )
5359 .as_ref(),
5360 )
5361 });
5362
5363 cx.spawn(async move |this, cx| {
5364 if let Some(waiter) =
5365 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5366 {
5367 waiter.await?;
5368 }
5369 cx.update(|cx| {
5370 this.update(cx, |this, cx| {
5371 this.request_lsp(
5372 buffer.clone(),
5373 LanguageServerToQuery::FirstCapable,
5374 OnTypeFormatting {
5375 position,
5376 trigger,
5377 options,
5378 push_to_history,
5379 },
5380 cx,
5381 )
5382 })
5383 })??
5384 .await
5385 })
5386 }
5387
5388 pub fn definitions(
5389 &mut self,
5390 buffer: &Entity<Buffer>,
5391 position: PointUtf16,
5392 cx: &mut Context<Self>,
5393 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5394 if let Some((upstream_client, project_id)) = self.upstream_client() {
5395 let request = GetDefinitions { position };
5396 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5397 return Task::ready(Ok(None));
5398 }
5399 let request_task = upstream_client.request_lsp(
5400 project_id,
5401 None,
5402 LSP_REQUEST_TIMEOUT,
5403 cx.background_executor().clone(),
5404 request.to_proto(project_id, buffer.read(cx)),
5405 );
5406 let buffer = buffer.clone();
5407 cx.spawn(async move |weak_lsp_store, cx| {
5408 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5409 return Ok(None);
5410 };
5411 let Some(responses) = request_task.await? else {
5412 return Ok(None);
5413 };
5414 let actions = join_all(responses.payload.into_iter().map(|response| {
5415 GetDefinitions { position }.response_from_proto(
5416 response.response,
5417 lsp_store.clone(),
5418 buffer.clone(),
5419 cx.clone(),
5420 )
5421 }))
5422 .await;
5423
5424 Ok(Some(
5425 actions
5426 .into_iter()
5427 .collect::<Result<Vec<Vec<_>>>>()?
5428 .into_iter()
5429 .flatten()
5430 .dedup()
5431 .collect(),
5432 ))
5433 })
5434 } else {
5435 let definitions_task = self.request_multiple_lsp_locally(
5436 buffer,
5437 Some(position),
5438 GetDefinitions { position },
5439 cx,
5440 );
5441 cx.background_spawn(async move {
5442 Ok(Some(
5443 definitions_task
5444 .await
5445 .into_iter()
5446 .flat_map(|(_, definitions)| definitions)
5447 .dedup()
5448 .collect(),
5449 ))
5450 })
5451 }
5452 }
5453
5454 pub fn declarations(
5455 &mut self,
5456 buffer: &Entity<Buffer>,
5457 position: PointUtf16,
5458 cx: &mut Context<Self>,
5459 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5460 if let Some((upstream_client, project_id)) = self.upstream_client() {
5461 let request = GetDeclarations { position };
5462 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5463 return Task::ready(Ok(None));
5464 }
5465 let request_task = upstream_client.request_lsp(
5466 project_id,
5467 None,
5468 LSP_REQUEST_TIMEOUT,
5469 cx.background_executor().clone(),
5470 request.to_proto(project_id, buffer.read(cx)),
5471 );
5472 let buffer = buffer.clone();
5473 cx.spawn(async move |weak_lsp_store, cx| {
5474 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5475 return Ok(None);
5476 };
5477 let Some(responses) = request_task.await? else {
5478 return Ok(None);
5479 };
5480 let actions = join_all(responses.payload.into_iter().map(|response| {
5481 GetDeclarations { position }.response_from_proto(
5482 response.response,
5483 lsp_store.clone(),
5484 buffer.clone(),
5485 cx.clone(),
5486 )
5487 }))
5488 .await;
5489
5490 Ok(Some(
5491 actions
5492 .into_iter()
5493 .collect::<Result<Vec<Vec<_>>>>()?
5494 .into_iter()
5495 .flatten()
5496 .dedup()
5497 .collect(),
5498 ))
5499 })
5500 } else {
5501 let declarations_task = self.request_multiple_lsp_locally(
5502 buffer,
5503 Some(position),
5504 GetDeclarations { position },
5505 cx,
5506 );
5507 cx.background_spawn(async move {
5508 Ok(Some(
5509 declarations_task
5510 .await
5511 .into_iter()
5512 .flat_map(|(_, declarations)| declarations)
5513 .dedup()
5514 .collect(),
5515 ))
5516 })
5517 }
5518 }
5519
5520 pub fn type_definitions(
5521 &mut self,
5522 buffer: &Entity<Buffer>,
5523 position: PointUtf16,
5524 cx: &mut Context<Self>,
5525 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5526 if let Some((upstream_client, project_id)) = self.upstream_client() {
5527 let request = GetTypeDefinitions { position };
5528 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5529 return Task::ready(Ok(None));
5530 }
5531 let request_task = upstream_client.request_lsp(
5532 project_id,
5533 None,
5534 LSP_REQUEST_TIMEOUT,
5535 cx.background_executor().clone(),
5536 request.to_proto(project_id, buffer.read(cx)),
5537 );
5538 let buffer = buffer.clone();
5539 cx.spawn(async move |weak_lsp_store, cx| {
5540 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5541 return Ok(None);
5542 };
5543 let Some(responses) = request_task.await? else {
5544 return Ok(None);
5545 };
5546 let actions = join_all(responses.payload.into_iter().map(|response| {
5547 GetTypeDefinitions { position }.response_from_proto(
5548 response.response,
5549 lsp_store.clone(),
5550 buffer.clone(),
5551 cx.clone(),
5552 )
5553 }))
5554 .await;
5555
5556 Ok(Some(
5557 actions
5558 .into_iter()
5559 .collect::<Result<Vec<Vec<_>>>>()?
5560 .into_iter()
5561 .flatten()
5562 .dedup()
5563 .collect(),
5564 ))
5565 })
5566 } else {
5567 let type_definitions_task = self.request_multiple_lsp_locally(
5568 buffer,
5569 Some(position),
5570 GetTypeDefinitions { position },
5571 cx,
5572 );
5573 cx.background_spawn(async move {
5574 Ok(Some(
5575 type_definitions_task
5576 .await
5577 .into_iter()
5578 .flat_map(|(_, type_definitions)| type_definitions)
5579 .dedup()
5580 .collect(),
5581 ))
5582 })
5583 }
5584 }
5585
5586 pub fn implementations(
5587 &mut self,
5588 buffer: &Entity<Buffer>,
5589 position: PointUtf16,
5590 cx: &mut Context<Self>,
5591 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5592 if let Some((upstream_client, project_id)) = self.upstream_client() {
5593 let request = GetImplementations { position };
5594 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5595 return Task::ready(Ok(None));
5596 }
5597 let request_task = upstream_client.request_lsp(
5598 project_id,
5599 None,
5600 LSP_REQUEST_TIMEOUT,
5601 cx.background_executor().clone(),
5602 request.to_proto(project_id, buffer.read(cx)),
5603 );
5604 let buffer = buffer.clone();
5605 cx.spawn(async move |weak_lsp_store, cx| {
5606 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5607 return Ok(None);
5608 };
5609 let Some(responses) = request_task.await? else {
5610 return Ok(None);
5611 };
5612 let actions = join_all(responses.payload.into_iter().map(|response| {
5613 GetImplementations { position }.response_from_proto(
5614 response.response,
5615 lsp_store.clone(),
5616 buffer.clone(),
5617 cx.clone(),
5618 )
5619 }))
5620 .await;
5621
5622 Ok(Some(
5623 actions
5624 .into_iter()
5625 .collect::<Result<Vec<Vec<_>>>>()?
5626 .into_iter()
5627 .flatten()
5628 .dedup()
5629 .collect(),
5630 ))
5631 })
5632 } else {
5633 let implementations_task = self.request_multiple_lsp_locally(
5634 buffer,
5635 Some(position),
5636 GetImplementations { position },
5637 cx,
5638 );
5639 cx.background_spawn(async move {
5640 Ok(Some(
5641 implementations_task
5642 .await
5643 .into_iter()
5644 .flat_map(|(_, implementations)| implementations)
5645 .dedup()
5646 .collect(),
5647 ))
5648 })
5649 }
5650 }
5651
5652 pub fn references(
5653 &mut self,
5654 buffer: &Entity<Buffer>,
5655 position: PointUtf16,
5656 cx: &mut Context<Self>,
5657 ) -> Task<Result<Option<Vec<Location>>>> {
5658 if let Some((upstream_client, project_id)) = self.upstream_client() {
5659 let request = GetReferences { position };
5660 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5661 return Task::ready(Ok(None));
5662 }
5663
5664 let request_task = upstream_client.request_lsp(
5665 project_id,
5666 None,
5667 LSP_REQUEST_TIMEOUT,
5668 cx.background_executor().clone(),
5669 request.to_proto(project_id, buffer.read(cx)),
5670 );
5671 let buffer = buffer.clone();
5672 cx.spawn(async move |weak_lsp_store, cx| {
5673 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5674 return Ok(None);
5675 };
5676 let Some(responses) = request_task.await? else {
5677 return Ok(None);
5678 };
5679
5680 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5681 GetReferences { position }.response_from_proto(
5682 lsp_response.response,
5683 lsp_store.clone(),
5684 buffer.clone(),
5685 cx.clone(),
5686 )
5687 }))
5688 .await
5689 .into_iter()
5690 .collect::<Result<Vec<Vec<_>>>>()?
5691 .into_iter()
5692 .flatten()
5693 .dedup()
5694 .collect();
5695 Ok(Some(locations))
5696 })
5697 } else {
5698 let references_task = self.request_multiple_lsp_locally(
5699 buffer,
5700 Some(position),
5701 GetReferences { position },
5702 cx,
5703 );
5704 cx.background_spawn(async move {
5705 Ok(Some(
5706 references_task
5707 .await
5708 .into_iter()
5709 .flat_map(|(_, references)| references)
5710 .dedup()
5711 .collect(),
5712 ))
5713 })
5714 }
5715 }
5716
5717 pub fn code_actions(
5718 &mut self,
5719 buffer: &Entity<Buffer>,
5720 range: Range<Anchor>,
5721 kinds: Option<Vec<CodeActionKind>>,
5722 cx: &mut Context<Self>,
5723 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5724 if let Some((upstream_client, project_id)) = self.upstream_client() {
5725 let request = GetCodeActions {
5726 range: range.clone(),
5727 kinds: kinds.clone(),
5728 };
5729 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5730 return Task::ready(Ok(None));
5731 }
5732 let request_task = upstream_client.request_lsp(
5733 project_id,
5734 None,
5735 LSP_REQUEST_TIMEOUT,
5736 cx.background_executor().clone(),
5737 request.to_proto(project_id, buffer.read(cx)),
5738 );
5739 let buffer = buffer.clone();
5740 cx.spawn(async move |weak_lsp_store, cx| {
5741 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5742 return Ok(None);
5743 };
5744 let Some(responses) = request_task.await? else {
5745 return Ok(None);
5746 };
5747 let actions = join_all(responses.payload.into_iter().map(|response| {
5748 GetCodeActions {
5749 range: range.clone(),
5750 kinds: kinds.clone(),
5751 }
5752 .response_from_proto(
5753 response.response,
5754 lsp_store.clone(),
5755 buffer.clone(),
5756 cx.clone(),
5757 )
5758 }))
5759 .await;
5760
5761 Ok(Some(
5762 actions
5763 .into_iter()
5764 .collect::<Result<Vec<Vec<_>>>>()?
5765 .into_iter()
5766 .flatten()
5767 .collect(),
5768 ))
5769 })
5770 } else {
5771 let all_actions_task = self.request_multiple_lsp_locally(
5772 buffer,
5773 Some(range.start),
5774 GetCodeActions { range, kinds },
5775 cx,
5776 );
5777 cx.background_spawn(async move {
5778 Ok(Some(
5779 all_actions_task
5780 .await
5781 .into_iter()
5782 .flat_map(|(_, actions)| actions)
5783 .collect(),
5784 ))
5785 })
5786 }
5787 }
5788
5789 pub fn code_lens_actions(
5790 &mut self,
5791 buffer: &Entity<Buffer>,
5792 cx: &mut Context<Self>,
5793 ) -> CodeLensTask {
5794 let version_queried_for = buffer.read(cx).version();
5795 let buffer_id = buffer.read(cx).remote_id();
5796 let existing_servers = self.as_local().map(|local| {
5797 local
5798 .buffers_opened_in_servers
5799 .get(&buffer_id)
5800 .cloned()
5801 .unwrap_or_default()
5802 });
5803
5804 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5805 if let Some(cached_lens) = &lsp_data.code_lens {
5806 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5807 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5808 existing_servers != cached_lens.lens.keys().copied().collect()
5809 });
5810 if !has_different_servers {
5811 return Task::ready(Ok(Some(
5812 cached_lens.lens.values().flatten().cloned().collect(),
5813 )))
5814 .shared();
5815 }
5816 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5817 if !version_queried_for.changed_since(updating_for) {
5818 return running_update.clone();
5819 }
5820 }
5821 }
5822 }
5823
5824 let lens_lsp_data = self
5825 .latest_lsp_data(buffer, cx)
5826 .code_lens
5827 .get_or_insert_default();
5828 let buffer = buffer.clone();
5829 let query_version_queried_for = version_queried_for.clone();
5830 let new_task = cx
5831 .spawn(async move |lsp_store, cx| {
5832 cx.background_executor()
5833 .timer(Duration::from_millis(30))
5834 .await;
5835 let fetched_lens = lsp_store
5836 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5837 .map_err(Arc::new)?
5838 .await
5839 .context("fetching code lens")
5840 .map_err(Arc::new);
5841 let fetched_lens = match fetched_lens {
5842 Ok(fetched_lens) => fetched_lens,
5843 Err(e) => {
5844 lsp_store
5845 .update(cx, |lsp_store, _| {
5846 if let Some(lens_lsp_data) = lsp_store
5847 .lsp_data
5848 .get_mut(&buffer_id)
5849 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5850 {
5851 lens_lsp_data.update = None;
5852 }
5853 })
5854 .ok();
5855 return Err(e);
5856 }
5857 };
5858
5859 lsp_store
5860 .update(cx, |lsp_store, _| {
5861 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5862 let code_lens = lsp_data.code_lens.as_mut()?;
5863 if let Some(fetched_lens) = fetched_lens {
5864 if lsp_data.buffer_version == query_version_queried_for {
5865 code_lens.lens.extend(fetched_lens);
5866 } else if !lsp_data
5867 .buffer_version
5868 .changed_since(&query_version_queried_for)
5869 {
5870 lsp_data.buffer_version = query_version_queried_for;
5871 code_lens.lens = fetched_lens;
5872 }
5873 }
5874 code_lens.update = None;
5875 Some(code_lens.lens.values().flatten().cloned().collect())
5876 })
5877 .map_err(Arc::new)
5878 })
5879 .shared();
5880 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5881 new_task
5882 }
5883
5884 fn fetch_code_lens(
5885 &mut self,
5886 buffer: &Entity<Buffer>,
5887 cx: &mut Context<Self>,
5888 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5889 if let Some((upstream_client, project_id)) = self.upstream_client() {
5890 let request = GetCodeLens;
5891 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5892 return Task::ready(Ok(None));
5893 }
5894 let request_task = upstream_client.request_lsp(
5895 project_id,
5896 None,
5897 LSP_REQUEST_TIMEOUT,
5898 cx.background_executor().clone(),
5899 request.to_proto(project_id, buffer.read(cx)),
5900 );
5901 let buffer = buffer.clone();
5902 cx.spawn(async move |weak_lsp_store, cx| {
5903 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5904 return Ok(None);
5905 };
5906 let Some(responses) = request_task.await? else {
5907 return Ok(None);
5908 };
5909
5910 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5911 let lsp_store = lsp_store.clone();
5912 let buffer = buffer.clone();
5913 let cx = cx.clone();
5914 async move {
5915 (
5916 LanguageServerId::from_proto(response.server_id),
5917 GetCodeLens
5918 .response_from_proto(response.response, lsp_store, buffer, cx)
5919 .await,
5920 )
5921 }
5922 }))
5923 .await;
5924
5925 let mut has_errors = false;
5926 let code_lens_actions = code_lens_actions
5927 .into_iter()
5928 .filter_map(|(server_id, code_lens)| match code_lens {
5929 Ok(code_lens) => Some((server_id, code_lens)),
5930 Err(e) => {
5931 has_errors = true;
5932 log::error!("{e:#}");
5933 None
5934 }
5935 })
5936 .collect::<HashMap<_, _>>();
5937 anyhow::ensure!(
5938 !has_errors || !code_lens_actions.is_empty(),
5939 "Failed to fetch code lens"
5940 );
5941 Ok(Some(code_lens_actions))
5942 })
5943 } else {
5944 let code_lens_actions_task =
5945 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5946 cx.background_spawn(async move {
5947 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5948 })
5949 }
5950 }
5951
5952 #[inline(never)]
5953 pub fn completions(
5954 &self,
5955 buffer: &Entity<Buffer>,
5956 position: PointUtf16,
5957 context: CompletionContext,
5958 cx: &mut Context<Self>,
5959 ) -> Task<Result<Vec<CompletionResponse>>> {
5960 let language_registry = self.languages.clone();
5961
5962 if let Some((upstream_client, project_id)) = self.upstream_client() {
5963 let snapshot = buffer.read(cx).snapshot();
5964 let offset = position.to_offset(&snapshot);
5965 let scope = snapshot.language_scope_at(offset);
5966 let capable_lsps = self.all_capable_for_proto_request(
5967 buffer,
5968 |server_name, capabilities| {
5969 capabilities.completion_provider.is_some()
5970 && scope
5971 .as_ref()
5972 .map(|scope| scope.language_allowed(server_name))
5973 .unwrap_or(true)
5974 },
5975 cx,
5976 );
5977 if capable_lsps.is_empty() {
5978 return Task::ready(Ok(Vec::new()));
5979 }
5980
5981 let language = buffer.read(cx).language().cloned();
5982
5983 // In the future, we should provide project guests with the names of LSP adapters,
5984 // so that they can use the correct LSP adapter when computing labels. For now,
5985 // guests just use the first LSP adapter associated with the buffer's language.
5986 let lsp_adapter = language.as_ref().and_then(|language| {
5987 language_registry
5988 .lsp_adapters(&language.name())
5989 .first()
5990 .cloned()
5991 });
5992
5993 let buffer = buffer.clone();
5994
5995 cx.spawn(async move |this, cx| {
5996 let requests = join_all(
5997 capable_lsps
5998 .into_iter()
5999 .map(|id| {
6000 let request = GetCompletions {
6001 position,
6002 context: context.clone(),
6003 server_id: Some(id),
6004 };
6005 let buffer = buffer.clone();
6006 let language = language.clone();
6007 let lsp_adapter = lsp_adapter.clone();
6008 let upstream_client = upstream_client.clone();
6009 let response = this
6010 .update(cx, |this, cx| {
6011 this.send_lsp_proto_request(
6012 buffer,
6013 upstream_client,
6014 project_id,
6015 request,
6016 cx,
6017 )
6018 })
6019 .log_err();
6020 async move {
6021 let response = response?.await.log_err()?;
6022
6023 let completions = populate_labels_for_completions(
6024 response.completions,
6025 language,
6026 lsp_adapter,
6027 )
6028 .await;
6029
6030 Some(CompletionResponse {
6031 completions,
6032 display_options: CompletionDisplayOptions::default(),
6033 is_incomplete: response.is_incomplete,
6034 })
6035 }
6036 })
6037 .collect::<Vec<_>>(),
6038 );
6039 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6040 })
6041 } else if let Some(local) = self.as_local() {
6042 let snapshot = buffer.read(cx).snapshot();
6043 let offset = position.to_offset(&snapshot);
6044 let scope = snapshot.language_scope_at(offset);
6045 let language = snapshot.language().cloned();
6046 let completion_settings = language_settings(
6047 language.as_ref().map(|language| language.name()),
6048 buffer.read(cx).file(),
6049 cx,
6050 )
6051 .completions
6052 .clone();
6053 if !completion_settings.lsp {
6054 return Task::ready(Ok(Vec::new()));
6055 }
6056
6057 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6058 local
6059 .language_servers_for_buffer(buffer, cx)
6060 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6061 .filter(|(adapter, _)| {
6062 scope
6063 .as_ref()
6064 .map(|scope| scope.language_allowed(&adapter.name))
6065 .unwrap_or(true)
6066 })
6067 .map(|(_, server)| server.server_id())
6068 .collect()
6069 });
6070
6071 let buffer = buffer.clone();
6072 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6073 let lsp_timeout = if lsp_timeout > 0 {
6074 Some(Duration::from_millis(lsp_timeout))
6075 } else {
6076 None
6077 };
6078 cx.spawn(async move |this, cx| {
6079 let mut tasks = Vec::with_capacity(server_ids.len());
6080 this.update(cx, |lsp_store, cx| {
6081 for server_id in server_ids {
6082 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6083 let lsp_timeout = lsp_timeout
6084 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6085 let mut timeout = cx.background_spawn(async move {
6086 match lsp_timeout {
6087 Some(lsp_timeout) => {
6088 lsp_timeout.await;
6089 true
6090 },
6091 None => false,
6092 }
6093 }).fuse();
6094 let mut lsp_request = lsp_store.request_lsp(
6095 buffer.clone(),
6096 LanguageServerToQuery::Other(server_id),
6097 GetCompletions {
6098 position,
6099 context: context.clone(),
6100 server_id: Some(server_id),
6101 },
6102 cx,
6103 ).fuse();
6104 let new_task = cx.background_spawn(async move {
6105 select_biased! {
6106 response = lsp_request => anyhow::Ok(Some(response?)),
6107 timeout_happened = timeout => {
6108 if timeout_happened {
6109 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6110 Ok(None)
6111 } else {
6112 let completions = lsp_request.await?;
6113 Ok(Some(completions))
6114 }
6115 },
6116 }
6117 });
6118 tasks.push((lsp_adapter, new_task));
6119 }
6120 })?;
6121
6122 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6123 let completion_response = task.await.ok()??;
6124 let completions = populate_labels_for_completions(
6125 completion_response.completions,
6126 language.clone(),
6127 lsp_adapter,
6128 )
6129 .await;
6130 Some(CompletionResponse {
6131 completions,
6132 display_options: CompletionDisplayOptions::default(),
6133 is_incomplete: completion_response.is_incomplete,
6134 })
6135 });
6136
6137 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6138
6139 Ok(responses.into_iter().flatten().collect())
6140 })
6141 } else {
6142 Task::ready(Err(anyhow!("No upstream client or local language server")))
6143 }
6144 }
6145
6146 pub fn resolve_completions(
6147 &self,
6148 buffer: Entity<Buffer>,
6149 completion_indices: Vec<usize>,
6150 completions: Rc<RefCell<Box<[Completion]>>>,
6151 cx: &mut Context<Self>,
6152 ) -> Task<Result<bool>> {
6153 let client = self.upstream_client();
6154 let buffer_id = buffer.read(cx).remote_id();
6155 let buffer_snapshot = buffer.read(cx).snapshot();
6156
6157 if !self.check_if_capable_for_proto_request(
6158 &buffer,
6159 GetCompletions::can_resolve_completions,
6160 cx,
6161 ) {
6162 return Task::ready(Ok(false));
6163 }
6164 cx.spawn(async move |lsp_store, cx| {
6165 let mut did_resolve = false;
6166 if let Some((client, project_id)) = client {
6167 for completion_index in completion_indices {
6168 let server_id = {
6169 let completion = &completions.borrow()[completion_index];
6170 completion.source.server_id()
6171 };
6172 if let Some(server_id) = server_id {
6173 if Self::resolve_completion_remote(
6174 project_id,
6175 server_id,
6176 buffer_id,
6177 completions.clone(),
6178 completion_index,
6179 client.clone(),
6180 )
6181 .await
6182 .log_err()
6183 .is_some()
6184 {
6185 did_resolve = true;
6186 }
6187 } else {
6188 resolve_word_completion(
6189 &buffer_snapshot,
6190 &mut completions.borrow_mut()[completion_index],
6191 );
6192 }
6193 }
6194 } else {
6195 for completion_index in completion_indices {
6196 let server_id = {
6197 let completion = &completions.borrow()[completion_index];
6198 completion.source.server_id()
6199 };
6200 if let Some(server_id) = server_id {
6201 let server_and_adapter = lsp_store
6202 .read_with(cx, |lsp_store, _| {
6203 let server = lsp_store.language_server_for_id(server_id)?;
6204 let adapter =
6205 lsp_store.language_server_adapter_for_id(server.server_id())?;
6206 Some((server, adapter))
6207 })
6208 .ok()
6209 .flatten();
6210 let Some((server, adapter)) = server_and_adapter else {
6211 continue;
6212 };
6213
6214 let resolved = Self::resolve_completion_local(
6215 server,
6216 completions.clone(),
6217 completion_index,
6218 )
6219 .await
6220 .log_err()
6221 .is_some();
6222 if resolved {
6223 Self::regenerate_completion_labels(
6224 adapter,
6225 &buffer_snapshot,
6226 completions.clone(),
6227 completion_index,
6228 )
6229 .await
6230 .log_err();
6231 did_resolve = true;
6232 }
6233 } else {
6234 resolve_word_completion(
6235 &buffer_snapshot,
6236 &mut completions.borrow_mut()[completion_index],
6237 );
6238 }
6239 }
6240 }
6241
6242 Ok(did_resolve)
6243 })
6244 }
6245
6246 async fn resolve_completion_local(
6247 server: Arc<lsp::LanguageServer>,
6248 completions: Rc<RefCell<Box<[Completion]>>>,
6249 completion_index: usize,
6250 ) -> Result<()> {
6251 let server_id = server.server_id();
6252 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6253 return Ok(());
6254 }
6255
6256 let request = {
6257 let completion = &completions.borrow()[completion_index];
6258 match &completion.source {
6259 CompletionSource::Lsp {
6260 lsp_completion,
6261 resolved,
6262 server_id: completion_server_id,
6263 ..
6264 } => {
6265 if *resolved {
6266 return Ok(());
6267 }
6268 anyhow::ensure!(
6269 server_id == *completion_server_id,
6270 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6271 );
6272 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6273 }
6274 CompletionSource::BufferWord { .. }
6275 | CompletionSource::Dap { .. }
6276 | CompletionSource::Custom => {
6277 return Ok(());
6278 }
6279 }
6280 };
6281 let resolved_completion = request
6282 .await
6283 .into_response()
6284 .context("resolve completion")?;
6285
6286 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6287 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6288
6289 let mut completions = completions.borrow_mut();
6290 let completion = &mut completions[completion_index];
6291 if let CompletionSource::Lsp {
6292 lsp_completion,
6293 resolved,
6294 server_id: completion_server_id,
6295 ..
6296 } = &mut completion.source
6297 {
6298 if *resolved {
6299 return Ok(());
6300 }
6301 anyhow::ensure!(
6302 server_id == *completion_server_id,
6303 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6304 );
6305 *lsp_completion = Box::new(resolved_completion);
6306 *resolved = true;
6307 }
6308 Ok(())
6309 }
6310
6311 async fn regenerate_completion_labels(
6312 adapter: Arc<CachedLspAdapter>,
6313 snapshot: &BufferSnapshot,
6314 completions: Rc<RefCell<Box<[Completion]>>>,
6315 completion_index: usize,
6316 ) -> Result<()> {
6317 let completion_item = completions.borrow()[completion_index]
6318 .source
6319 .lsp_completion(true)
6320 .map(Cow::into_owned);
6321 if let Some(lsp_documentation) = completion_item
6322 .as_ref()
6323 .and_then(|completion_item| completion_item.documentation.clone())
6324 {
6325 let mut completions = completions.borrow_mut();
6326 let completion = &mut completions[completion_index];
6327 completion.documentation = Some(lsp_documentation.into());
6328 } else {
6329 let mut completions = completions.borrow_mut();
6330 let completion = &mut completions[completion_index];
6331 completion.documentation = Some(CompletionDocumentation::Undocumented);
6332 }
6333
6334 let mut new_label = match completion_item {
6335 Some(completion_item) => {
6336 // 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
6337 // So we have to update the label here anyway...
6338 let language = snapshot.language();
6339 match language {
6340 Some(language) => {
6341 adapter
6342 .labels_for_completions(
6343 std::slice::from_ref(&completion_item),
6344 language,
6345 )
6346 .await?
6347 }
6348 None => Vec::new(),
6349 }
6350 .pop()
6351 .flatten()
6352 .unwrap_or_else(|| {
6353 CodeLabel::fallback_for_completion(
6354 &completion_item,
6355 language.map(|language| language.as_ref()),
6356 )
6357 })
6358 }
6359 None => CodeLabel::plain(
6360 completions.borrow()[completion_index].new_text.clone(),
6361 None,
6362 ),
6363 };
6364 ensure_uniform_list_compatible_label(&mut new_label);
6365
6366 let mut completions = completions.borrow_mut();
6367 let completion = &mut completions[completion_index];
6368 if completion.label.filter_text() == new_label.filter_text() {
6369 completion.label = new_label;
6370 } else {
6371 log::error!(
6372 "Resolved completion changed display label from {} to {}. \
6373 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6374 completion.label.text(),
6375 new_label.text(),
6376 completion.label.filter_text(),
6377 new_label.filter_text()
6378 );
6379 }
6380
6381 Ok(())
6382 }
6383
6384 async fn resolve_completion_remote(
6385 project_id: u64,
6386 server_id: LanguageServerId,
6387 buffer_id: BufferId,
6388 completions: Rc<RefCell<Box<[Completion]>>>,
6389 completion_index: usize,
6390 client: AnyProtoClient,
6391 ) -> Result<()> {
6392 let lsp_completion = {
6393 let completion = &completions.borrow()[completion_index];
6394 match &completion.source {
6395 CompletionSource::Lsp {
6396 lsp_completion,
6397 resolved,
6398 server_id: completion_server_id,
6399 ..
6400 } => {
6401 anyhow::ensure!(
6402 server_id == *completion_server_id,
6403 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6404 );
6405 if *resolved {
6406 return Ok(());
6407 }
6408 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6409 }
6410 CompletionSource::Custom
6411 | CompletionSource::Dap { .. }
6412 | CompletionSource::BufferWord { .. } => {
6413 return Ok(());
6414 }
6415 }
6416 };
6417 let request = proto::ResolveCompletionDocumentation {
6418 project_id,
6419 language_server_id: server_id.0 as u64,
6420 lsp_completion,
6421 buffer_id: buffer_id.into(),
6422 };
6423
6424 let response = client
6425 .request(request)
6426 .await
6427 .context("completion documentation resolve proto request")?;
6428 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6429
6430 let documentation = if response.documentation.is_empty() {
6431 CompletionDocumentation::Undocumented
6432 } else if response.documentation_is_markdown {
6433 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6434 } else if response.documentation.lines().count() <= 1 {
6435 CompletionDocumentation::SingleLine(response.documentation.into())
6436 } else {
6437 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6438 };
6439
6440 let mut completions = completions.borrow_mut();
6441 let completion = &mut completions[completion_index];
6442 completion.documentation = Some(documentation);
6443 if let CompletionSource::Lsp {
6444 insert_range,
6445 lsp_completion,
6446 resolved,
6447 server_id: completion_server_id,
6448 lsp_defaults: _,
6449 } = &mut completion.source
6450 {
6451 let completion_insert_range = response
6452 .old_insert_start
6453 .and_then(deserialize_anchor)
6454 .zip(response.old_insert_end.and_then(deserialize_anchor));
6455 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6456
6457 if *resolved {
6458 return Ok(());
6459 }
6460 anyhow::ensure!(
6461 server_id == *completion_server_id,
6462 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6463 );
6464 *lsp_completion = Box::new(resolved_lsp_completion);
6465 *resolved = true;
6466 }
6467
6468 let replace_range = response
6469 .old_replace_start
6470 .and_then(deserialize_anchor)
6471 .zip(response.old_replace_end.and_then(deserialize_anchor));
6472 if let Some((old_replace_start, old_replace_end)) = replace_range
6473 && !response.new_text.is_empty()
6474 {
6475 completion.new_text = response.new_text;
6476 completion.replace_range = old_replace_start..old_replace_end;
6477 }
6478
6479 Ok(())
6480 }
6481
6482 pub fn apply_additional_edits_for_completion(
6483 &self,
6484 buffer_handle: Entity<Buffer>,
6485 completions: Rc<RefCell<Box<[Completion]>>>,
6486 completion_index: usize,
6487 push_to_history: bool,
6488 cx: &mut Context<Self>,
6489 ) -> Task<Result<Option<Transaction>>> {
6490 if let Some((client, project_id)) = self.upstream_client() {
6491 let buffer = buffer_handle.read(cx);
6492 let buffer_id = buffer.remote_id();
6493 cx.spawn(async move |_, cx| {
6494 let request = {
6495 let completion = completions.borrow()[completion_index].clone();
6496 proto::ApplyCompletionAdditionalEdits {
6497 project_id,
6498 buffer_id: buffer_id.into(),
6499 completion: Some(Self::serialize_completion(&CoreCompletion {
6500 replace_range: completion.replace_range,
6501 new_text: completion.new_text,
6502 source: completion.source,
6503 })),
6504 }
6505 };
6506
6507 if let Some(transaction) = client.request(request).await?.transaction {
6508 let transaction = language::proto::deserialize_transaction(transaction)?;
6509 buffer_handle
6510 .update(cx, |buffer, _| {
6511 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6512 })?
6513 .await?;
6514 if push_to_history {
6515 buffer_handle.update(cx, |buffer, _| {
6516 buffer.push_transaction(transaction.clone(), Instant::now());
6517 buffer.finalize_last_transaction();
6518 })?;
6519 }
6520 Ok(Some(transaction))
6521 } else {
6522 Ok(None)
6523 }
6524 })
6525 } else {
6526 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6527 let completion = &completions.borrow()[completion_index];
6528 let server_id = completion.source.server_id()?;
6529 Some(
6530 self.language_server_for_local_buffer(buffer, server_id, cx)?
6531 .1
6532 .clone(),
6533 )
6534 }) else {
6535 return Task::ready(Ok(None));
6536 };
6537
6538 cx.spawn(async move |this, cx| {
6539 Self::resolve_completion_local(
6540 server.clone(),
6541 completions.clone(),
6542 completion_index,
6543 )
6544 .await
6545 .context("resolving completion")?;
6546 let completion = completions.borrow()[completion_index].clone();
6547 let additional_text_edits = completion
6548 .source
6549 .lsp_completion(true)
6550 .as_ref()
6551 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6552 if let Some(edits) = additional_text_edits {
6553 let edits = this
6554 .update(cx, |this, cx| {
6555 this.as_local_mut().unwrap().edits_from_lsp(
6556 &buffer_handle,
6557 edits,
6558 server.server_id(),
6559 None,
6560 cx,
6561 )
6562 })?
6563 .await?;
6564
6565 buffer_handle.update(cx, |buffer, cx| {
6566 buffer.finalize_last_transaction();
6567 buffer.start_transaction();
6568
6569 for (range, text) in edits {
6570 let primary = &completion.replace_range;
6571
6572 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6573 // and the primary completion is just an insertion (empty range), then this is likely
6574 // an auto-import scenario and should not be considered overlapping
6575 // https://github.com/zed-industries/zed/issues/26136
6576 let is_file_start_auto_import = {
6577 let snapshot = buffer.snapshot();
6578 let primary_start_point = primary.start.to_point(&snapshot);
6579 let range_start_point = range.start.to_point(&snapshot);
6580
6581 let result = primary_start_point.row == 0
6582 && primary_start_point.column == 0
6583 && range_start_point.row == 0
6584 && range_start_point.column == 0;
6585
6586 result
6587 };
6588
6589 let has_overlap = if is_file_start_auto_import {
6590 false
6591 } else {
6592 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6593 && primary.end.cmp(&range.start, buffer).is_ge();
6594 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6595 && range.end.cmp(&primary.end, buffer).is_ge();
6596 let result = start_within || end_within;
6597 result
6598 };
6599
6600 //Skip additional edits which overlap with the primary completion edit
6601 //https://github.com/zed-industries/zed/pull/1871
6602 if !has_overlap {
6603 buffer.edit([(range, text)], None, cx);
6604 }
6605 }
6606
6607 let transaction = if buffer.end_transaction(cx).is_some() {
6608 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6609 if !push_to_history {
6610 buffer.forget_transaction(transaction.id);
6611 }
6612 Some(transaction)
6613 } else {
6614 None
6615 };
6616 Ok(transaction)
6617 })?
6618 } else {
6619 Ok(None)
6620 }
6621 })
6622 }
6623 }
6624
6625 pub fn pull_diagnostics(
6626 &mut self,
6627 buffer: Entity<Buffer>,
6628 cx: &mut Context<Self>,
6629 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6630 let buffer_id = buffer.read(cx).remote_id();
6631
6632 if let Some((client, upstream_project_id)) = self.upstream_client() {
6633 let mut suitable_capabilities = None;
6634 // Are we capable for proto request?
6635 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6636 &buffer,
6637 |capabilities| {
6638 if let Some(caps) = &capabilities.diagnostic_provider {
6639 suitable_capabilities = Some(caps.clone());
6640 true
6641 } else {
6642 false
6643 }
6644 },
6645 cx,
6646 );
6647 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6648 let Some(dynamic_caps) = suitable_capabilities else {
6649 return Task::ready(Ok(None));
6650 };
6651 assert!(any_server_has_diagnostics_provider);
6652
6653 let request = GetDocumentDiagnostics {
6654 previous_result_id: None,
6655 dynamic_caps,
6656 };
6657 let request_task = client.request_lsp(
6658 upstream_project_id,
6659 None,
6660 LSP_REQUEST_TIMEOUT,
6661 cx.background_executor().clone(),
6662 request.to_proto(upstream_project_id, buffer.read(cx)),
6663 );
6664 cx.background_spawn(async move {
6665 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6666 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6667 // Do not attempt to further process the dummy responses here.
6668 let _response = request_task.await?;
6669 Ok(None)
6670 })
6671 } else {
6672 let servers = buffer.update(cx, |buffer, cx| {
6673 self.language_servers_for_local_buffer(buffer, cx)
6674 .map(|(_, server)| server.clone())
6675 .collect::<Vec<_>>()
6676 });
6677
6678 let pull_diagnostics = servers
6679 .into_iter()
6680 .flat_map(|server| {
6681 let result = maybe!({
6682 let local = self.as_local()?;
6683 let server_id = server.server_id();
6684 let providers_with_identifiers = local
6685 .language_server_dynamic_registrations
6686 .get(&server_id)
6687 .into_iter()
6688 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6689 .collect::<Vec<_>>();
6690 Some(
6691 providers_with_identifiers
6692 .into_iter()
6693 .map(|dynamic_caps| {
6694 let result_id = self.result_id(server_id, buffer_id, cx);
6695 self.request_lsp(
6696 buffer.clone(),
6697 LanguageServerToQuery::Other(server_id),
6698 GetDocumentDiagnostics {
6699 previous_result_id: result_id,
6700 dynamic_caps,
6701 },
6702 cx,
6703 )
6704 })
6705 .collect::<Vec<_>>(),
6706 )
6707 });
6708
6709 result.unwrap_or_default()
6710 })
6711 .collect::<Vec<_>>();
6712
6713 cx.background_spawn(async move {
6714 let mut responses = Vec::new();
6715 for diagnostics in join_all(pull_diagnostics).await {
6716 responses.extend(diagnostics?);
6717 }
6718 Ok(Some(responses))
6719 })
6720 }
6721 }
6722
6723 pub fn applicable_inlay_chunks(
6724 &mut self,
6725 buffer: &Entity<Buffer>,
6726 ranges: &[Range<text::Anchor>],
6727 cx: &mut Context<Self>,
6728 ) -> Vec<Range<BufferRow>> {
6729 self.latest_lsp_data(buffer, cx)
6730 .inlay_hints
6731 .applicable_chunks(ranges)
6732 .map(|chunk| chunk.row_range())
6733 .collect()
6734 }
6735
6736 pub fn invalidate_inlay_hints<'a>(
6737 &'a mut self,
6738 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6739 ) {
6740 for buffer_id in for_buffers {
6741 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6742 lsp_data.inlay_hints.clear();
6743 }
6744 }
6745 }
6746
6747 pub fn inlay_hints(
6748 &mut self,
6749 invalidate: InvalidationStrategy,
6750 buffer: Entity<Buffer>,
6751 ranges: Vec<Range<text::Anchor>>,
6752 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6753 cx: &mut Context<Self>,
6754 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6755 let next_hint_id = self.next_hint_id.clone();
6756 let lsp_data = self.latest_lsp_data(&buffer, cx);
6757 let query_version = lsp_data.buffer_version.clone();
6758 let mut lsp_refresh_requested = false;
6759 let for_server = if let InvalidationStrategy::RefreshRequested {
6760 server_id,
6761 request_id,
6762 } = invalidate
6763 {
6764 let invalidated = lsp_data
6765 .inlay_hints
6766 .invalidate_for_server_refresh(server_id, request_id);
6767 lsp_refresh_requested = invalidated;
6768 Some(server_id)
6769 } else {
6770 None
6771 };
6772 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6773 let known_chunks = known_chunks
6774 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6775 .map(|(_, known_chunks)| known_chunks)
6776 .unwrap_or_default();
6777
6778 let mut hint_fetch_tasks = Vec::new();
6779 let mut cached_inlay_hints = None;
6780 let mut ranges_to_query = None;
6781 let applicable_chunks = existing_inlay_hints
6782 .applicable_chunks(ranges.as_slice())
6783 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6784 .collect::<Vec<_>>();
6785 if applicable_chunks.is_empty() {
6786 return HashMap::default();
6787 }
6788
6789 for row_chunk in applicable_chunks {
6790 match (
6791 existing_inlay_hints
6792 .cached_hints(&row_chunk)
6793 .filter(|_| !lsp_refresh_requested)
6794 .cloned(),
6795 existing_inlay_hints
6796 .fetched_hints(&row_chunk)
6797 .as_ref()
6798 .filter(|_| !lsp_refresh_requested)
6799 .cloned(),
6800 ) {
6801 (None, None) => {
6802 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6803 continue;
6804 };
6805 ranges_to_query
6806 .get_or_insert_with(Vec::new)
6807 .push((row_chunk, chunk_range));
6808 }
6809 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6810 (Some(cached_hints), None) => {
6811 for (server_id, cached_hints) in cached_hints {
6812 if for_server.is_none_or(|for_server| for_server == server_id) {
6813 cached_inlay_hints
6814 .get_or_insert_with(HashMap::default)
6815 .entry(row_chunk.row_range())
6816 .or_insert_with(HashMap::default)
6817 .entry(server_id)
6818 .or_insert_with(Vec::new)
6819 .extend(cached_hints);
6820 }
6821 }
6822 }
6823 (Some(cached_hints), Some(fetched_hints)) => {
6824 hint_fetch_tasks.push((row_chunk, fetched_hints));
6825 for (server_id, cached_hints) in cached_hints {
6826 if for_server.is_none_or(|for_server| for_server == server_id) {
6827 cached_inlay_hints
6828 .get_or_insert_with(HashMap::default)
6829 .entry(row_chunk.row_range())
6830 .or_insert_with(HashMap::default)
6831 .entry(server_id)
6832 .or_insert_with(Vec::new)
6833 .extend(cached_hints);
6834 }
6835 }
6836 }
6837 }
6838 }
6839
6840 if hint_fetch_tasks.is_empty()
6841 && ranges_to_query
6842 .as_ref()
6843 .is_none_or(|ranges| ranges.is_empty())
6844 && let Some(cached_inlay_hints) = cached_inlay_hints
6845 {
6846 cached_inlay_hints
6847 .into_iter()
6848 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6849 .collect()
6850 } else {
6851 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6852 let next_hint_id = next_hint_id.clone();
6853 let buffer = buffer.clone();
6854 let query_version = query_version.clone();
6855 let new_inlay_hints = cx
6856 .spawn(async move |lsp_store, cx| {
6857 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6858 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6859 })?;
6860 new_fetch_task
6861 .await
6862 .and_then(|new_hints_by_server| {
6863 lsp_store.update(cx, |lsp_store, cx| {
6864 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6865 let update_cache = lsp_data.buffer_version == query_version;
6866 if new_hints_by_server.is_empty() {
6867 if update_cache {
6868 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6869 }
6870 HashMap::default()
6871 } else {
6872 new_hints_by_server
6873 .into_iter()
6874 .map(|(server_id, new_hints)| {
6875 let new_hints = new_hints
6876 .into_iter()
6877 .map(|new_hint| {
6878 (
6879 InlayId::Hint(next_hint_id.fetch_add(
6880 1,
6881 atomic::Ordering::AcqRel,
6882 )),
6883 new_hint,
6884 )
6885 })
6886 .collect::<Vec<_>>();
6887 if update_cache {
6888 lsp_data.inlay_hints.insert_new_hints(
6889 chunk,
6890 server_id,
6891 new_hints.clone(),
6892 );
6893 }
6894 (server_id, new_hints)
6895 })
6896 .collect()
6897 }
6898 })
6899 })
6900 .map_err(Arc::new)
6901 })
6902 .shared();
6903
6904 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6905 *fetch_task = Some(new_inlay_hints.clone());
6906 hint_fetch_tasks.push((chunk, new_inlay_hints));
6907 }
6908
6909 cached_inlay_hints
6910 .unwrap_or_default()
6911 .into_iter()
6912 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6913 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6914 (
6915 chunk.row_range(),
6916 cx.spawn(async move |_, _| {
6917 hints_fetch.await.map_err(|e| {
6918 if e.error_code() != ErrorCode::Internal {
6919 anyhow!(e.error_code())
6920 } else {
6921 anyhow!("{e:#}")
6922 }
6923 })
6924 }),
6925 )
6926 }))
6927 .collect()
6928 }
6929 }
6930
6931 fn fetch_inlay_hints(
6932 &mut self,
6933 for_server: Option<LanguageServerId>,
6934 buffer: &Entity<Buffer>,
6935 range: Range<Anchor>,
6936 cx: &mut Context<Self>,
6937 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6938 let request = InlayHints {
6939 range: range.clone(),
6940 };
6941 if let Some((upstream_client, project_id)) = self.upstream_client() {
6942 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6943 return Task::ready(Ok(HashMap::default()));
6944 }
6945 let request_task = upstream_client.request_lsp(
6946 project_id,
6947 for_server.map(|id| id.to_proto()),
6948 LSP_REQUEST_TIMEOUT,
6949 cx.background_executor().clone(),
6950 request.to_proto(project_id, buffer.read(cx)),
6951 );
6952 let buffer = buffer.clone();
6953 cx.spawn(async move |weak_lsp_store, cx| {
6954 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6955 return Ok(HashMap::default());
6956 };
6957 let Some(responses) = request_task.await? else {
6958 return Ok(HashMap::default());
6959 };
6960
6961 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6962 let lsp_store = lsp_store.clone();
6963 let buffer = buffer.clone();
6964 let cx = cx.clone();
6965 let request = request.clone();
6966 async move {
6967 (
6968 LanguageServerId::from_proto(response.server_id),
6969 request
6970 .response_from_proto(response.response, lsp_store, buffer, cx)
6971 .await,
6972 )
6973 }
6974 }))
6975 .await;
6976
6977 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
6978 let mut has_errors = false;
6979 let inlay_hints = inlay_hints
6980 .into_iter()
6981 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6982 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6983 Err(e) => {
6984 has_errors = true;
6985 log::error!("{e:#}");
6986 None
6987 }
6988 })
6989 .map(|(server_id, mut new_hints)| {
6990 new_hints.retain(|hint| {
6991 hint.position.is_valid(&buffer_snapshot)
6992 && range.start.is_valid(&buffer_snapshot)
6993 && range.end.is_valid(&buffer_snapshot)
6994 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6995 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6996 });
6997 (server_id, new_hints)
6998 })
6999 .collect::<HashMap<_, _>>();
7000 anyhow::ensure!(
7001 !has_errors || !inlay_hints.is_empty(),
7002 "Failed to fetch inlay hints"
7003 );
7004 Ok(inlay_hints)
7005 })
7006 } else {
7007 let inlay_hints_task = match for_server {
7008 Some(server_id) => {
7009 let server_task = self.request_lsp(
7010 buffer.clone(),
7011 LanguageServerToQuery::Other(server_id),
7012 request,
7013 cx,
7014 );
7015 cx.background_spawn(async move {
7016 let mut responses = Vec::new();
7017 match server_task.await {
7018 Ok(response) => responses.push((server_id, response)),
7019 // rust-analyzer likes to error with this when its still loading up
7020 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7021 Err(e) => log::error!(
7022 "Error handling response for inlay hints request: {e:#}"
7023 ),
7024 }
7025 responses
7026 })
7027 }
7028 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7029 };
7030 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7031 cx.background_spawn(async move {
7032 Ok(inlay_hints_task
7033 .await
7034 .into_iter()
7035 .map(|(server_id, mut new_hints)| {
7036 new_hints.retain(|hint| {
7037 hint.position.is_valid(&buffer_snapshot)
7038 && range.start.is_valid(&buffer_snapshot)
7039 && range.end.is_valid(&buffer_snapshot)
7040 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7041 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7042 });
7043 (server_id, new_hints)
7044 })
7045 .collect())
7046 })
7047 }
7048 }
7049
7050 pub fn pull_diagnostics_for_buffer(
7051 &mut self,
7052 buffer: Entity<Buffer>,
7053 cx: &mut Context<Self>,
7054 ) -> Task<anyhow::Result<()>> {
7055 let diagnostics = self.pull_diagnostics(buffer, cx);
7056 cx.spawn(async move |lsp_store, cx| {
7057 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7058 return Ok(());
7059 };
7060 lsp_store.update(cx, |lsp_store, cx| {
7061 if lsp_store.as_local().is_none() {
7062 return;
7063 }
7064
7065 let mut unchanged_buffers = HashSet::default();
7066 let mut changed_buffers = HashSet::default();
7067 let server_diagnostics_updates = diagnostics
7068 .into_iter()
7069 .filter_map(|diagnostics_set| match diagnostics_set {
7070 LspPullDiagnostics::Response {
7071 server_id,
7072 uri,
7073 diagnostics,
7074 } => Some((server_id, uri, diagnostics)),
7075 LspPullDiagnostics::Default => None,
7076 })
7077 .fold(
7078 HashMap::default(),
7079 |mut acc, (server_id, uri, diagnostics)| {
7080 let (result_id, diagnostics) = match diagnostics {
7081 PulledDiagnostics::Unchanged { result_id } => {
7082 unchanged_buffers.insert(uri.clone());
7083 (Some(result_id), Vec::new())
7084 }
7085 PulledDiagnostics::Changed {
7086 result_id,
7087 diagnostics,
7088 } => {
7089 changed_buffers.insert(uri.clone());
7090 (result_id, diagnostics)
7091 }
7092 };
7093 let disk_based_sources = Cow::Owned(
7094 lsp_store
7095 .language_server_adapter_for_id(server_id)
7096 .as_ref()
7097 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7098 .unwrap_or(&[])
7099 .to_vec(),
7100 );
7101 acc.entry(server_id).or_insert_with(Vec::new).push(
7102 DocumentDiagnosticsUpdate {
7103 server_id,
7104 diagnostics: lsp::PublishDiagnosticsParams {
7105 uri,
7106 diagnostics,
7107 version: None,
7108 },
7109 result_id,
7110 disk_based_sources,
7111 },
7112 );
7113 acc
7114 },
7115 );
7116
7117 for diagnostic_updates in server_diagnostics_updates.into_values() {
7118 lsp_store
7119 .merge_lsp_diagnostics(
7120 DiagnosticSourceKind::Pulled,
7121 diagnostic_updates,
7122 |buffer, old_diagnostic, cx| {
7123 File::from_dyn(buffer.file())
7124 .and_then(|file| {
7125 let abs_path = file.as_local()?.abs_path(cx);
7126 lsp::Uri::from_file_path(abs_path).ok()
7127 })
7128 .is_none_or(|buffer_uri| {
7129 unchanged_buffers.contains(&buffer_uri)
7130 || match old_diagnostic.source_kind {
7131 DiagnosticSourceKind::Pulled => {
7132 !changed_buffers.contains(&buffer_uri)
7133 }
7134 DiagnosticSourceKind::Other
7135 | DiagnosticSourceKind::Pushed => true,
7136 }
7137 })
7138 },
7139 cx,
7140 )
7141 .log_err();
7142 }
7143 })
7144 })
7145 }
7146
7147 pub fn document_colors(
7148 &mut self,
7149 known_cache_version: Option<usize>,
7150 buffer: Entity<Buffer>,
7151 cx: &mut Context<Self>,
7152 ) -> Option<DocumentColorTask> {
7153 let version_queried_for = buffer.read(cx).version();
7154 let buffer_id = buffer.read(cx).remote_id();
7155
7156 let current_language_servers = self.as_local().map(|local| {
7157 local
7158 .buffers_opened_in_servers
7159 .get(&buffer_id)
7160 .cloned()
7161 .unwrap_or_default()
7162 });
7163
7164 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7165 if let Some(cached_colors) = &lsp_data.document_colors {
7166 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7167 let has_different_servers =
7168 current_language_servers.is_some_and(|current_language_servers| {
7169 current_language_servers
7170 != cached_colors.colors.keys().copied().collect()
7171 });
7172 if !has_different_servers {
7173 let cache_version = cached_colors.cache_version;
7174 if Some(cache_version) == known_cache_version {
7175 return None;
7176 } else {
7177 return Some(
7178 Task::ready(Ok(DocumentColors {
7179 colors: cached_colors
7180 .colors
7181 .values()
7182 .flatten()
7183 .cloned()
7184 .collect(),
7185 cache_version: Some(cache_version),
7186 }))
7187 .shared(),
7188 );
7189 }
7190 }
7191 }
7192 }
7193 }
7194
7195 let color_lsp_data = self
7196 .latest_lsp_data(&buffer, cx)
7197 .document_colors
7198 .get_or_insert_default();
7199 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7200 && !version_queried_for.changed_since(updating_for)
7201 {
7202 return Some(running_update.clone());
7203 }
7204 let buffer_version_queried_for = version_queried_for.clone();
7205 let new_task = cx
7206 .spawn(async move |lsp_store, cx| {
7207 cx.background_executor()
7208 .timer(Duration::from_millis(30))
7209 .await;
7210 let fetched_colors = lsp_store
7211 .update(cx, |lsp_store, cx| {
7212 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7213 })?
7214 .await
7215 .context("fetching document colors")
7216 .map_err(Arc::new);
7217 let fetched_colors = match fetched_colors {
7218 Ok(fetched_colors) => {
7219 if Some(true)
7220 == buffer
7221 .update(cx, |buffer, _| {
7222 buffer.version() != buffer_version_queried_for
7223 })
7224 .ok()
7225 {
7226 return Ok(DocumentColors::default());
7227 }
7228 fetched_colors
7229 }
7230 Err(e) => {
7231 lsp_store
7232 .update(cx, |lsp_store, _| {
7233 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7234 if let Some(document_colors) = &mut lsp_data.document_colors {
7235 document_colors.colors_update = None;
7236 }
7237 }
7238 })
7239 .ok();
7240 return Err(e);
7241 }
7242 };
7243
7244 lsp_store
7245 .update(cx, |lsp_store, cx| {
7246 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7247 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7248
7249 if let Some(fetched_colors) = fetched_colors {
7250 if lsp_data.buffer_version == buffer_version_queried_for {
7251 lsp_colors.colors.extend(fetched_colors);
7252 lsp_colors.cache_version += 1;
7253 } else if !lsp_data
7254 .buffer_version
7255 .changed_since(&buffer_version_queried_for)
7256 {
7257 lsp_data.buffer_version = buffer_version_queried_for;
7258 lsp_colors.colors = fetched_colors;
7259 lsp_colors.cache_version += 1;
7260 }
7261 }
7262 lsp_colors.colors_update = None;
7263 let colors = lsp_colors
7264 .colors
7265 .values()
7266 .flatten()
7267 .cloned()
7268 .collect::<HashSet<_>>();
7269 DocumentColors {
7270 colors,
7271 cache_version: Some(lsp_colors.cache_version),
7272 }
7273 })
7274 .map_err(Arc::new)
7275 })
7276 .shared();
7277 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7278 Some(new_task)
7279 }
7280
7281 fn fetch_document_colors_for_buffer(
7282 &mut self,
7283 buffer: &Entity<Buffer>,
7284 cx: &mut Context<Self>,
7285 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7286 if let Some((client, project_id)) = self.upstream_client() {
7287 let request = GetDocumentColor {};
7288 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7289 return Task::ready(Ok(None));
7290 }
7291
7292 let request_task = client.request_lsp(
7293 project_id,
7294 None,
7295 LSP_REQUEST_TIMEOUT,
7296 cx.background_executor().clone(),
7297 request.to_proto(project_id, buffer.read(cx)),
7298 );
7299 let buffer = buffer.clone();
7300 cx.spawn(async move |lsp_store, cx| {
7301 let Some(lsp_store) = lsp_store.upgrade() else {
7302 return Ok(None);
7303 };
7304 let colors = join_all(
7305 request_task
7306 .await
7307 .log_err()
7308 .flatten()
7309 .map(|response| response.payload)
7310 .unwrap_or_default()
7311 .into_iter()
7312 .map(|color_response| {
7313 let response = request.response_from_proto(
7314 color_response.response,
7315 lsp_store.clone(),
7316 buffer.clone(),
7317 cx.clone(),
7318 );
7319 async move {
7320 (
7321 LanguageServerId::from_proto(color_response.server_id),
7322 response.await.log_err().unwrap_or_default(),
7323 )
7324 }
7325 }),
7326 )
7327 .await
7328 .into_iter()
7329 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7330 acc.entry(server_id)
7331 .or_insert_with(HashSet::default)
7332 .extend(colors);
7333 acc
7334 });
7335 Ok(Some(colors))
7336 })
7337 } else {
7338 let document_colors_task =
7339 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7340 cx.background_spawn(async move {
7341 Ok(Some(
7342 document_colors_task
7343 .await
7344 .into_iter()
7345 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7346 acc.entry(server_id)
7347 .or_insert_with(HashSet::default)
7348 .extend(colors);
7349 acc
7350 })
7351 .into_iter()
7352 .collect(),
7353 ))
7354 })
7355 }
7356 }
7357
7358 pub fn signature_help<T: ToPointUtf16>(
7359 &mut self,
7360 buffer: &Entity<Buffer>,
7361 position: T,
7362 cx: &mut Context<Self>,
7363 ) -> Task<Option<Vec<SignatureHelp>>> {
7364 let position = position.to_point_utf16(buffer.read(cx));
7365
7366 if let Some((client, upstream_project_id)) = self.upstream_client() {
7367 let request = GetSignatureHelp { position };
7368 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7369 return Task::ready(None);
7370 }
7371 let request_task = client.request_lsp(
7372 upstream_project_id,
7373 None,
7374 LSP_REQUEST_TIMEOUT,
7375 cx.background_executor().clone(),
7376 request.to_proto(upstream_project_id, buffer.read(cx)),
7377 );
7378 let buffer = buffer.clone();
7379 cx.spawn(async move |weak_lsp_store, cx| {
7380 let lsp_store = weak_lsp_store.upgrade()?;
7381 let signatures = join_all(
7382 request_task
7383 .await
7384 .log_err()
7385 .flatten()
7386 .map(|response| response.payload)
7387 .unwrap_or_default()
7388 .into_iter()
7389 .map(|response| {
7390 let response = GetSignatureHelp { position }.response_from_proto(
7391 response.response,
7392 lsp_store.clone(),
7393 buffer.clone(),
7394 cx.clone(),
7395 );
7396 async move { response.await.log_err().flatten() }
7397 }),
7398 )
7399 .await
7400 .into_iter()
7401 .flatten()
7402 .collect();
7403 Some(signatures)
7404 })
7405 } else {
7406 let all_actions_task = self.request_multiple_lsp_locally(
7407 buffer,
7408 Some(position),
7409 GetSignatureHelp { position },
7410 cx,
7411 );
7412 cx.background_spawn(async move {
7413 Some(
7414 all_actions_task
7415 .await
7416 .into_iter()
7417 .flat_map(|(_, actions)| actions)
7418 .collect::<Vec<_>>(),
7419 )
7420 })
7421 }
7422 }
7423
7424 pub fn hover(
7425 &mut self,
7426 buffer: &Entity<Buffer>,
7427 position: PointUtf16,
7428 cx: &mut Context<Self>,
7429 ) -> Task<Option<Vec<Hover>>> {
7430 if let Some((client, upstream_project_id)) = self.upstream_client() {
7431 let request = GetHover { position };
7432 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7433 return Task::ready(None);
7434 }
7435 let request_task = client.request_lsp(
7436 upstream_project_id,
7437 None,
7438 LSP_REQUEST_TIMEOUT,
7439 cx.background_executor().clone(),
7440 request.to_proto(upstream_project_id, buffer.read(cx)),
7441 );
7442 let buffer = buffer.clone();
7443 cx.spawn(async move |weak_lsp_store, cx| {
7444 let lsp_store = weak_lsp_store.upgrade()?;
7445 let hovers = join_all(
7446 request_task
7447 .await
7448 .log_err()
7449 .flatten()
7450 .map(|response| response.payload)
7451 .unwrap_or_default()
7452 .into_iter()
7453 .map(|response| {
7454 let response = GetHover { position }.response_from_proto(
7455 response.response,
7456 lsp_store.clone(),
7457 buffer.clone(),
7458 cx.clone(),
7459 );
7460 async move {
7461 response
7462 .await
7463 .log_err()
7464 .flatten()
7465 .and_then(remove_empty_hover_blocks)
7466 }
7467 }),
7468 )
7469 .await
7470 .into_iter()
7471 .flatten()
7472 .collect();
7473 Some(hovers)
7474 })
7475 } else {
7476 let all_actions_task = self.request_multiple_lsp_locally(
7477 buffer,
7478 Some(position),
7479 GetHover { position },
7480 cx,
7481 );
7482 cx.background_spawn(async move {
7483 Some(
7484 all_actions_task
7485 .await
7486 .into_iter()
7487 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7488 .collect::<Vec<Hover>>(),
7489 )
7490 })
7491 }
7492 }
7493
7494 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7495 let language_registry = self.languages.clone();
7496
7497 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7498 let request = upstream_client.request(proto::GetProjectSymbols {
7499 project_id: *project_id,
7500 query: query.to_string(),
7501 });
7502 cx.foreground_executor().spawn(async move {
7503 let response = request.await?;
7504 let mut symbols = Vec::new();
7505 let core_symbols = response
7506 .symbols
7507 .into_iter()
7508 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7509 .collect::<Vec<_>>();
7510 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7511 .await;
7512 Ok(symbols)
7513 })
7514 } else if let Some(local) = self.as_local() {
7515 struct WorkspaceSymbolsResult {
7516 server_id: LanguageServerId,
7517 lsp_adapter: Arc<CachedLspAdapter>,
7518 worktree: WeakEntity<Worktree>,
7519 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7520 }
7521
7522 let mut requests = Vec::new();
7523 let mut requested_servers = BTreeSet::new();
7524 for (seed, state) in local.language_server_ids.iter() {
7525 let Some(worktree_handle) = self
7526 .worktree_store
7527 .read(cx)
7528 .worktree_for_id(seed.worktree_id, cx)
7529 else {
7530 continue;
7531 };
7532 let worktree = worktree_handle.read(cx);
7533 if !worktree.is_visible() {
7534 continue;
7535 }
7536
7537 if !requested_servers.insert(state.id) {
7538 continue;
7539 }
7540
7541 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7542 Some(LanguageServerState::Running {
7543 adapter, server, ..
7544 }) => (adapter.clone(), server),
7545
7546 _ => continue,
7547 };
7548 let supports_workspace_symbol_request =
7549 match server.capabilities().workspace_symbol_provider {
7550 Some(OneOf::Left(supported)) => supported,
7551 Some(OneOf::Right(_)) => true,
7552 None => false,
7553 };
7554 if !supports_workspace_symbol_request {
7555 continue;
7556 }
7557 let worktree_handle = worktree_handle.clone();
7558 let server_id = server.server_id();
7559 requests.push(
7560 server
7561 .request::<lsp::request::WorkspaceSymbolRequest>(
7562 lsp::WorkspaceSymbolParams {
7563 query: query.to_string(),
7564 ..Default::default()
7565 },
7566 )
7567 .map(move |response| {
7568 let lsp_symbols = response.into_response()
7569 .context("workspace symbols request")
7570 .log_err()
7571 .flatten()
7572 .map(|symbol_response| match symbol_response {
7573 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7574 flat_responses.into_iter().map(|lsp_symbol| {
7575 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7576 }).collect::<Vec<_>>()
7577 }
7578 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7579 nested_responses.into_iter().filter_map(|lsp_symbol| {
7580 let location = match lsp_symbol.location {
7581 OneOf::Left(location) => location,
7582 OneOf::Right(_) => {
7583 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7584 return None
7585 }
7586 };
7587 Some((lsp_symbol.name, lsp_symbol.kind, location))
7588 }).collect::<Vec<_>>()
7589 }
7590 }).unwrap_or_default();
7591
7592 WorkspaceSymbolsResult {
7593 server_id,
7594 lsp_adapter,
7595 worktree: worktree_handle.downgrade(),
7596 lsp_symbols,
7597 }
7598 }),
7599 );
7600 }
7601
7602 cx.spawn(async move |this, cx| {
7603 let responses = futures::future::join_all(requests).await;
7604 let this = match this.upgrade() {
7605 Some(this) => this,
7606 None => return Ok(Vec::new()),
7607 };
7608
7609 let mut symbols = Vec::new();
7610 for result in responses {
7611 let core_symbols = this.update(cx, |this, cx| {
7612 result
7613 .lsp_symbols
7614 .into_iter()
7615 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7616 let abs_path = symbol_location.uri.to_file_path().ok()?;
7617 let source_worktree = result.worktree.upgrade()?;
7618 let source_worktree_id = source_worktree.read(cx).id();
7619
7620 let path = if let Some((tree, rel_path)) =
7621 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7622 {
7623 let worktree_id = tree.read(cx).id();
7624 SymbolLocation::InProject(ProjectPath {
7625 worktree_id,
7626 path: rel_path,
7627 })
7628 } else {
7629 SymbolLocation::OutsideProject {
7630 signature: this.symbol_signature(&abs_path),
7631 abs_path: abs_path.into(),
7632 }
7633 };
7634
7635 Some(CoreSymbol {
7636 source_language_server_id: result.server_id,
7637 language_server_name: result.lsp_adapter.name.clone(),
7638 source_worktree_id,
7639 path,
7640 kind: symbol_kind,
7641 name: symbol_name,
7642 range: range_from_lsp(symbol_location.range),
7643 })
7644 })
7645 .collect()
7646 })?;
7647
7648 populate_labels_for_symbols(
7649 core_symbols,
7650 &language_registry,
7651 Some(result.lsp_adapter),
7652 &mut symbols,
7653 )
7654 .await;
7655 }
7656
7657 Ok(symbols)
7658 })
7659 } else {
7660 Task::ready(Err(anyhow!("No upstream client or local language server")))
7661 }
7662 }
7663
7664 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7665 let mut summary = DiagnosticSummary::default();
7666 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7667 summary.error_count += path_summary.error_count;
7668 summary.warning_count += path_summary.warning_count;
7669 }
7670 summary
7671 }
7672
7673 /// Returns the diagnostic summary for a specific project path.
7674 pub fn diagnostic_summary_for_path(
7675 &self,
7676 project_path: &ProjectPath,
7677 _: &App,
7678 ) -> DiagnosticSummary {
7679 if let Some(summaries) = self
7680 .diagnostic_summaries
7681 .get(&project_path.worktree_id)
7682 .and_then(|map| map.get(&project_path.path))
7683 {
7684 let (error_count, warning_count) = summaries.iter().fold(
7685 (0, 0),
7686 |(error_count, warning_count), (_language_server_id, summary)| {
7687 (
7688 error_count + summary.error_count,
7689 warning_count + summary.warning_count,
7690 )
7691 },
7692 );
7693
7694 DiagnosticSummary {
7695 error_count,
7696 warning_count,
7697 }
7698 } else {
7699 DiagnosticSummary::default()
7700 }
7701 }
7702
7703 pub fn diagnostic_summaries<'a>(
7704 &'a self,
7705 include_ignored: bool,
7706 cx: &'a App,
7707 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7708 self.worktree_store
7709 .read(cx)
7710 .visible_worktrees(cx)
7711 .filter_map(|worktree| {
7712 let worktree = worktree.read(cx);
7713 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7714 })
7715 .flat_map(move |(worktree, summaries)| {
7716 let worktree_id = worktree.id();
7717 summaries
7718 .iter()
7719 .filter(move |(path, _)| {
7720 include_ignored
7721 || worktree
7722 .entry_for_path(path.as_ref())
7723 .is_some_and(|entry| !entry.is_ignored)
7724 })
7725 .flat_map(move |(path, summaries)| {
7726 summaries.iter().map(move |(server_id, summary)| {
7727 (
7728 ProjectPath {
7729 worktree_id,
7730 path: path.clone(),
7731 },
7732 *server_id,
7733 *summary,
7734 )
7735 })
7736 })
7737 })
7738 }
7739
7740 pub fn on_buffer_edited(
7741 &mut self,
7742 buffer: Entity<Buffer>,
7743 cx: &mut Context<Self>,
7744 ) -> Option<()> {
7745 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7746 Some(
7747 self.as_local()?
7748 .language_servers_for_buffer(buffer, cx)
7749 .map(|i| i.1.clone())
7750 .collect(),
7751 )
7752 })?;
7753
7754 let buffer = buffer.read(cx);
7755 let file = File::from_dyn(buffer.file())?;
7756 let abs_path = file.as_local()?.abs_path(cx);
7757 let uri = lsp::Uri::from_file_path(&abs_path)
7758 .ok()
7759 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7760 .log_err()?;
7761 let next_snapshot = buffer.text_snapshot();
7762 for language_server in language_servers {
7763 let language_server = language_server.clone();
7764
7765 let buffer_snapshots = self
7766 .as_local_mut()?
7767 .buffer_snapshots
7768 .get_mut(&buffer.remote_id())
7769 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7770 let previous_snapshot = buffer_snapshots.last()?;
7771
7772 let build_incremental_change = || {
7773 buffer
7774 .edits_since::<Dimensions<PointUtf16, usize>>(
7775 previous_snapshot.snapshot.version(),
7776 )
7777 .map(|edit| {
7778 let edit_start = edit.new.start.0;
7779 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7780 let new_text = next_snapshot
7781 .text_for_range(edit.new.start.1..edit.new.end.1)
7782 .collect();
7783 lsp::TextDocumentContentChangeEvent {
7784 range: Some(lsp::Range::new(
7785 point_to_lsp(edit_start),
7786 point_to_lsp(edit_end),
7787 )),
7788 range_length: None,
7789 text: new_text,
7790 }
7791 })
7792 .collect()
7793 };
7794
7795 let document_sync_kind = language_server
7796 .capabilities()
7797 .text_document_sync
7798 .as_ref()
7799 .and_then(|sync| match sync {
7800 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7801 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7802 });
7803
7804 let content_changes: Vec<_> = match document_sync_kind {
7805 Some(lsp::TextDocumentSyncKind::FULL) => {
7806 vec![lsp::TextDocumentContentChangeEvent {
7807 range: None,
7808 range_length: None,
7809 text: next_snapshot.text(),
7810 }]
7811 }
7812 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7813 _ => {
7814 #[cfg(any(test, feature = "test-support"))]
7815 {
7816 build_incremental_change()
7817 }
7818
7819 #[cfg(not(any(test, feature = "test-support")))]
7820 {
7821 continue;
7822 }
7823 }
7824 };
7825
7826 let next_version = previous_snapshot.version + 1;
7827 buffer_snapshots.push(LspBufferSnapshot {
7828 version: next_version,
7829 snapshot: next_snapshot.clone(),
7830 });
7831
7832 language_server
7833 .notify::<lsp::notification::DidChangeTextDocument>(
7834 lsp::DidChangeTextDocumentParams {
7835 text_document: lsp::VersionedTextDocumentIdentifier::new(
7836 uri.clone(),
7837 next_version,
7838 ),
7839 content_changes,
7840 },
7841 )
7842 .ok();
7843 self.pull_workspace_diagnostics(language_server.server_id());
7844 }
7845
7846 None
7847 }
7848
7849 pub fn on_buffer_saved(
7850 &mut self,
7851 buffer: Entity<Buffer>,
7852 cx: &mut Context<Self>,
7853 ) -> Option<()> {
7854 let file = File::from_dyn(buffer.read(cx).file())?;
7855 let worktree_id = file.worktree_id(cx);
7856 let abs_path = file.as_local()?.abs_path(cx);
7857 let text_document = lsp::TextDocumentIdentifier {
7858 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7859 };
7860 let local = self.as_local()?;
7861
7862 for server in local.language_servers_for_worktree(worktree_id) {
7863 if let Some(include_text) = include_text(server.as_ref()) {
7864 let text = if include_text {
7865 Some(buffer.read(cx).text())
7866 } else {
7867 None
7868 };
7869 server
7870 .notify::<lsp::notification::DidSaveTextDocument>(
7871 lsp::DidSaveTextDocumentParams {
7872 text_document: text_document.clone(),
7873 text,
7874 },
7875 )
7876 .ok();
7877 }
7878 }
7879
7880 let language_servers = buffer.update(cx, |buffer, cx| {
7881 local.language_server_ids_for_buffer(buffer, cx)
7882 });
7883 for language_server_id in language_servers {
7884 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7885 }
7886
7887 None
7888 }
7889
7890 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7891 maybe!(async move {
7892 let mut refreshed_servers = HashSet::default();
7893 let servers = lsp_store
7894 .update(cx, |lsp_store, cx| {
7895 let local = lsp_store.as_local()?;
7896
7897 let servers = local
7898 .language_server_ids
7899 .iter()
7900 .filter_map(|(seed, state)| {
7901 let worktree = lsp_store
7902 .worktree_store
7903 .read(cx)
7904 .worktree_for_id(seed.worktree_id, cx);
7905 let delegate: Arc<dyn LspAdapterDelegate> =
7906 worktree.map(|worktree| {
7907 LocalLspAdapterDelegate::new(
7908 local.languages.clone(),
7909 &local.environment,
7910 cx.weak_entity(),
7911 &worktree,
7912 local.http_client.clone(),
7913 local.fs.clone(),
7914 cx,
7915 )
7916 })?;
7917 let server_id = state.id;
7918
7919 let states = local.language_servers.get(&server_id)?;
7920
7921 match states {
7922 LanguageServerState::Starting { .. } => None,
7923 LanguageServerState::Running {
7924 adapter, server, ..
7925 } => {
7926 let adapter = adapter.clone();
7927 let server = server.clone();
7928 refreshed_servers.insert(server.name());
7929 let toolchain = seed.toolchain.clone();
7930 Some(cx.spawn(async move |_, cx| {
7931 let settings =
7932 LocalLspStore::workspace_configuration_for_adapter(
7933 adapter.adapter.clone(),
7934 &delegate,
7935 toolchain,
7936 cx,
7937 )
7938 .await
7939 .ok()?;
7940 server
7941 .notify::<lsp::notification::DidChangeConfiguration>(
7942 lsp::DidChangeConfigurationParams { settings },
7943 )
7944 .ok()?;
7945 Some(())
7946 }))
7947 }
7948 }
7949 })
7950 .collect::<Vec<_>>();
7951
7952 Some(servers)
7953 })
7954 .ok()
7955 .flatten()?;
7956
7957 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7958 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7959 // to stop and unregister its language server wrapper.
7960 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7961 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7962 let _: Vec<Option<()>> = join_all(servers).await;
7963
7964 Some(())
7965 })
7966 .await;
7967 }
7968
7969 fn maintain_workspace_config(
7970 external_refresh_requests: watch::Receiver<()>,
7971 cx: &mut Context<Self>,
7972 ) -> Task<Result<()>> {
7973 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7974 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7975
7976 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7977 *settings_changed_tx.borrow_mut() = ();
7978 });
7979
7980 let mut joint_future =
7981 futures::stream::select(settings_changed_rx, external_refresh_requests);
7982 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7983 // - 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).
7984 // - 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.
7985 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7986 // - 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,
7987 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7988 cx.spawn(async move |this, cx| {
7989 while let Some(()) = joint_future.next().await {
7990 this.update(cx, |this, cx| {
7991 this.refresh_server_tree(cx);
7992 })
7993 .ok();
7994
7995 Self::refresh_workspace_configurations(&this, cx).await;
7996 }
7997
7998 drop(settings_observation);
7999 anyhow::Ok(())
8000 })
8001 }
8002
8003 pub fn language_servers_for_local_buffer<'a>(
8004 &'a self,
8005 buffer: &Buffer,
8006 cx: &mut App,
8007 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8008 let local = self.as_local();
8009 let language_server_ids = local
8010 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8011 .unwrap_or_default();
8012
8013 language_server_ids
8014 .into_iter()
8015 .filter_map(
8016 move |server_id| match local?.language_servers.get(&server_id)? {
8017 LanguageServerState::Running {
8018 adapter, server, ..
8019 } => Some((adapter, server)),
8020 _ => None,
8021 },
8022 )
8023 }
8024
8025 pub fn language_server_for_local_buffer<'a>(
8026 &'a self,
8027 buffer: &'a Buffer,
8028 server_id: LanguageServerId,
8029 cx: &'a mut App,
8030 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8031 self.as_local()?
8032 .language_servers_for_buffer(buffer, cx)
8033 .find(|(_, s)| s.server_id() == server_id)
8034 }
8035
8036 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8037 self.diagnostic_summaries.remove(&id_to_remove);
8038 if let Some(local) = self.as_local_mut() {
8039 let to_remove = local.remove_worktree(id_to_remove, cx);
8040 for server in to_remove {
8041 self.language_server_statuses.remove(&server);
8042 }
8043 }
8044 }
8045
8046 pub fn shared(
8047 &mut self,
8048 project_id: u64,
8049 downstream_client: AnyProtoClient,
8050 _: &mut Context<Self>,
8051 ) {
8052 self.downstream_client = Some((downstream_client.clone(), project_id));
8053
8054 for (server_id, status) in &self.language_server_statuses {
8055 if let Some(server) = self.language_server_for_id(*server_id) {
8056 downstream_client
8057 .send(proto::StartLanguageServer {
8058 project_id,
8059 server: Some(proto::LanguageServer {
8060 id: server_id.to_proto(),
8061 name: status.name.to_string(),
8062 worktree_id: status.worktree.map(|id| id.to_proto()),
8063 }),
8064 capabilities: serde_json::to_string(&server.capabilities())
8065 .expect("serializing server LSP capabilities"),
8066 })
8067 .log_err();
8068 }
8069 }
8070 }
8071
8072 pub fn disconnected_from_host(&mut self) {
8073 self.downstream_client.take();
8074 }
8075
8076 pub fn disconnected_from_ssh_remote(&mut self) {
8077 if let LspStoreMode::Remote(RemoteLspStore {
8078 upstream_client, ..
8079 }) = &mut self.mode
8080 {
8081 upstream_client.take();
8082 }
8083 }
8084
8085 pub(crate) fn set_language_server_statuses_from_proto(
8086 &mut self,
8087 project: WeakEntity<Project>,
8088 language_servers: Vec<proto::LanguageServer>,
8089 server_capabilities: Vec<String>,
8090 cx: &mut Context<Self>,
8091 ) {
8092 let lsp_logs = cx
8093 .try_global::<GlobalLogStore>()
8094 .map(|lsp_store| lsp_store.0.clone());
8095
8096 self.language_server_statuses = language_servers
8097 .into_iter()
8098 .zip(server_capabilities)
8099 .map(|(server, server_capabilities)| {
8100 let server_id = LanguageServerId(server.id as usize);
8101 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8102 self.lsp_server_capabilities
8103 .insert(server_id, server_capabilities);
8104 }
8105
8106 let name = LanguageServerName::from_proto(server.name);
8107 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8108
8109 if let Some(lsp_logs) = &lsp_logs {
8110 lsp_logs.update(cx, |lsp_logs, cx| {
8111 lsp_logs.add_language_server(
8112 // Only remote clients get their language servers set from proto
8113 LanguageServerKind::Remote {
8114 project: project.clone(),
8115 },
8116 server_id,
8117 Some(name.clone()),
8118 worktree,
8119 None,
8120 cx,
8121 );
8122 });
8123 }
8124
8125 (
8126 server_id,
8127 LanguageServerStatus {
8128 name,
8129 pending_work: Default::default(),
8130 has_pending_diagnostic_updates: false,
8131 progress_tokens: Default::default(),
8132 worktree,
8133 },
8134 )
8135 })
8136 .collect();
8137 }
8138
8139 #[cfg(test)]
8140 pub fn update_diagnostic_entries(
8141 &mut self,
8142 server_id: LanguageServerId,
8143 abs_path: PathBuf,
8144 result_id: Option<String>,
8145 version: Option<i32>,
8146 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8147 cx: &mut Context<Self>,
8148 ) -> anyhow::Result<()> {
8149 self.merge_diagnostic_entries(
8150 vec![DocumentDiagnosticsUpdate {
8151 diagnostics: DocumentDiagnostics {
8152 diagnostics,
8153 document_abs_path: abs_path,
8154 version,
8155 },
8156 result_id,
8157 server_id,
8158 disk_based_sources: Cow::Borrowed(&[]),
8159 }],
8160 |_, _, _| false,
8161 cx,
8162 )?;
8163 Ok(())
8164 }
8165
8166 pub fn merge_diagnostic_entries<'a>(
8167 &mut self,
8168 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8169 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8170 cx: &mut Context<Self>,
8171 ) -> anyhow::Result<()> {
8172 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8173 let mut updated_diagnostics_paths = HashMap::default();
8174 for mut update in diagnostic_updates {
8175 let abs_path = &update.diagnostics.document_abs_path;
8176 let server_id = update.server_id;
8177 let Some((worktree, relative_path)) =
8178 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8179 else {
8180 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8181 return Ok(());
8182 };
8183
8184 let worktree_id = worktree.read(cx).id();
8185 let project_path = ProjectPath {
8186 worktree_id,
8187 path: relative_path,
8188 };
8189
8190 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8191 let snapshot = buffer_handle.read(cx).snapshot();
8192 let buffer = buffer_handle.read(cx);
8193 let reused_diagnostics = buffer
8194 .buffer_diagnostics(Some(server_id))
8195 .iter()
8196 .filter(|v| merge(buffer, &v.diagnostic, cx))
8197 .map(|v| {
8198 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8199 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8200 DiagnosticEntry {
8201 range: start..end,
8202 diagnostic: v.diagnostic.clone(),
8203 }
8204 })
8205 .collect::<Vec<_>>();
8206
8207 self.as_local_mut()
8208 .context("cannot merge diagnostics on a remote LspStore")?
8209 .update_buffer_diagnostics(
8210 &buffer_handle,
8211 server_id,
8212 update.result_id,
8213 update.diagnostics.version,
8214 update.diagnostics.diagnostics.clone(),
8215 reused_diagnostics.clone(),
8216 cx,
8217 )?;
8218
8219 update.diagnostics.diagnostics.extend(reused_diagnostics);
8220 }
8221
8222 let updated = worktree.update(cx, |worktree, cx| {
8223 self.update_worktree_diagnostics(
8224 worktree.id(),
8225 server_id,
8226 project_path.path.clone(),
8227 update.diagnostics.diagnostics,
8228 cx,
8229 )
8230 })?;
8231 match updated {
8232 ControlFlow::Continue(new_summary) => {
8233 if let Some((project_id, new_summary)) = new_summary {
8234 match &mut diagnostics_summary {
8235 Some(diagnostics_summary) => {
8236 diagnostics_summary
8237 .more_summaries
8238 .push(proto::DiagnosticSummary {
8239 path: project_path.path.as_ref().to_proto(),
8240 language_server_id: server_id.0 as u64,
8241 error_count: new_summary.error_count,
8242 warning_count: new_summary.warning_count,
8243 })
8244 }
8245 None => {
8246 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8247 project_id,
8248 worktree_id: worktree_id.to_proto(),
8249 summary: Some(proto::DiagnosticSummary {
8250 path: project_path.path.as_ref().to_proto(),
8251 language_server_id: server_id.0 as u64,
8252 error_count: new_summary.error_count,
8253 warning_count: new_summary.warning_count,
8254 }),
8255 more_summaries: Vec::new(),
8256 })
8257 }
8258 }
8259 }
8260 updated_diagnostics_paths
8261 .entry(server_id)
8262 .or_insert_with(Vec::new)
8263 .push(project_path);
8264 }
8265 ControlFlow::Break(()) => {}
8266 }
8267 }
8268
8269 if let Some((diagnostics_summary, (downstream_client, _))) =
8270 diagnostics_summary.zip(self.downstream_client.as_ref())
8271 {
8272 downstream_client.send(diagnostics_summary).log_err();
8273 }
8274 for (server_id, paths) in updated_diagnostics_paths {
8275 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8276 }
8277 Ok(())
8278 }
8279
8280 fn update_worktree_diagnostics(
8281 &mut self,
8282 worktree_id: WorktreeId,
8283 server_id: LanguageServerId,
8284 path_in_worktree: Arc<RelPath>,
8285 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8286 _: &mut Context<Worktree>,
8287 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8288 let local = match &mut self.mode {
8289 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8290 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8291 };
8292
8293 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8294 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8295 let summaries_by_server_id = summaries_for_tree
8296 .entry(path_in_worktree.clone())
8297 .or_default();
8298
8299 let old_summary = summaries_by_server_id
8300 .remove(&server_id)
8301 .unwrap_or_default();
8302
8303 let new_summary = DiagnosticSummary::new(&diagnostics);
8304 if new_summary.is_empty() {
8305 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8306 {
8307 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8308 diagnostics_by_server_id.remove(ix);
8309 }
8310 if diagnostics_by_server_id.is_empty() {
8311 diagnostics_for_tree.remove(&path_in_worktree);
8312 }
8313 }
8314 } else {
8315 summaries_by_server_id.insert(server_id, new_summary);
8316 let diagnostics_by_server_id = diagnostics_for_tree
8317 .entry(path_in_worktree.clone())
8318 .or_default();
8319 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8320 Ok(ix) => {
8321 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8322 }
8323 Err(ix) => {
8324 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8325 }
8326 }
8327 }
8328
8329 if !old_summary.is_empty() || !new_summary.is_empty() {
8330 if let Some((_, project_id)) = &self.downstream_client {
8331 Ok(ControlFlow::Continue(Some((
8332 *project_id,
8333 proto::DiagnosticSummary {
8334 path: path_in_worktree.to_proto(),
8335 language_server_id: server_id.0 as u64,
8336 error_count: new_summary.error_count as u32,
8337 warning_count: new_summary.warning_count as u32,
8338 },
8339 ))))
8340 } else {
8341 Ok(ControlFlow::Continue(None))
8342 }
8343 } else {
8344 Ok(ControlFlow::Break(()))
8345 }
8346 }
8347
8348 pub fn open_buffer_for_symbol(
8349 &mut self,
8350 symbol: &Symbol,
8351 cx: &mut Context<Self>,
8352 ) -> Task<Result<Entity<Buffer>>> {
8353 if let Some((client, project_id)) = self.upstream_client() {
8354 let request = client.request(proto::OpenBufferForSymbol {
8355 project_id,
8356 symbol: Some(Self::serialize_symbol(symbol)),
8357 });
8358 cx.spawn(async move |this, cx| {
8359 let response = request.await?;
8360 let buffer_id = BufferId::new(response.buffer_id)?;
8361 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8362 .await
8363 })
8364 } else if let Some(local) = self.as_local() {
8365 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8366 seed.worktree_id == symbol.source_worktree_id
8367 && state.id == symbol.source_language_server_id
8368 && symbol.language_server_name == seed.name
8369 });
8370 if !is_valid {
8371 return Task::ready(Err(anyhow!(
8372 "language server for worktree and language not found"
8373 )));
8374 };
8375
8376 let symbol_abs_path = match &symbol.path {
8377 SymbolLocation::InProject(project_path) => self
8378 .worktree_store
8379 .read(cx)
8380 .absolutize(&project_path, cx)
8381 .context("no such worktree"),
8382 SymbolLocation::OutsideProject {
8383 abs_path,
8384 signature: _,
8385 } => Ok(abs_path.to_path_buf()),
8386 };
8387 let symbol_abs_path = match symbol_abs_path {
8388 Ok(abs_path) => abs_path,
8389 Err(err) => return Task::ready(Err(err)),
8390 };
8391 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8392 uri
8393 } else {
8394 return Task::ready(Err(anyhow!("invalid symbol path")));
8395 };
8396
8397 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8398 } else {
8399 Task::ready(Err(anyhow!("no upstream client or local store")))
8400 }
8401 }
8402
8403 pub(crate) fn open_local_buffer_via_lsp(
8404 &mut self,
8405 abs_path: lsp::Uri,
8406 language_server_id: LanguageServerId,
8407 cx: &mut Context<Self>,
8408 ) -> Task<Result<Entity<Buffer>>> {
8409 cx.spawn(async move |lsp_store, cx| {
8410 // Escape percent-encoded string.
8411 let current_scheme = abs_path.scheme().to_owned();
8412 // Uri is immutable, so we can't modify the scheme
8413
8414 let abs_path = abs_path
8415 .to_file_path()
8416 .map_err(|()| anyhow!("can't convert URI to path"))?;
8417 let p = abs_path.clone();
8418 let yarn_worktree = lsp_store
8419 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8420 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8421 cx.spawn(async move |this, cx| {
8422 let t = this
8423 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8424 .ok()?;
8425 t.await
8426 })
8427 }),
8428 None => Task::ready(None),
8429 })?
8430 .await;
8431 let (worktree_root_target, known_relative_path) =
8432 if let Some((zip_root, relative_path)) = yarn_worktree {
8433 (zip_root, Some(relative_path))
8434 } else {
8435 (Arc::<Path>::from(abs_path.as_path()), None)
8436 };
8437 let (worktree, relative_path) = if let Some(result) =
8438 lsp_store.update(cx, |lsp_store, cx| {
8439 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8440 worktree_store.find_worktree(&worktree_root_target, cx)
8441 })
8442 })? {
8443 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8444 (result.0, relative_path)
8445 } else {
8446 let worktree = lsp_store
8447 .update(cx, |lsp_store, cx| {
8448 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8449 worktree_store.create_worktree(&worktree_root_target, false, cx)
8450 })
8451 })?
8452 .await?;
8453 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8454 lsp_store
8455 .update(cx, |lsp_store, cx| {
8456 if let Some(local) = lsp_store.as_local_mut() {
8457 local.register_language_server_for_invisible_worktree(
8458 &worktree,
8459 language_server_id,
8460 cx,
8461 )
8462 }
8463 })
8464 .ok();
8465 }
8466 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8467 let relative_path = if let Some(known_path) = known_relative_path {
8468 known_path
8469 } else {
8470 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8471 .into_arc()
8472 };
8473 (worktree, relative_path)
8474 };
8475 let project_path = ProjectPath {
8476 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8477 path: relative_path,
8478 };
8479 lsp_store
8480 .update(cx, |lsp_store, cx| {
8481 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8482 buffer_store.open_buffer(project_path, cx)
8483 })
8484 })?
8485 .await
8486 })
8487 }
8488
8489 fn request_multiple_lsp_locally<P, R>(
8490 &mut self,
8491 buffer: &Entity<Buffer>,
8492 position: Option<P>,
8493 request: R,
8494 cx: &mut Context<Self>,
8495 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8496 where
8497 P: ToOffset,
8498 R: LspCommand + Clone,
8499 <R::LspRequest as lsp::request::Request>::Result: Send,
8500 <R::LspRequest as lsp::request::Request>::Params: Send,
8501 {
8502 let Some(local) = self.as_local() else {
8503 return Task::ready(Vec::new());
8504 };
8505
8506 let snapshot = buffer.read(cx).snapshot();
8507 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8508
8509 let server_ids = buffer.update(cx, |buffer, cx| {
8510 local
8511 .language_servers_for_buffer(buffer, cx)
8512 .filter(|(adapter, _)| {
8513 scope
8514 .as_ref()
8515 .map(|scope| scope.language_allowed(&adapter.name))
8516 .unwrap_or(true)
8517 })
8518 .map(|(_, server)| server.server_id())
8519 .filter(|server_id| {
8520 self.as_local().is_none_or(|local| {
8521 local
8522 .buffers_opened_in_servers
8523 .get(&snapshot.remote_id())
8524 .is_some_and(|servers| servers.contains(server_id))
8525 })
8526 })
8527 .collect::<Vec<_>>()
8528 });
8529
8530 let mut response_results = server_ids
8531 .into_iter()
8532 .map(|server_id| {
8533 let task = self.request_lsp(
8534 buffer.clone(),
8535 LanguageServerToQuery::Other(server_id),
8536 request.clone(),
8537 cx,
8538 );
8539 async move { (server_id, task.await) }
8540 })
8541 .collect::<FuturesUnordered<_>>();
8542
8543 cx.background_spawn(async move {
8544 let mut responses = Vec::with_capacity(response_results.len());
8545 while let Some((server_id, response_result)) = response_results.next().await {
8546 match response_result {
8547 Ok(response) => responses.push((server_id, response)),
8548 // rust-analyzer likes to error with this when its still loading up
8549 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8550 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8551 }
8552 }
8553 responses
8554 })
8555 }
8556
8557 async fn handle_lsp_get_completions(
8558 this: Entity<Self>,
8559 envelope: TypedEnvelope<proto::GetCompletions>,
8560 mut cx: AsyncApp,
8561 ) -> Result<proto::GetCompletionsResponse> {
8562 let sender_id = envelope.original_sender_id().unwrap_or_default();
8563
8564 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8565 let buffer_handle = this.update(&mut cx, |this, cx| {
8566 this.buffer_store.read(cx).get_existing(buffer_id)
8567 })??;
8568 let request = GetCompletions::from_proto(
8569 envelope.payload,
8570 this.clone(),
8571 buffer_handle.clone(),
8572 cx.clone(),
8573 )
8574 .await?;
8575
8576 let server_to_query = match request.server_id {
8577 Some(server_id) => LanguageServerToQuery::Other(server_id),
8578 None => LanguageServerToQuery::FirstCapable,
8579 };
8580
8581 let response = this
8582 .update(&mut cx, |this, cx| {
8583 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8584 })?
8585 .await?;
8586 this.update(&mut cx, |this, cx| {
8587 Ok(GetCompletions::response_to_proto(
8588 response,
8589 this,
8590 sender_id,
8591 &buffer_handle.read(cx).version(),
8592 cx,
8593 ))
8594 })?
8595 }
8596
8597 async fn handle_lsp_command<T: LspCommand>(
8598 this: Entity<Self>,
8599 envelope: TypedEnvelope<T::ProtoRequest>,
8600 mut cx: AsyncApp,
8601 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8602 where
8603 <T::LspRequest as lsp::request::Request>::Params: Send,
8604 <T::LspRequest as lsp::request::Request>::Result: Send,
8605 {
8606 let sender_id = envelope.original_sender_id().unwrap_or_default();
8607 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8608 let buffer_handle = this.update(&mut cx, |this, cx| {
8609 this.buffer_store.read(cx).get_existing(buffer_id)
8610 })??;
8611 let request = T::from_proto(
8612 envelope.payload,
8613 this.clone(),
8614 buffer_handle.clone(),
8615 cx.clone(),
8616 )
8617 .await?;
8618 let response = this
8619 .update(&mut cx, |this, cx| {
8620 this.request_lsp(
8621 buffer_handle.clone(),
8622 LanguageServerToQuery::FirstCapable,
8623 request,
8624 cx,
8625 )
8626 })?
8627 .await?;
8628 this.update(&mut cx, |this, cx| {
8629 Ok(T::response_to_proto(
8630 response,
8631 this,
8632 sender_id,
8633 &buffer_handle.read(cx).version(),
8634 cx,
8635 ))
8636 })?
8637 }
8638
8639 async fn handle_lsp_query(
8640 lsp_store: Entity<Self>,
8641 envelope: TypedEnvelope<proto::LspQuery>,
8642 mut cx: AsyncApp,
8643 ) -> Result<proto::Ack> {
8644 use proto::lsp_query::Request;
8645 let sender_id = envelope.original_sender_id().unwrap_or_default();
8646 let lsp_query = envelope.payload;
8647 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8648 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8649 match lsp_query.request.context("invalid LSP query request")? {
8650 Request::GetReferences(get_references) => {
8651 let position = get_references.position.clone().and_then(deserialize_anchor);
8652 Self::query_lsp_locally::<GetReferences>(
8653 lsp_store,
8654 server_id,
8655 sender_id,
8656 lsp_request_id,
8657 get_references,
8658 position,
8659 &mut cx,
8660 )
8661 .await?;
8662 }
8663 Request::GetDocumentColor(get_document_color) => {
8664 Self::query_lsp_locally::<GetDocumentColor>(
8665 lsp_store,
8666 server_id,
8667 sender_id,
8668 lsp_request_id,
8669 get_document_color,
8670 None,
8671 &mut cx,
8672 )
8673 .await?;
8674 }
8675 Request::GetHover(get_hover) => {
8676 let position = get_hover.position.clone().and_then(deserialize_anchor);
8677 Self::query_lsp_locally::<GetHover>(
8678 lsp_store,
8679 server_id,
8680 sender_id,
8681 lsp_request_id,
8682 get_hover,
8683 position,
8684 &mut cx,
8685 )
8686 .await?;
8687 }
8688 Request::GetCodeActions(get_code_actions) => {
8689 Self::query_lsp_locally::<GetCodeActions>(
8690 lsp_store,
8691 server_id,
8692 sender_id,
8693 lsp_request_id,
8694 get_code_actions,
8695 None,
8696 &mut cx,
8697 )
8698 .await?;
8699 }
8700 Request::GetSignatureHelp(get_signature_help) => {
8701 let position = get_signature_help
8702 .position
8703 .clone()
8704 .and_then(deserialize_anchor);
8705 Self::query_lsp_locally::<GetSignatureHelp>(
8706 lsp_store,
8707 server_id,
8708 sender_id,
8709 lsp_request_id,
8710 get_signature_help,
8711 position,
8712 &mut cx,
8713 )
8714 .await?;
8715 }
8716 Request::GetCodeLens(get_code_lens) => {
8717 Self::query_lsp_locally::<GetCodeLens>(
8718 lsp_store,
8719 server_id,
8720 sender_id,
8721 lsp_request_id,
8722 get_code_lens,
8723 None,
8724 &mut cx,
8725 )
8726 .await?;
8727 }
8728 Request::GetDefinition(get_definition) => {
8729 let position = get_definition.position.clone().and_then(deserialize_anchor);
8730 Self::query_lsp_locally::<GetDefinitions>(
8731 lsp_store,
8732 server_id,
8733 sender_id,
8734 lsp_request_id,
8735 get_definition,
8736 position,
8737 &mut cx,
8738 )
8739 .await?;
8740 }
8741 Request::GetDeclaration(get_declaration) => {
8742 let position = get_declaration
8743 .position
8744 .clone()
8745 .and_then(deserialize_anchor);
8746 Self::query_lsp_locally::<GetDeclarations>(
8747 lsp_store,
8748 server_id,
8749 sender_id,
8750 lsp_request_id,
8751 get_declaration,
8752 position,
8753 &mut cx,
8754 )
8755 .await?;
8756 }
8757 Request::GetTypeDefinition(get_type_definition) => {
8758 let position = get_type_definition
8759 .position
8760 .clone()
8761 .and_then(deserialize_anchor);
8762 Self::query_lsp_locally::<GetTypeDefinitions>(
8763 lsp_store,
8764 server_id,
8765 sender_id,
8766 lsp_request_id,
8767 get_type_definition,
8768 position,
8769 &mut cx,
8770 )
8771 .await?;
8772 }
8773 Request::GetImplementation(get_implementation) => {
8774 let position = get_implementation
8775 .position
8776 .clone()
8777 .and_then(deserialize_anchor);
8778 Self::query_lsp_locally::<GetImplementations>(
8779 lsp_store,
8780 server_id,
8781 sender_id,
8782 lsp_request_id,
8783 get_implementation,
8784 position,
8785 &mut cx,
8786 )
8787 .await?;
8788 }
8789 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8790 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8791 let version = deserialize_version(get_document_diagnostics.buffer_version());
8792 let buffer = lsp_store.update(&mut cx, |this, cx| {
8793 this.buffer_store.read(cx).get_existing(buffer_id)
8794 })??;
8795 buffer
8796 .update(&mut cx, |buffer, _| {
8797 buffer.wait_for_version(version.clone())
8798 })?
8799 .await?;
8800 lsp_store.update(&mut cx, |lsp_store, cx| {
8801 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8802 let key = LspKey {
8803 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8804 server_queried: server_id,
8805 };
8806 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8807 ) {
8808 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8809 lsp_requests.clear();
8810 };
8811 }
8812
8813 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8814 existing_queries.insert(
8815 lsp_request_id,
8816 cx.spawn(async move |lsp_store, cx| {
8817 let diagnostics_pull = lsp_store
8818 .update(cx, |lsp_store, cx| {
8819 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8820 })
8821 .ok();
8822 if let Some(diagnostics_pull) = diagnostics_pull {
8823 match diagnostics_pull.await {
8824 Ok(()) => {}
8825 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8826 };
8827 }
8828 }),
8829 );
8830 })?;
8831 }
8832 Request::InlayHints(inlay_hints) => {
8833 let query_start = inlay_hints
8834 .start
8835 .clone()
8836 .and_then(deserialize_anchor)
8837 .context("invalid inlay hints range start")?;
8838 let query_end = inlay_hints
8839 .end
8840 .clone()
8841 .and_then(deserialize_anchor)
8842 .context("invalid inlay hints range end")?;
8843 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8844 &lsp_store,
8845 server_id,
8846 lsp_request_id,
8847 &inlay_hints,
8848 query_start..query_end,
8849 &mut cx,
8850 )
8851 .await
8852 .context("preparing inlay hints request")?;
8853 Self::query_lsp_locally::<InlayHints>(
8854 lsp_store,
8855 server_id,
8856 sender_id,
8857 lsp_request_id,
8858 inlay_hints,
8859 None,
8860 &mut cx,
8861 )
8862 .await
8863 .context("querying for inlay hints")?
8864 }
8865 }
8866 Ok(proto::Ack {})
8867 }
8868
8869 async fn handle_lsp_query_response(
8870 lsp_store: Entity<Self>,
8871 envelope: TypedEnvelope<proto::LspQueryResponse>,
8872 cx: AsyncApp,
8873 ) -> Result<()> {
8874 lsp_store.read_with(&cx, |lsp_store, _| {
8875 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8876 upstream_client.handle_lsp_response(envelope.clone());
8877 }
8878 })?;
8879 Ok(())
8880 }
8881
8882 async fn handle_apply_code_action(
8883 this: Entity<Self>,
8884 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8885 mut cx: AsyncApp,
8886 ) -> Result<proto::ApplyCodeActionResponse> {
8887 let sender_id = envelope.original_sender_id().unwrap_or_default();
8888 let action =
8889 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8890 let apply_code_action = this.update(&mut cx, |this, cx| {
8891 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8892 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8893 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8894 })??;
8895
8896 let project_transaction = apply_code_action.await?;
8897 let project_transaction = this.update(&mut cx, |this, cx| {
8898 this.buffer_store.update(cx, |buffer_store, cx| {
8899 buffer_store.serialize_project_transaction_for_peer(
8900 project_transaction,
8901 sender_id,
8902 cx,
8903 )
8904 })
8905 })?;
8906 Ok(proto::ApplyCodeActionResponse {
8907 transaction: Some(project_transaction),
8908 })
8909 }
8910
8911 async fn handle_register_buffer_with_language_servers(
8912 this: Entity<Self>,
8913 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8914 mut cx: AsyncApp,
8915 ) -> Result<proto::Ack> {
8916 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8917 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8918 this.update(&mut cx, |this, cx| {
8919 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8920 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8921 project_id: upstream_project_id,
8922 buffer_id: buffer_id.to_proto(),
8923 only_servers: envelope.payload.only_servers,
8924 });
8925 }
8926
8927 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8928 anyhow::bail!("buffer is not open");
8929 };
8930
8931 let handle = this.register_buffer_with_language_servers(
8932 &buffer,
8933 envelope
8934 .payload
8935 .only_servers
8936 .into_iter()
8937 .filter_map(|selector| {
8938 Some(match selector.selector? {
8939 proto::language_server_selector::Selector::ServerId(server_id) => {
8940 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8941 }
8942 proto::language_server_selector::Selector::Name(name) => {
8943 LanguageServerSelector::Name(LanguageServerName(
8944 SharedString::from(name),
8945 ))
8946 }
8947 })
8948 })
8949 .collect(),
8950 false,
8951 cx,
8952 );
8953 this.buffer_store().update(cx, |buffer_store, _| {
8954 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8955 });
8956
8957 Ok(())
8958 })??;
8959 Ok(proto::Ack {})
8960 }
8961
8962 async fn handle_rename_project_entry(
8963 this: Entity<Self>,
8964 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8965 mut cx: AsyncApp,
8966 ) -> Result<proto::ProjectEntryResponse> {
8967 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8968 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8969 let new_path =
8970 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8971
8972 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8973 .update(&mut cx, |this, cx| {
8974 let (worktree, entry) = this
8975 .worktree_store
8976 .read(cx)
8977 .worktree_and_entry_for_id(entry_id, cx)?;
8978 let new_worktree = this
8979 .worktree_store
8980 .read(cx)
8981 .worktree_for_id(new_worktree_id, cx)?;
8982 Some((
8983 this.worktree_store.clone(),
8984 worktree,
8985 new_worktree,
8986 entry.clone(),
8987 ))
8988 })?
8989 .context("worktree not found")?;
8990 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8991 (worktree.absolutize(&old_entry.path), worktree.id())
8992 })?;
8993 let new_abs_path =
8994 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8995
8996 let _transaction = Self::will_rename_entry(
8997 this.downgrade(),
8998 old_worktree_id,
8999 &old_abs_path,
9000 &new_abs_path,
9001 old_entry.is_dir(),
9002 cx.clone(),
9003 )
9004 .await;
9005 let response = WorktreeStore::handle_rename_project_entry(
9006 worktree_store,
9007 envelope.payload,
9008 cx.clone(),
9009 )
9010 .await;
9011 this.read_with(&cx, |this, _| {
9012 this.did_rename_entry(
9013 old_worktree_id,
9014 &old_abs_path,
9015 &new_abs_path,
9016 old_entry.is_dir(),
9017 );
9018 })
9019 .ok();
9020 response
9021 }
9022
9023 async fn handle_update_diagnostic_summary(
9024 this: Entity<Self>,
9025 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9026 mut cx: AsyncApp,
9027 ) -> Result<()> {
9028 this.update(&mut cx, |lsp_store, cx| {
9029 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9030 let mut updated_diagnostics_paths = HashMap::default();
9031 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9032 for message_summary in envelope
9033 .payload
9034 .summary
9035 .into_iter()
9036 .chain(envelope.payload.more_summaries)
9037 {
9038 let project_path = ProjectPath {
9039 worktree_id,
9040 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9041 };
9042 let path = project_path.path.clone();
9043 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9044 let summary = DiagnosticSummary {
9045 error_count: message_summary.error_count as usize,
9046 warning_count: message_summary.warning_count as usize,
9047 };
9048
9049 if summary.is_empty() {
9050 if let Some(worktree_summaries) =
9051 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9052 && let Some(summaries) = worktree_summaries.get_mut(&path)
9053 {
9054 summaries.remove(&server_id);
9055 if summaries.is_empty() {
9056 worktree_summaries.remove(&path);
9057 }
9058 }
9059 } else {
9060 lsp_store
9061 .diagnostic_summaries
9062 .entry(worktree_id)
9063 .or_default()
9064 .entry(path)
9065 .or_default()
9066 .insert(server_id, summary);
9067 }
9068
9069 if let Some((_, project_id)) = &lsp_store.downstream_client {
9070 match &mut diagnostics_summary {
9071 Some(diagnostics_summary) => {
9072 diagnostics_summary
9073 .more_summaries
9074 .push(proto::DiagnosticSummary {
9075 path: project_path.path.as_ref().to_proto(),
9076 language_server_id: server_id.0 as u64,
9077 error_count: summary.error_count as u32,
9078 warning_count: summary.warning_count as u32,
9079 })
9080 }
9081 None => {
9082 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9083 project_id: *project_id,
9084 worktree_id: worktree_id.to_proto(),
9085 summary: Some(proto::DiagnosticSummary {
9086 path: project_path.path.as_ref().to_proto(),
9087 language_server_id: server_id.0 as u64,
9088 error_count: summary.error_count as u32,
9089 warning_count: summary.warning_count as u32,
9090 }),
9091 more_summaries: Vec::new(),
9092 })
9093 }
9094 }
9095 }
9096 updated_diagnostics_paths
9097 .entry(server_id)
9098 .or_insert_with(Vec::new)
9099 .push(project_path);
9100 }
9101
9102 if let Some((diagnostics_summary, (downstream_client, _))) =
9103 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9104 {
9105 downstream_client.send(diagnostics_summary).log_err();
9106 }
9107 for (server_id, paths) in updated_diagnostics_paths {
9108 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9109 }
9110 Ok(())
9111 })?
9112 }
9113
9114 async fn handle_start_language_server(
9115 lsp_store: Entity<Self>,
9116 envelope: TypedEnvelope<proto::StartLanguageServer>,
9117 mut cx: AsyncApp,
9118 ) -> Result<()> {
9119 let server = envelope.payload.server.context("invalid server")?;
9120 let server_capabilities =
9121 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9122 .with_context(|| {
9123 format!(
9124 "incorrect server capabilities {}",
9125 envelope.payload.capabilities
9126 )
9127 })?;
9128 lsp_store.update(&mut cx, |lsp_store, cx| {
9129 let server_id = LanguageServerId(server.id as usize);
9130 let server_name = LanguageServerName::from_proto(server.name.clone());
9131 lsp_store
9132 .lsp_server_capabilities
9133 .insert(server_id, server_capabilities);
9134 lsp_store.language_server_statuses.insert(
9135 server_id,
9136 LanguageServerStatus {
9137 name: server_name.clone(),
9138 pending_work: Default::default(),
9139 has_pending_diagnostic_updates: false,
9140 progress_tokens: Default::default(),
9141 worktree: server.worktree_id.map(WorktreeId::from_proto),
9142 },
9143 );
9144 cx.emit(LspStoreEvent::LanguageServerAdded(
9145 server_id,
9146 server_name,
9147 server.worktree_id.map(WorktreeId::from_proto),
9148 ));
9149 cx.notify();
9150 })?;
9151 Ok(())
9152 }
9153
9154 async fn handle_update_language_server(
9155 lsp_store: Entity<Self>,
9156 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9157 mut cx: AsyncApp,
9158 ) -> Result<()> {
9159 lsp_store.update(&mut cx, |lsp_store, cx| {
9160 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9161
9162 match envelope.payload.variant.context("invalid variant")? {
9163 proto::update_language_server::Variant::WorkStart(payload) => {
9164 lsp_store.on_lsp_work_start(
9165 language_server_id,
9166 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9167 .context("invalid progress token value")?,
9168 LanguageServerProgress {
9169 title: payload.title,
9170 is_disk_based_diagnostics_progress: false,
9171 is_cancellable: payload.is_cancellable.unwrap_or(false),
9172 message: payload.message,
9173 percentage: payload.percentage.map(|p| p as usize),
9174 last_update_at: cx.background_executor().now(),
9175 },
9176 cx,
9177 );
9178 }
9179 proto::update_language_server::Variant::WorkProgress(payload) => {
9180 lsp_store.on_lsp_work_progress(
9181 language_server_id,
9182 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9183 .context("invalid progress token value")?,
9184 LanguageServerProgress {
9185 title: None,
9186 is_disk_based_diagnostics_progress: false,
9187 is_cancellable: payload.is_cancellable.unwrap_or(false),
9188 message: payload.message,
9189 percentage: payload.percentage.map(|p| p as usize),
9190 last_update_at: cx.background_executor().now(),
9191 },
9192 cx,
9193 );
9194 }
9195
9196 proto::update_language_server::Variant::WorkEnd(payload) => {
9197 lsp_store.on_lsp_work_end(
9198 language_server_id,
9199 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9200 .context("invalid progress token value")?,
9201 cx,
9202 );
9203 }
9204
9205 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9206 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9207 }
9208
9209 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9210 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9211 }
9212
9213 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9214 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9215 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9216 cx.emit(LspStoreEvent::LanguageServerUpdate {
9217 language_server_id,
9218 name: envelope
9219 .payload
9220 .server_name
9221 .map(SharedString::new)
9222 .map(LanguageServerName),
9223 message: non_lsp,
9224 });
9225 }
9226 }
9227
9228 Ok(())
9229 })?
9230 }
9231
9232 async fn handle_language_server_log(
9233 this: Entity<Self>,
9234 envelope: TypedEnvelope<proto::LanguageServerLog>,
9235 mut cx: AsyncApp,
9236 ) -> Result<()> {
9237 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9238 let log_type = envelope
9239 .payload
9240 .log_type
9241 .map(LanguageServerLogType::from_proto)
9242 .context("invalid language server log type")?;
9243
9244 let message = envelope.payload.message;
9245
9246 this.update(&mut cx, |_, cx| {
9247 cx.emit(LspStoreEvent::LanguageServerLog(
9248 language_server_id,
9249 log_type,
9250 message,
9251 ));
9252 })
9253 }
9254
9255 async fn handle_lsp_ext_cancel_flycheck(
9256 lsp_store: Entity<Self>,
9257 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9258 cx: AsyncApp,
9259 ) -> Result<proto::Ack> {
9260 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9261 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9262 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9263 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9264 } else {
9265 None
9266 }
9267 })?;
9268 if let Some(task) = task {
9269 task.context("handling lsp ext cancel flycheck")?;
9270 }
9271
9272 Ok(proto::Ack {})
9273 }
9274
9275 async fn handle_lsp_ext_run_flycheck(
9276 lsp_store: Entity<Self>,
9277 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9278 mut cx: AsyncApp,
9279 ) -> Result<proto::Ack> {
9280 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9281 lsp_store.update(&mut cx, |lsp_store, cx| {
9282 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9283 let text_document = if envelope.payload.current_file_only {
9284 let buffer_id = envelope
9285 .payload
9286 .buffer_id
9287 .map(|id| BufferId::new(id))
9288 .transpose()?;
9289 buffer_id
9290 .and_then(|buffer_id| {
9291 lsp_store
9292 .buffer_store()
9293 .read(cx)
9294 .get(buffer_id)
9295 .and_then(|buffer| {
9296 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9297 })
9298 .map(|path| make_text_document_identifier(&path))
9299 })
9300 .transpose()?
9301 } else {
9302 None
9303 };
9304 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9305 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9306 )?;
9307 }
9308 anyhow::Ok(())
9309 })??;
9310
9311 Ok(proto::Ack {})
9312 }
9313
9314 async fn handle_lsp_ext_clear_flycheck(
9315 lsp_store: Entity<Self>,
9316 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9317 cx: AsyncApp,
9318 ) -> Result<proto::Ack> {
9319 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9320 lsp_store
9321 .read_with(&cx, |lsp_store, _| {
9322 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9323 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9324 } else {
9325 None
9326 }
9327 })
9328 .context("handling lsp ext clear flycheck")?;
9329
9330 Ok(proto::Ack {})
9331 }
9332
9333 pub fn disk_based_diagnostics_started(
9334 &mut self,
9335 language_server_id: LanguageServerId,
9336 cx: &mut Context<Self>,
9337 ) {
9338 if let Some(language_server_status) =
9339 self.language_server_statuses.get_mut(&language_server_id)
9340 {
9341 language_server_status.has_pending_diagnostic_updates = true;
9342 }
9343
9344 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9345 cx.emit(LspStoreEvent::LanguageServerUpdate {
9346 language_server_id,
9347 name: self
9348 .language_server_adapter_for_id(language_server_id)
9349 .map(|adapter| adapter.name()),
9350 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9351 Default::default(),
9352 ),
9353 })
9354 }
9355
9356 pub fn disk_based_diagnostics_finished(
9357 &mut self,
9358 language_server_id: LanguageServerId,
9359 cx: &mut Context<Self>,
9360 ) {
9361 if let Some(language_server_status) =
9362 self.language_server_statuses.get_mut(&language_server_id)
9363 {
9364 language_server_status.has_pending_diagnostic_updates = false;
9365 }
9366
9367 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9368 cx.emit(LspStoreEvent::LanguageServerUpdate {
9369 language_server_id,
9370 name: self
9371 .language_server_adapter_for_id(language_server_id)
9372 .map(|adapter| adapter.name()),
9373 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9374 Default::default(),
9375 ),
9376 })
9377 }
9378
9379 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9380 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9381 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9382 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9383 // the language server might take some time to publish diagnostics.
9384 fn simulate_disk_based_diagnostics_events_if_needed(
9385 &mut self,
9386 language_server_id: LanguageServerId,
9387 cx: &mut Context<Self>,
9388 ) {
9389 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9390
9391 let Some(LanguageServerState::Running {
9392 simulate_disk_based_diagnostics_completion,
9393 adapter,
9394 ..
9395 }) = self
9396 .as_local_mut()
9397 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9398 else {
9399 return;
9400 };
9401
9402 if adapter.disk_based_diagnostics_progress_token.is_some() {
9403 return;
9404 }
9405
9406 let prev_task =
9407 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9408 cx.background_executor()
9409 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9410 .await;
9411
9412 this.update(cx, |this, cx| {
9413 this.disk_based_diagnostics_finished(language_server_id, cx);
9414
9415 if let Some(LanguageServerState::Running {
9416 simulate_disk_based_diagnostics_completion,
9417 ..
9418 }) = this.as_local_mut().and_then(|local_store| {
9419 local_store.language_servers.get_mut(&language_server_id)
9420 }) {
9421 *simulate_disk_based_diagnostics_completion = None;
9422 }
9423 })
9424 .ok();
9425 }));
9426
9427 if prev_task.is_none() {
9428 self.disk_based_diagnostics_started(language_server_id, cx);
9429 }
9430 }
9431
9432 pub fn language_server_statuses(
9433 &self,
9434 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9435 self.language_server_statuses
9436 .iter()
9437 .map(|(key, value)| (*key, value))
9438 }
9439
9440 pub(super) fn did_rename_entry(
9441 &self,
9442 worktree_id: WorktreeId,
9443 old_path: &Path,
9444 new_path: &Path,
9445 is_dir: bool,
9446 ) {
9447 maybe!({
9448 let local_store = self.as_local()?;
9449
9450 let old_uri = lsp::Uri::from_file_path(old_path)
9451 .ok()
9452 .map(|uri| uri.to_string())?;
9453 let new_uri = lsp::Uri::from_file_path(new_path)
9454 .ok()
9455 .map(|uri| uri.to_string())?;
9456
9457 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9458 let Some(filter) = local_store
9459 .language_server_paths_watched_for_rename
9460 .get(&language_server.server_id())
9461 else {
9462 continue;
9463 };
9464
9465 if filter.should_send_did_rename(&old_uri, is_dir) {
9466 language_server
9467 .notify::<DidRenameFiles>(RenameFilesParams {
9468 files: vec![FileRename {
9469 old_uri: old_uri.clone(),
9470 new_uri: new_uri.clone(),
9471 }],
9472 })
9473 .ok();
9474 }
9475 }
9476 Some(())
9477 });
9478 }
9479
9480 pub(super) fn will_rename_entry(
9481 this: WeakEntity<Self>,
9482 worktree_id: WorktreeId,
9483 old_path: &Path,
9484 new_path: &Path,
9485 is_dir: bool,
9486 cx: AsyncApp,
9487 ) -> Task<ProjectTransaction> {
9488 let old_uri = lsp::Uri::from_file_path(old_path)
9489 .ok()
9490 .map(|uri| uri.to_string());
9491 let new_uri = lsp::Uri::from_file_path(new_path)
9492 .ok()
9493 .map(|uri| uri.to_string());
9494 cx.spawn(async move |cx| {
9495 let mut tasks = vec![];
9496 this.update(cx, |this, cx| {
9497 let local_store = this.as_local()?;
9498 let old_uri = old_uri?;
9499 let new_uri = new_uri?;
9500 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9501 let Some(filter) = local_store
9502 .language_server_paths_watched_for_rename
9503 .get(&language_server.server_id())
9504 else {
9505 continue;
9506 };
9507
9508 if filter.should_send_will_rename(&old_uri, is_dir) {
9509 let apply_edit = cx.spawn({
9510 let old_uri = old_uri.clone();
9511 let new_uri = new_uri.clone();
9512 let language_server = language_server.clone();
9513 async move |this, cx| {
9514 let edit = language_server
9515 .request::<WillRenameFiles>(RenameFilesParams {
9516 files: vec![FileRename { old_uri, new_uri }],
9517 })
9518 .await
9519 .into_response()
9520 .context("will rename files")
9521 .log_err()
9522 .flatten()?;
9523
9524 let transaction = LocalLspStore::deserialize_workspace_edit(
9525 this.upgrade()?,
9526 edit,
9527 false,
9528 language_server.clone(),
9529 cx,
9530 )
9531 .await
9532 .ok()?;
9533 Some(transaction)
9534 }
9535 });
9536 tasks.push(apply_edit);
9537 }
9538 }
9539 Some(())
9540 })
9541 .ok()
9542 .flatten();
9543 let mut merged_transaction = ProjectTransaction::default();
9544 for task in tasks {
9545 // Await on tasks sequentially so that the order of application of edits is deterministic
9546 // (at least with regards to the order of registration of language servers)
9547 if let Some(transaction) = task.await {
9548 for (buffer, buffer_transaction) in transaction.0 {
9549 merged_transaction.0.insert(buffer, buffer_transaction);
9550 }
9551 }
9552 }
9553 merged_transaction
9554 })
9555 }
9556
9557 fn lsp_notify_abs_paths_changed(
9558 &mut self,
9559 server_id: LanguageServerId,
9560 changes: Vec<PathEvent>,
9561 ) {
9562 maybe!({
9563 let server = self.language_server_for_id(server_id)?;
9564 let changes = changes
9565 .into_iter()
9566 .filter_map(|event| {
9567 let typ = match event.kind? {
9568 PathEventKind::Created => lsp::FileChangeType::CREATED,
9569 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9570 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9571 };
9572 Some(lsp::FileEvent {
9573 uri: file_path_to_lsp_url(&event.path).log_err()?,
9574 typ,
9575 })
9576 })
9577 .collect::<Vec<_>>();
9578 if !changes.is_empty() {
9579 server
9580 .notify::<lsp::notification::DidChangeWatchedFiles>(
9581 lsp::DidChangeWatchedFilesParams { changes },
9582 )
9583 .ok();
9584 }
9585 Some(())
9586 });
9587 }
9588
9589 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9590 self.as_local()?.language_server_for_id(id)
9591 }
9592
9593 fn on_lsp_progress(
9594 &mut self,
9595 progress_params: lsp::ProgressParams,
9596 language_server_id: LanguageServerId,
9597 disk_based_diagnostics_progress_token: Option<String>,
9598 cx: &mut Context<Self>,
9599 ) {
9600 match progress_params.value {
9601 lsp::ProgressParamsValue::WorkDone(progress) => {
9602 self.handle_work_done_progress(
9603 progress,
9604 language_server_id,
9605 disk_based_diagnostics_progress_token,
9606 ProgressToken::from_lsp(progress_params.token),
9607 cx,
9608 );
9609 }
9610 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9611 let identifier = match progress_params.token {
9612 lsp::NumberOrString::Number(_) => None,
9613 lsp::NumberOrString::String(token) => token
9614 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9615 .map(|(_, id)| id.to_owned()),
9616 };
9617 if let Some(LanguageServerState::Running {
9618 workspace_diagnostics_refresh_tasks,
9619 ..
9620 }) = self
9621 .as_local_mut()
9622 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9623 && let Some(workspace_diagnostics) =
9624 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9625 {
9626 workspace_diagnostics.progress_tx.try_send(()).ok();
9627 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9628 }
9629 }
9630 }
9631 }
9632
9633 fn handle_work_done_progress(
9634 &mut self,
9635 progress: lsp::WorkDoneProgress,
9636 language_server_id: LanguageServerId,
9637 disk_based_diagnostics_progress_token: Option<String>,
9638 token: ProgressToken,
9639 cx: &mut Context<Self>,
9640 ) {
9641 let language_server_status =
9642 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9643 status
9644 } else {
9645 return;
9646 };
9647
9648 if !language_server_status.progress_tokens.contains(&token) {
9649 return;
9650 }
9651
9652 let is_disk_based_diagnostics_progress =
9653 if let (Some(disk_based_token), ProgressToken::String(token)) =
9654 (&disk_based_diagnostics_progress_token, &token)
9655 {
9656 token.starts_with(disk_based_token)
9657 } else {
9658 false
9659 };
9660
9661 match progress {
9662 lsp::WorkDoneProgress::Begin(report) => {
9663 if is_disk_based_diagnostics_progress {
9664 self.disk_based_diagnostics_started(language_server_id, cx);
9665 }
9666 self.on_lsp_work_start(
9667 language_server_id,
9668 token.clone(),
9669 LanguageServerProgress {
9670 title: Some(report.title),
9671 is_disk_based_diagnostics_progress,
9672 is_cancellable: report.cancellable.unwrap_or(false),
9673 message: report.message.clone(),
9674 percentage: report.percentage.map(|p| p as usize),
9675 last_update_at: cx.background_executor().now(),
9676 },
9677 cx,
9678 );
9679 }
9680 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9681 language_server_id,
9682 token,
9683 LanguageServerProgress {
9684 title: None,
9685 is_disk_based_diagnostics_progress,
9686 is_cancellable: report.cancellable.unwrap_or(false),
9687 message: report.message,
9688 percentage: report.percentage.map(|p| p as usize),
9689 last_update_at: cx.background_executor().now(),
9690 },
9691 cx,
9692 ),
9693 lsp::WorkDoneProgress::End(_) => {
9694 language_server_status.progress_tokens.remove(&token);
9695 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9696 if is_disk_based_diagnostics_progress {
9697 self.disk_based_diagnostics_finished(language_server_id, cx);
9698 }
9699 }
9700 }
9701 }
9702
9703 fn on_lsp_work_start(
9704 &mut self,
9705 language_server_id: LanguageServerId,
9706 token: ProgressToken,
9707 progress: LanguageServerProgress,
9708 cx: &mut Context<Self>,
9709 ) {
9710 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9711 status.pending_work.insert(token.clone(), progress.clone());
9712 cx.notify();
9713 }
9714 cx.emit(LspStoreEvent::LanguageServerUpdate {
9715 language_server_id,
9716 name: self
9717 .language_server_adapter_for_id(language_server_id)
9718 .map(|adapter| adapter.name()),
9719 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9720 token: Some(token.to_proto()),
9721 title: progress.title,
9722 message: progress.message,
9723 percentage: progress.percentage.map(|p| p as u32),
9724 is_cancellable: Some(progress.is_cancellable),
9725 }),
9726 })
9727 }
9728
9729 fn on_lsp_work_progress(
9730 &mut self,
9731 language_server_id: LanguageServerId,
9732 token: ProgressToken,
9733 progress: LanguageServerProgress,
9734 cx: &mut Context<Self>,
9735 ) {
9736 let mut did_update = false;
9737 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9738 match status.pending_work.entry(token.clone()) {
9739 btree_map::Entry::Vacant(entry) => {
9740 entry.insert(progress.clone());
9741 did_update = true;
9742 }
9743 btree_map::Entry::Occupied(mut entry) => {
9744 let entry = entry.get_mut();
9745 if (progress.last_update_at - entry.last_update_at)
9746 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9747 {
9748 entry.last_update_at = progress.last_update_at;
9749 if progress.message.is_some() {
9750 entry.message = progress.message.clone();
9751 }
9752 if progress.percentage.is_some() {
9753 entry.percentage = progress.percentage;
9754 }
9755 if progress.is_cancellable != entry.is_cancellable {
9756 entry.is_cancellable = progress.is_cancellable;
9757 }
9758 did_update = true;
9759 }
9760 }
9761 }
9762 }
9763
9764 if did_update {
9765 cx.emit(LspStoreEvent::LanguageServerUpdate {
9766 language_server_id,
9767 name: self
9768 .language_server_adapter_for_id(language_server_id)
9769 .map(|adapter| adapter.name()),
9770 message: proto::update_language_server::Variant::WorkProgress(
9771 proto::LspWorkProgress {
9772 token: Some(token.to_proto()),
9773 message: progress.message,
9774 percentage: progress.percentage.map(|p| p as u32),
9775 is_cancellable: Some(progress.is_cancellable),
9776 },
9777 ),
9778 })
9779 }
9780 }
9781
9782 fn on_lsp_work_end(
9783 &mut self,
9784 language_server_id: LanguageServerId,
9785 token: ProgressToken,
9786 cx: &mut Context<Self>,
9787 ) {
9788 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9789 if let Some(work) = status.pending_work.remove(&token)
9790 && !work.is_disk_based_diagnostics_progress
9791 {
9792 cx.emit(LspStoreEvent::RefreshInlayHints {
9793 server_id: language_server_id,
9794 request_id: None,
9795 });
9796 }
9797 cx.notify();
9798 }
9799
9800 cx.emit(LspStoreEvent::LanguageServerUpdate {
9801 language_server_id,
9802 name: self
9803 .language_server_adapter_for_id(language_server_id)
9804 .map(|adapter| adapter.name()),
9805 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9806 token: Some(token.to_proto()),
9807 }),
9808 })
9809 }
9810
9811 pub async fn handle_resolve_completion_documentation(
9812 this: Entity<Self>,
9813 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9814 mut cx: AsyncApp,
9815 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9816 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9817
9818 let completion = this
9819 .read_with(&cx, |this, cx| {
9820 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9821 let server = this
9822 .language_server_for_id(id)
9823 .with_context(|| format!("No language server {id}"))?;
9824
9825 anyhow::Ok(cx.background_spawn(async move {
9826 let can_resolve = server
9827 .capabilities()
9828 .completion_provider
9829 .as_ref()
9830 .and_then(|options| options.resolve_provider)
9831 .unwrap_or(false);
9832 if can_resolve {
9833 server
9834 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9835 .await
9836 .into_response()
9837 .context("resolve completion item")
9838 } else {
9839 anyhow::Ok(lsp_completion)
9840 }
9841 }))
9842 })??
9843 .await?;
9844
9845 let mut documentation_is_markdown = false;
9846 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9847 let documentation = match completion.documentation {
9848 Some(lsp::Documentation::String(text)) => text,
9849
9850 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9851 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9852 value
9853 }
9854
9855 _ => String::new(),
9856 };
9857
9858 // If we have a new buffer_id, that means we're talking to a new client
9859 // and want to check for new text_edits in the completion too.
9860 let mut old_replace_start = None;
9861 let mut old_replace_end = None;
9862 let mut old_insert_start = None;
9863 let mut old_insert_end = None;
9864 let mut new_text = String::default();
9865 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9866 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9867 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9868 anyhow::Ok(buffer.read(cx).snapshot())
9869 })??;
9870
9871 if let Some(text_edit) = completion.text_edit.as_ref() {
9872 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9873
9874 if let Some(mut edit) = edit {
9875 LineEnding::normalize(&mut edit.new_text);
9876
9877 new_text = edit.new_text;
9878 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9879 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9880 if let Some(insert_range) = edit.insert_range {
9881 old_insert_start = Some(serialize_anchor(&insert_range.start));
9882 old_insert_end = Some(serialize_anchor(&insert_range.end));
9883 }
9884 }
9885 }
9886 }
9887
9888 Ok(proto::ResolveCompletionDocumentationResponse {
9889 documentation,
9890 documentation_is_markdown,
9891 old_replace_start,
9892 old_replace_end,
9893 new_text,
9894 lsp_completion,
9895 old_insert_start,
9896 old_insert_end,
9897 })
9898 }
9899
9900 async fn handle_on_type_formatting(
9901 this: Entity<Self>,
9902 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9903 mut cx: AsyncApp,
9904 ) -> Result<proto::OnTypeFormattingResponse> {
9905 let on_type_formatting = this.update(&mut cx, |this, cx| {
9906 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9907 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9908 let position = envelope
9909 .payload
9910 .position
9911 .and_then(deserialize_anchor)
9912 .context("invalid position")?;
9913 anyhow::Ok(this.apply_on_type_formatting(
9914 buffer,
9915 position,
9916 envelope.payload.trigger.clone(),
9917 cx,
9918 ))
9919 })??;
9920
9921 let transaction = on_type_formatting
9922 .await?
9923 .as_ref()
9924 .map(language::proto::serialize_transaction);
9925 Ok(proto::OnTypeFormattingResponse { transaction })
9926 }
9927
9928 async fn handle_refresh_inlay_hints(
9929 lsp_store: Entity<Self>,
9930 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9931 mut cx: AsyncApp,
9932 ) -> Result<proto::Ack> {
9933 lsp_store.update(&mut cx, |_, cx| {
9934 cx.emit(LspStoreEvent::RefreshInlayHints {
9935 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9936 request_id: envelope.payload.request_id.map(|id| id as usize),
9937 });
9938 })?;
9939 Ok(proto::Ack {})
9940 }
9941
9942 async fn handle_pull_workspace_diagnostics(
9943 lsp_store: Entity<Self>,
9944 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9945 mut cx: AsyncApp,
9946 ) -> Result<proto::Ack> {
9947 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9948 lsp_store.update(&mut cx, |lsp_store, _| {
9949 lsp_store.pull_workspace_diagnostics(server_id);
9950 })?;
9951 Ok(proto::Ack {})
9952 }
9953
9954 async fn handle_get_color_presentation(
9955 lsp_store: Entity<Self>,
9956 envelope: TypedEnvelope<proto::GetColorPresentation>,
9957 mut cx: AsyncApp,
9958 ) -> Result<proto::GetColorPresentationResponse> {
9959 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9960 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9961 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9962 })??;
9963
9964 let color = envelope
9965 .payload
9966 .color
9967 .context("invalid color resolve request")?;
9968 let start = color
9969 .lsp_range_start
9970 .context("invalid color resolve request")?;
9971 let end = color
9972 .lsp_range_end
9973 .context("invalid color resolve request")?;
9974
9975 let color = DocumentColor {
9976 lsp_range: lsp::Range {
9977 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9978 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9979 },
9980 color: lsp::Color {
9981 red: color.red,
9982 green: color.green,
9983 blue: color.blue,
9984 alpha: color.alpha,
9985 },
9986 resolved: false,
9987 color_presentations: Vec::new(),
9988 };
9989 let resolved_color = lsp_store
9990 .update(&mut cx, |lsp_store, cx| {
9991 lsp_store.resolve_color_presentation(
9992 color,
9993 buffer.clone(),
9994 LanguageServerId(envelope.payload.server_id as usize),
9995 cx,
9996 )
9997 })?
9998 .await
9999 .context("resolving color presentation")?;
10000
10001 Ok(proto::GetColorPresentationResponse {
10002 presentations: resolved_color
10003 .color_presentations
10004 .into_iter()
10005 .map(|presentation| proto::ColorPresentation {
10006 label: presentation.label.to_string(),
10007 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10008 additional_text_edits: presentation
10009 .additional_text_edits
10010 .into_iter()
10011 .map(serialize_lsp_edit)
10012 .collect(),
10013 })
10014 .collect(),
10015 })
10016 }
10017
10018 async fn handle_resolve_inlay_hint(
10019 lsp_store: Entity<Self>,
10020 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10021 mut cx: AsyncApp,
10022 ) -> Result<proto::ResolveInlayHintResponse> {
10023 let proto_hint = envelope
10024 .payload
10025 .hint
10026 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10027 let hint = InlayHints::proto_to_project_hint(proto_hint)
10028 .context("resolved proto inlay hint conversion")?;
10029 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10030 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10031 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10032 })??;
10033 let response_hint = lsp_store
10034 .update(&mut cx, |lsp_store, cx| {
10035 lsp_store.resolve_inlay_hint(
10036 hint,
10037 buffer,
10038 LanguageServerId(envelope.payload.language_server_id as usize),
10039 cx,
10040 )
10041 })?
10042 .await
10043 .context("inlay hints fetch")?;
10044 Ok(proto::ResolveInlayHintResponse {
10045 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10046 })
10047 }
10048
10049 async fn handle_refresh_code_lens(
10050 this: Entity<Self>,
10051 _: TypedEnvelope<proto::RefreshCodeLens>,
10052 mut cx: AsyncApp,
10053 ) -> Result<proto::Ack> {
10054 this.update(&mut cx, |_, cx| {
10055 cx.emit(LspStoreEvent::RefreshCodeLens);
10056 })?;
10057 Ok(proto::Ack {})
10058 }
10059
10060 async fn handle_open_buffer_for_symbol(
10061 this: Entity<Self>,
10062 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10063 mut cx: AsyncApp,
10064 ) -> Result<proto::OpenBufferForSymbolResponse> {
10065 let peer_id = envelope.original_sender_id().unwrap_or_default();
10066 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10067 let symbol = Self::deserialize_symbol(symbol)?;
10068 this.read_with(&cx, |this, _| {
10069 if let SymbolLocation::OutsideProject {
10070 abs_path,
10071 signature,
10072 } = &symbol.path
10073 {
10074 let new_signature = this.symbol_signature(&abs_path);
10075 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10076 }
10077 Ok(())
10078 })??;
10079 let buffer = this
10080 .update(&mut cx, |this, cx| {
10081 this.open_buffer_for_symbol(
10082 &Symbol {
10083 language_server_name: symbol.language_server_name,
10084 source_worktree_id: symbol.source_worktree_id,
10085 source_language_server_id: symbol.source_language_server_id,
10086 path: symbol.path,
10087 name: symbol.name,
10088 kind: symbol.kind,
10089 range: symbol.range,
10090 label: CodeLabel::default(),
10091 },
10092 cx,
10093 )
10094 })?
10095 .await?;
10096
10097 this.update(&mut cx, |this, cx| {
10098 let is_private = buffer
10099 .read(cx)
10100 .file()
10101 .map(|f| f.is_private())
10102 .unwrap_or_default();
10103 if is_private {
10104 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10105 } else {
10106 this.buffer_store
10107 .update(cx, |buffer_store, cx| {
10108 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10109 })
10110 .detach_and_log_err(cx);
10111 let buffer_id = buffer.read(cx).remote_id().to_proto();
10112 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10113 }
10114 })?
10115 }
10116
10117 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10118 let mut hasher = Sha256::new();
10119 hasher.update(abs_path.to_string_lossy().as_bytes());
10120 hasher.update(self.nonce.to_be_bytes());
10121 hasher.finalize().as_slice().try_into().unwrap()
10122 }
10123
10124 pub async fn handle_get_project_symbols(
10125 this: Entity<Self>,
10126 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10127 mut cx: AsyncApp,
10128 ) -> Result<proto::GetProjectSymbolsResponse> {
10129 let symbols = this
10130 .update(&mut cx, |this, cx| {
10131 this.symbols(&envelope.payload.query, cx)
10132 })?
10133 .await?;
10134
10135 Ok(proto::GetProjectSymbolsResponse {
10136 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10137 })
10138 }
10139
10140 pub async fn handle_restart_language_servers(
10141 this: Entity<Self>,
10142 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10143 mut cx: AsyncApp,
10144 ) -> Result<proto::Ack> {
10145 this.update(&mut cx, |lsp_store, cx| {
10146 let buffers =
10147 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10148 lsp_store.restart_language_servers_for_buffers(
10149 buffers,
10150 envelope
10151 .payload
10152 .only_servers
10153 .into_iter()
10154 .filter_map(|selector| {
10155 Some(match selector.selector? {
10156 proto::language_server_selector::Selector::ServerId(server_id) => {
10157 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10158 }
10159 proto::language_server_selector::Selector::Name(name) => {
10160 LanguageServerSelector::Name(LanguageServerName(
10161 SharedString::from(name),
10162 ))
10163 }
10164 })
10165 })
10166 .collect(),
10167 cx,
10168 );
10169 })?;
10170
10171 Ok(proto::Ack {})
10172 }
10173
10174 pub async fn handle_stop_language_servers(
10175 lsp_store: Entity<Self>,
10176 envelope: TypedEnvelope<proto::StopLanguageServers>,
10177 mut cx: AsyncApp,
10178 ) -> Result<proto::Ack> {
10179 lsp_store.update(&mut cx, |lsp_store, cx| {
10180 if envelope.payload.all
10181 && envelope.payload.also_servers.is_empty()
10182 && envelope.payload.buffer_ids.is_empty()
10183 {
10184 lsp_store.stop_all_language_servers(cx);
10185 } else {
10186 let buffers =
10187 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10188 lsp_store
10189 .stop_language_servers_for_buffers(
10190 buffers,
10191 envelope
10192 .payload
10193 .also_servers
10194 .into_iter()
10195 .filter_map(|selector| {
10196 Some(match selector.selector? {
10197 proto::language_server_selector::Selector::ServerId(
10198 server_id,
10199 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10200 server_id,
10201 )),
10202 proto::language_server_selector::Selector::Name(name) => {
10203 LanguageServerSelector::Name(LanguageServerName(
10204 SharedString::from(name),
10205 ))
10206 }
10207 })
10208 })
10209 .collect(),
10210 cx,
10211 )
10212 .detach_and_log_err(cx);
10213 }
10214 })?;
10215
10216 Ok(proto::Ack {})
10217 }
10218
10219 pub async fn handle_cancel_language_server_work(
10220 lsp_store: Entity<Self>,
10221 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10222 mut cx: AsyncApp,
10223 ) -> Result<proto::Ack> {
10224 lsp_store.update(&mut cx, |lsp_store, cx| {
10225 if let Some(work) = envelope.payload.work {
10226 match work {
10227 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10228 let buffers =
10229 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10230 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10231 }
10232 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10233 let server_id = LanguageServerId::from_proto(work.language_server_id);
10234 let token = work
10235 .token
10236 .map(|token| {
10237 ProgressToken::from_proto(token)
10238 .context("invalid work progress token")
10239 })
10240 .transpose()?;
10241 lsp_store.cancel_language_server_work(server_id, token, cx);
10242 }
10243 }
10244 }
10245 anyhow::Ok(())
10246 })??;
10247
10248 Ok(proto::Ack {})
10249 }
10250
10251 fn buffer_ids_to_buffers(
10252 &mut self,
10253 buffer_ids: impl Iterator<Item = u64>,
10254 cx: &mut Context<Self>,
10255 ) -> Vec<Entity<Buffer>> {
10256 buffer_ids
10257 .into_iter()
10258 .flat_map(|buffer_id| {
10259 self.buffer_store
10260 .read(cx)
10261 .get(BufferId::new(buffer_id).log_err()?)
10262 })
10263 .collect::<Vec<_>>()
10264 }
10265
10266 async fn handle_apply_additional_edits_for_completion(
10267 this: Entity<Self>,
10268 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10269 mut cx: AsyncApp,
10270 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10271 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10272 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10273 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10274 let completion = Self::deserialize_completion(
10275 envelope.payload.completion.context("invalid completion")?,
10276 )?;
10277 anyhow::Ok((buffer, completion))
10278 })??;
10279
10280 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10281 this.apply_additional_edits_for_completion(
10282 buffer,
10283 Rc::new(RefCell::new(Box::new([Completion {
10284 replace_range: completion.replace_range,
10285 new_text: completion.new_text,
10286 source: completion.source,
10287 documentation: None,
10288 label: CodeLabel::default(),
10289 match_start: None,
10290 snippet_deduplication_key: None,
10291 insert_text_mode: None,
10292 icon_path: None,
10293 confirm: None,
10294 }]))),
10295 0,
10296 false,
10297 cx,
10298 )
10299 })?;
10300
10301 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10302 transaction: apply_additional_edits
10303 .await?
10304 .as_ref()
10305 .map(language::proto::serialize_transaction),
10306 })
10307 }
10308
10309 pub fn last_formatting_failure(&self) -> Option<&str> {
10310 self.last_formatting_failure.as_deref()
10311 }
10312
10313 pub fn reset_last_formatting_failure(&mut self) {
10314 self.last_formatting_failure = None;
10315 }
10316
10317 pub fn environment_for_buffer(
10318 &self,
10319 buffer: &Entity<Buffer>,
10320 cx: &mut Context<Self>,
10321 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10322 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10323 environment.update(cx, |env, cx| {
10324 env.buffer_environment(buffer, &self.worktree_store, cx)
10325 })
10326 } else {
10327 Task::ready(None).shared()
10328 }
10329 }
10330
10331 pub fn format(
10332 &mut self,
10333 buffers: HashSet<Entity<Buffer>>,
10334 target: LspFormatTarget,
10335 push_to_history: bool,
10336 trigger: FormatTrigger,
10337 cx: &mut Context<Self>,
10338 ) -> Task<anyhow::Result<ProjectTransaction>> {
10339 let logger = zlog::scoped!("format");
10340 if self.as_local().is_some() {
10341 zlog::trace!(logger => "Formatting locally");
10342 let logger = zlog::scoped!(logger => "local");
10343 let buffers = buffers
10344 .into_iter()
10345 .map(|buffer_handle| {
10346 let buffer = buffer_handle.read(cx);
10347 let buffer_abs_path = File::from_dyn(buffer.file())
10348 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10349
10350 (buffer_handle, buffer_abs_path, buffer.remote_id())
10351 })
10352 .collect::<Vec<_>>();
10353
10354 cx.spawn(async move |lsp_store, cx| {
10355 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10356
10357 for (handle, abs_path, id) in buffers {
10358 let env = lsp_store
10359 .update(cx, |lsp_store, cx| {
10360 lsp_store.environment_for_buffer(&handle, cx)
10361 })?
10362 .await;
10363
10364 let ranges = match &target {
10365 LspFormatTarget::Buffers => None,
10366 LspFormatTarget::Ranges(ranges) => {
10367 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10368 }
10369 };
10370
10371 formattable_buffers.push(FormattableBuffer {
10372 handle,
10373 abs_path,
10374 env,
10375 ranges,
10376 });
10377 }
10378 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10379
10380 let format_timer = zlog::time!(logger => "Formatting buffers");
10381 let result = LocalLspStore::format_locally(
10382 lsp_store.clone(),
10383 formattable_buffers,
10384 push_to_history,
10385 trigger,
10386 logger,
10387 cx,
10388 )
10389 .await;
10390 format_timer.end();
10391
10392 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10393
10394 lsp_store.update(cx, |lsp_store, _| {
10395 lsp_store.update_last_formatting_failure(&result);
10396 })?;
10397
10398 result
10399 })
10400 } else if let Some((client, project_id)) = self.upstream_client() {
10401 zlog::trace!(logger => "Formatting remotely");
10402 let logger = zlog::scoped!(logger => "remote");
10403 // Don't support formatting ranges via remote
10404 match target {
10405 LspFormatTarget::Buffers => {}
10406 LspFormatTarget::Ranges(_) => {
10407 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10408 return Task::ready(Ok(ProjectTransaction::default()));
10409 }
10410 }
10411
10412 let buffer_store = self.buffer_store();
10413 cx.spawn(async move |lsp_store, cx| {
10414 zlog::trace!(logger => "Sending remote format request");
10415 let request_timer = zlog::time!(logger => "remote format request");
10416 let result = client
10417 .request(proto::FormatBuffers {
10418 project_id,
10419 trigger: trigger as i32,
10420 buffer_ids: buffers
10421 .iter()
10422 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10423 .collect::<Result<_>>()?,
10424 })
10425 .await
10426 .and_then(|result| result.transaction.context("missing transaction"));
10427 request_timer.end();
10428
10429 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10430
10431 lsp_store.update(cx, |lsp_store, _| {
10432 lsp_store.update_last_formatting_failure(&result);
10433 })?;
10434
10435 let transaction_response = result?;
10436 let _timer = zlog::time!(logger => "deserializing project transaction");
10437 buffer_store
10438 .update(cx, |buffer_store, cx| {
10439 buffer_store.deserialize_project_transaction(
10440 transaction_response,
10441 push_to_history,
10442 cx,
10443 )
10444 })?
10445 .await
10446 })
10447 } else {
10448 zlog::trace!(logger => "Not formatting");
10449 Task::ready(Ok(ProjectTransaction::default()))
10450 }
10451 }
10452
10453 async fn handle_format_buffers(
10454 this: Entity<Self>,
10455 envelope: TypedEnvelope<proto::FormatBuffers>,
10456 mut cx: AsyncApp,
10457 ) -> Result<proto::FormatBuffersResponse> {
10458 let sender_id = envelope.original_sender_id().unwrap_or_default();
10459 let format = this.update(&mut cx, |this, cx| {
10460 let mut buffers = HashSet::default();
10461 for buffer_id in &envelope.payload.buffer_ids {
10462 let buffer_id = BufferId::new(*buffer_id)?;
10463 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10464 }
10465 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10466 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10467 })??;
10468
10469 let project_transaction = format.await?;
10470 let project_transaction = this.update(&mut cx, |this, cx| {
10471 this.buffer_store.update(cx, |buffer_store, cx| {
10472 buffer_store.serialize_project_transaction_for_peer(
10473 project_transaction,
10474 sender_id,
10475 cx,
10476 )
10477 })
10478 })?;
10479 Ok(proto::FormatBuffersResponse {
10480 transaction: Some(project_transaction),
10481 })
10482 }
10483
10484 async fn handle_apply_code_action_kind(
10485 this: Entity<Self>,
10486 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10487 mut cx: AsyncApp,
10488 ) -> Result<proto::ApplyCodeActionKindResponse> {
10489 let sender_id = envelope.original_sender_id().unwrap_or_default();
10490 let format = this.update(&mut cx, |this, cx| {
10491 let mut buffers = HashSet::default();
10492 for buffer_id in &envelope.payload.buffer_ids {
10493 let buffer_id = BufferId::new(*buffer_id)?;
10494 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10495 }
10496 let kind = match envelope.payload.kind.as_str() {
10497 "" => CodeActionKind::EMPTY,
10498 "quickfix" => CodeActionKind::QUICKFIX,
10499 "refactor" => CodeActionKind::REFACTOR,
10500 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10501 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10502 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10503 "source" => CodeActionKind::SOURCE,
10504 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10505 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10506 _ => anyhow::bail!(
10507 "Invalid code action kind {}",
10508 envelope.payload.kind.as_str()
10509 ),
10510 };
10511 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10512 })??;
10513
10514 let project_transaction = format.await?;
10515 let project_transaction = this.update(&mut cx, |this, cx| {
10516 this.buffer_store.update(cx, |buffer_store, cx| {
10517 buffer_store.serialize_project_transaction_for_peer(
10518 project_transaction,
10519 sender_id,
10520 cx,
10521 )
10522 })
10523 })?;
10524 Ok(proto::ApplyCodeActionKindResponse {
10525 transaction: Some(project_transaction),
10526 })
10527 }
10528
10529 async fn shutdown_language_server(
10530 server_state: Option<LanguageServerState>,
10531 name: LanguageServerName,
10532 cx: &mut AsyncApp,
10533 ) {
10534 let server = match server_state {
10535 Some(LanguageServerState::Starting { startup, .. }) => {
10536 let mut timer = cx
10537 .background_executor()
10538 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10539 .fuse();
10540
10541 select! {
10542 server = startup.fuse() => server,
10543 () = timer => {
10544 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10545 None
10546 },
10547 }
10548 }
10549
10550 Some(LanguageServerState::Running { server, .. }) => Some(server),
10551
10552 None => None,
10553 };
10554
10555 if let Some(server) = server
10556 && let Some(shutdown) = server.shutdown()
10557 {
10558 shutdown.await;
10559 }
10560 }
10561
10562 // Returns a list of all of the worktrees which no longer have a language server and the root path
10563 // for the stopped server
10564 fn stop_local_language_server(
10565 &mut self,
10566 server_id: LanguageServerId,
10567 cx: &mut Context<Self>,
10568 ) -> Task<()> {
10569 let local = match &mut self.mode {
10570 LspStoreMode::Local(local) => local,
10571 _ => {
10572 return Task::ready(());
10573 }
10574 };
10575
10576 // Remove this server ID from all entries in the given worktree.
10577 local
10578 .language_server_ids
10579 .retain(|_, state| state.id != server_id);
10580 self.buffer_store.update(cx, |buffer_store, cx| {
10581 for buffer in buffer_store.buffers() {
10582 buffer.update(cx, |buffer, cx| {
10583 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10584 buffer.set_completion_triggers(server_id, Default::default(), cx);
10585 });
10586 }
10587 });
10588
10589 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10590 summaries.retain(|path, summaries_by_server_id| {
10591 if summaries_by_server_id.remove(&server_id).is_some() {
10592 if let Some((client, project_id)) = self.downstream_client.clone() {
10593 client
10594 .send(proto::UpdateDiagnosticSummary {
10595 project_id,
10596 worktree_id: worktree_id.to_proto(),
10597 summary: Some(proto::DiagnosticSummary {
10598 path: path.as_ref().to_proto(),
10599 language_server_id: server_id.0 as u64,
10600 error_count: 0,
10601 warning_count: 0,
10602 }),
10603 more_summaries: Vec::new(),
10604 })
10605 .log_err();
10606 }
10607 !summaries_by_server_id.is_empty()
10608 } else {
10609 true
10610 }
10611 });
10612 }
10613
10614 let local = self.as_local_mut().unwrap();
10615 for diagnostics in local.diagnostics.values_mut() {
10616 diagnostics.retain(|_, diagnostics_by_server_id| {
10617 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10618 diagnostics_by_server_id.remove(ix);
10619 !diagnostics_by_server_id.is_empty()
10620 } else {
10621 true
10622 }
10623 });
10624 }
10625 local.language_server_watched_paths.remove(&server_id);
10626
10627 let server_state = local.language_servers.remove(&server_id);
10628 self.cleanup_lsp_data(server_id);
10629 let name = self
10630 .language_server_statuses
10631 .remove(&server_id)
10632 .map(|status| status.name)
10633 .or_else(|| {
10634 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10635 Some(adapter.name())
10636 } else {
10637 None
10638 }
10639 });
10640
10641 if let Some(name) = name {
10642 log::info!("stopping language server {name}");
10643 self.languages
10644 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10645 cx.notify();
10646
10647 return cx.spawn(async move |lsp_store, cx| {
10648 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10649 lsp_store
10650 .update(cx, |lsp_store, cx| {
10651 lsp_store
10652 .languages
10653 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10654 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10655 cx.notify();
10656 })
10657 .ok();
10658 });
10659 }
10660
10661 if server_state.is_some() {
10662 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10663 }
10664 Task::ready(())
10665 }
10666
10667 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10668 if let Some((client, project_id)) = self.upstream_client() {
10669 let request = client.request(proto::StopLanguageServers {
10670 project_id,
10671 buffer_ids: Vec::new(),
10672 also_servers: Vec::new(),
10673 all: true,
10674 });
10675 cx.background_spawn(request).detach_and_log_err(cx);
10676 } else {
10677 let Some(local) = self.as_local_mut() else {
10678 return;
10679 };
10680 let language_servers_to_stop = local
10681 .language_server_ids
10682 .values()
10683 .map(|state| state.id)
10684 .collect();
10685 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10686 let tasks = language_servers_to_stop
10687 .into_iter()
10688 .map(|server| self.stop_local_language_server(server, cx))
10689 .collect::<Vec<_>>();
10690 cx.background_spawn(async move {
10691 futures::future::join_all(tasks).await;
10692 })
10693 .detach();
10694 }
10695 }
10696
10697 pub fn restart_language_servers_for_buffers(
10698 &mut self,
10699 buffers: Vec<Entity<Buffer>>,
10700 only_restart_servers: HashSet<LanguageServerSelector>,
10701 cx: &mut Context<Self>,
10702 ) {
10703 if let Some((client, project_id)) = self.upstream_client() {
10704 let request = client.request(proto::RestartLanguageServers {
10705 project_id,
10706 buffer_ids: buffers
10707 .into_iter()
10708 .map(|b| b.read(cx).remote_id().to_proto())
10709 .collect(),
10710 only_servers: only_restart_servers
10711 .into_iter()
10712 .map(|selector| {
10713 let selector = match selector {
10714 LanguageServerSelector::Id(language_server_id) => {
10715 proto::language_server_selector::Selector::ServerId(
10716 language_server_id.to_proto(),
10717 )
10718 }
10719 LanguageServerSelector::Name(language_server_name) => {
10720 proto::language_server_selector::Selector::Name(
10721 language_server_name.to_string(),
10722 )
10723 }
10724 };
10725 proto::LanguageServerSelector {
10726 selector: Some(selector),
10727 }
10728 })
10729 .collect(),
10730 all: false,
10731 });
10732 cx.background_spawn(request).detach_and_log_err(cx);
10733 } else {
10734 let stop_task = if only_restart_servers.is_empty() {
10735 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10736 } else {
10737 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10738 };
10739 cx.spawn(async move |lsp_store, cx| {
10740 stop_task.await;
10741 lsp_store
10742 .update(cx, |lsp_store, cx| {
10743 for buffer in buffers {
10744 lsp_store.register_buffer_with_language_servers(
10745 &buffer,
10746 only_restart_servers.clone(),
10747 true,
10748 cx,
10749 );
10750 }
10751 })
10752 .ok()
10753 })
10754 .detach();
10755 }
10756 }
10757
10758 pub fn stop_language_servers_for_buffers(
10759 &mut self,
10760 buffers: Vec<Entity<Buffer>>,
10761 also_stop_servers: HashSet<LanguageServerSelector>,
10762 cx: &mut Context<Self>,
10763 ) -> Task<Result<()>> {
10764 if let Some((client, project_id)) = self.upstream_client() {
10765 let request = client.request(proto::StopLanguageServers {
10766 project_id,
10767 buffer_ids: buffers
10768 .into_iter()
10769 .map(|b| b.read(cx).remote_id().to_proto())
10770 .collect(),
10771 also_servers: also_stop_servers
10772 .into_iter()
10773 .map(|selector| {
10774 let selector = match selector {
10775 LanguageServerSelector::Id(language_server_id) => {
10776 proto::language_server_selector::Selector::ServerId(
10777 language_server_id.to_proto(),
10778 )
10779 }
10780 LanguageServerSelector::Name(language_server_name) => {
10781 proto::language_server_selector::Selector::Name(
10782 language_server_name.to_string(),
10783 )
10784 }
10785 };
10786 proto::LanguageServerSelector {
10787 selector: Some(selector),
10788 }
10789 })
10790 .collect(),
10791 all: false,
10792 });
10793 cx.background_spawn(async move {
10794 let _ = request.await?;
10795 Ok(())
10796 })
10797 } else {
10798 let task =
10799 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10800 cx.background_spawn(async move {
10801 task.await;
10802 Ok(())
10803 })
10804 }
10805 }
10806
10807 fn stop_local_language_servers_for_buffers(
10808 &mut self,
10809 buffers: &[Entity<Buffer>],
10810 also_stop_servers: HashSet<LanguageServerSelector>,
10811 cx: &mut Context<Self>,
10812 ) -> Task<()> {
10813 let Some(local) = self.as_local_mut() else {
10814 return Task::ready(());
10815 };
10816 let mut language_server_names_to_stop = BTreeSet::default();
10817 let mut language_servers_to_stop = also_stop_servers
10818 .into_iter()
10819 .flat_map(|selector| match selector {
10820 LanguageServerSelector::Id(id) => Some(id),
10821 LanguageServerSelector::Name(name) => {
10822 language_server_names_to_stop.insert(name);
10823 None
10824 }
10825 })
10826 .collect::<BTreeSet<_>>();
10827
10828 let mut covered_worktrees = HashSet::default();
10829 for buffer in buffers {
10830 buffer.update(cx, |buffer, cx| {
10831 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10832 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10833 && covered_worktrees.insert(worktree_id)
10834 {
10835 language_server_names_to_stop.retain(|name| {
10836 let old_ids_count = language_servers_to_stop.len();
10837 let all_language_servers_with_this_name = local
10838 .language_server_ids
10839 .iter()
10840 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10841 language_servers_to_stop.extend(all_language_servers_with_this_name);
10842 old_ids_count == language_servers_to_stop.len()
10843 });
10844 }
10845 });
10846 }
10847 for name in language_server_names_to_stop {
10848 language_servers_to_stop.extend(
10849 local
10850 .language_server_ids
10851 .iter()
10852 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10853 );
10854 }
10855
10856 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10857 let tasks = language_servers_to_stop
10858 .into_iter()
10859 .map(|server| self.stop_local_language_server(server, cx))
10860 .collect::<Vec<_>>();
10861
10862 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10863 }
10864
10865 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10866 let (worktree, relative_path) =
10867 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10868
10869 let project_path = ProjectPath {
10870 worktree_id: worktree.read(cx).id(),
10871 path: relative_path,
10872 };
10873
10874 Some(
10875 self.buffer_store()
10876 .read(cx)
10877 .get_by_path(&project_path)?
10878 .read(cx),
10879 )
10880 }
10881
10882 #[cfg(any(test, feature = "test-support"))]
10883 pub fn update_diagnostics(
10884 &mut self,
10885 server_id: LanguageServerId,
10886 diagnostics: lsp::PublishDiagnosticsParams,
10887 result_id: Option<String>,
10888 source_kind: DiagnosticSourceKind,
10889 disk_based_sources: &[String],
10890 cx: &mut Context<Self>,
10891 ) -> Result<()> {
10892 self.merge_lsp_diagnostics(
10893 source_kind,
10894 vec![DocumentDiagnosticsUpdate {
10895 diagnostics,
10896 result_id,
10897 server_id,
10898 disk_based_sources: Cow::Borrowed(disk_based_sources),
10899 }],
10900 |_, _, _| false,
10901 cx,
10902 )
10903 }
10904
10905 pub fn merge_lsp_diagnostics(
10906 &mut self,
10907 source_kind: DiagnosticSourceKind,
10908 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10909 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10910 cx: &mut Context<Self>,
10911 ) -> Result<()> {
10912 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10913 let updates = lsp_diagnostics
10914 .into_iter()
10915 .filter_map(|update| {
10916 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10917 Some(DocumentDiagnosticsUpdate {
10918 diagnostics: self.lsp_to_document_diagnostics(
10919 abs_path,
10920 source_kind,
10921 update.server_id,
10922 update.diagnostics,
10923 &update.disk_based_sources,
10924 ),
10925 result_id: update.result_id,
10926 server_id: update.server_id,
10927 disk_based_sources: update.disk_based_sources,
10928 })
10929 })
10930 .collect();
10931 self.merge_diagnostic_entries(updates, merge, cx)?;
10932 Ok(())
10933 }
10934
10935 fn lsp_to_document_diagnostics(
10936 &mut self,
10937 document_abs_path: PathBuf,
10938 source_kind: DiagnosticSourceKind,
10939 server_id: LanguageServerId,
10940 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10941 disk_based_sources: &[String],
10942 ) -> DocumentDiagnostics {
10943 let mut diagnostics = Vec::default();
10944 let mut primary_diagnostic_group_ids = HashMap::default();
10945 let mut sources_by_group_id = HashMap::default();
10946 let mut supporting_diagnostics = HashMap::default();
10947
10948 let adapter = self.language_server_adapter_for_id(server_id);
10949
10950 // Ensure that primary diagnostics are always the most severe
10951 lsp_diagnostics
10952 .diagnostics
10953 .sort_by_key(|item| item.severity);
10954
10955 for diagnostic in &lsp_diagnostics.diagnostics {
10956 let source = diagnostic.source.as_ref();
10957 let range = range_from_lsp(diagnostic.range);
10958 let is_supporting = diagnostic
10959 .related_information
10960 .as_ref()
10961 .is_some_and(|infos| {
10962 infos.iter().any(|info| {
10963 primary_diagnostic_group_ids.contains_key(&(
10964 source,
10965 diagnostic.code.clone(),
10966 range_from_lsp(info.location.range),
10967 ))
10968 })
10969 });
10970
10971 let is_unnecessary = diagnostic
10972 .tags
10973 .as_ref()
10974 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10975
10976 let underline = self
10977 .language_server_adapter_for_id(server_id)
10978 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10979
10980 if is_supporting {
10981 supporting_diagnostics.insert(
10982 (source, diagnostic.code.clone(), range),
10983 (diagnostic.severity, is_unnecessary),
10984 );
10985 } else {
10986 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10987 let is_disk_based =
10988 source.is_some_and(|source| disk_based_sources.contains(source));
10989
10990 sources_by_group_id.insert(group_id, source);
10991 primary_diagnostic_group_ids
10992 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10993
10994 diagnostics.push(DiagnosticEntry {
10995 range,
10996 diagnostic: Diagnostic {
10997 source: diagnostic.source.clone(),
10998 source_kind,
10999 code: diagnostic.code.clone(),
11000 code_description: diagnostic
11001 .code_description
11002 .as_ref()
11003 .and_then(|d| d.href.clone()),
11004 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11005 markdown: adapter.as_ref().and_then(|adapter| {
11006 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11007 }),
11008 message: diagnostic.message.trim().to_string(),
11009 group_id,
11010 is_primary: true,
11011 is_disk_based,
11012 is_unnecessary,
11013 underline,
11014 data: diagnostic.data.clone(),
11015 },
11016 });
11017 if let Some(infos) = &diagnostic.related_information {
11018 for info in infos {
11019 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11020 let range = range_from_lsp(info.location.range);
11021 diagnostics.push(DiagnosticEntry {
11022 range,
11023 diagnostic: Diagnostic {
11024 source: diagnostic.source.clone(),
11025 source_kind,
11026 code: diagnostic.code.clone(),
11027 code_description: diagnostic
11028 .code_description
11029 .as_ref()
11030 .and_then(|d| d.href.clone()),
11031 severity: DiagnosticSeverity::INFORMATION,
11032 markdown: adapter.as_ref().and_then(|adapter| {
11033 adapter.diagnostic_message_to_markdown(&info.message)
11034 }),
11035 message: info.message.trim().to_string(),
11036 group_id,
11037 is_primary: false,
11038 is_disk_based,
11039 is_unnecessary: false,
11040 underline,
11041 data: diagnostic.data.clone(),
11042 },
11043 });
11044 }
11045 }
11046 }
11047 }
11048 }
11049
11050 for entry in &mut diagnostics {
11051 let diagnostic = &mut entry.diagnostic;
11052 if !diagnostic.is_primary {
11053 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11054 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11055 source,
11056 diagnostic.code.clone(),
11057 entry.range.clone(),
11058 )) {
11059 if let Some(severity) = severity {
11060 diagnostic.severity = severity;
11061 }
11062 diagnostic.is_unnecessary = is_unnecessary;
11063 }
11064 }
11065 }
11066
11067 DocumentDiagnostics {
11068 diagnostics,
11069 document_abs_path,
11070 version: lsp_diagnostics.version,
11071 }
11072 }
11073
11074 fn insert_newly_running_language_server(
11075 &mut self,
11076 adapter: Arc<CachedLspAdapter>,
11077 language_server: Arc<LanguageServer>,
11078 server_id: LanguageServerId,
11079 key: LanguageServerSeed,
11080 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11081 cx: &mut Context<Self>,
11082 ) {
11083 let Some(local) = self.as_local_mut() else {
11084 return;
11085 };
11086 // If the language server for this key doesn't match the server id, don't store the
11087 // server. Which will cause it to be dropped, killing the process
11088 if local
11089 .language_server_ids
11090 .get(&key)
11091 .map(|state| state.id != server_id)
11092 .unwrap_or(false)
11093 {
11094 return;
11095 }
11096
11097 // Update language_servers collection with Running variant of LanguageServerState
11098 // indicating that the server is up and running and ready
11099 let workspace_folders = workspace_folders.lock().clone();
11100 language_server.set_workspace_folders(workspace_folders);
11101
11102 let workspace_diagnostics_refresh_tasks = language_server
11103 .capabilities()
11104 .diagnostic_provider
11105 .and_then(|provider| {
11106 local
11107 .language_server_dynamic_registrations
11108 .entry(server_id)
11109 .or_default()
11110 .diagnostics
11111 .entry(None)
11112 .or_insert(provider.clone());
11113 let workspace_refresher =
11114 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11115
11116 Some((None, workspace_refresher))
11117 })
11118 .into_iter()
11119 .collect();
11120 local.language_servers.insert(
11121 server_id,
11122 LanguageServerState::Running {
11123 workspace_diagnostics_refresh_tasks,
11124 adapter: adapter.clone(),
11125 server: language_server.clone(),
11126 simulate_disk_based_diagnostics_completion: None,
11127 },
11128 );
11129 local
11130 .languages
11131 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11132 if let Some(file_ops_caps) = language_server
11133 .capabilities()
11134 .workspace
11135 .as_ref()
11136 .and_then(|ws| ws.file_operations.as_ref())
11137 {
11138 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11139 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11140 if did_rename_caps.or(will_rename_caps).is_some() {
11141 let watcher = RenamePathsWatchedForServer::default()
11142 .with_did_rename_patterns(did_rename_caps)
11143 .with_will_rename_patterns(will_rename_caps);
11144 local
11145 .language_server_paths_watched_for_rename
11146 .insert(server_id, watcher);
11147 }
11148 }
11149
11150 self.language_server_statuses.insert(
11151 server_id,
11152 LanguageServerStatus {
11153 name: language_server.name(),
11154 pending_work: Default::default(),
11155 has_pending_diagnostic_updates: false,
11156 progress_tokens: Default::default(),
11157 worktree: Some(key.worktree_id),
11158 },
11159 );
11160
11161 cx.emit(LspStoreEvent::LanguageServerAdded(
11162 server_id,
11163 language_server.name(),
11164 Some(key.worktree_id),
11165 ));
11166
11167 let server_capabilities = language_server.capabilities();
11168 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11169 downstream_client
11170 .send(proto::StartLanguageServer {
11171 project_id: *project_id,
11172 server: Some(proto::LanguageServer {
11173 id: server_id.to_proto(),
11174 name: language_server.name().to_string(),
11175 worktree_id: Some(key.worktree_id.to_proto()),
11176 }),
11177 capabilities: serde_json::to_string(&server_capabilities)
11178 .expect("serializing server LSP capabilities"),
11179 })
11180 .log_err();
11181 }
11182 self.lsp_server_capabilities
11183 .insert(server_id, server_capabilities);
11184
11185 // Tell the language server about every open buffer in the worktree that matches the language.
11186 // Also check for buffers in worktrees that reused this server
11187 let mut worktrees_using_server = vec![key.worktree_id];
11188 if let Some(local) = self.as_local() {
11189 // Find all worktrees that have this server in their language server tree
11190 for (worktree_id, servers) in &local.lsp_tree.instances {
11191 if *worktree_id != key.worktree_id {
11192 for server_map in servers.roots.values() {
11193 if server_map
11194 .values()
11195 .any(|(node, _)| node.id() == Some(server_id))
11196 {
11197 worktrees_using_server.push(*worktree_id);
11198 }
11199 }
11200 }
11201 }
11202 }
11203
11204 let mut buffer_paths_registered = Vec::new();
11205 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11206 let mut lsp_adapters = HashMap::default();
11207 for buffer_handle in buffer_store.buffers() {
11208 let buffer = buffer_handle.read(cx);
11209 let file = match File::from_dyn(buffer.file()) {
11210 Some(file) => file,
11211 None => continue,
11212 };
11213 let language = match buffer.language() {
11214 Some(language) => language,
11215 None => continue,
11216 };
11217
11218 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11219 || !lsp_adapters
11220 .entry(language.name())
11221 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11222 .iter()
11223 .any(|a| a.name == key.name)
11224 {
11225 continue;
11226 }
11227 // didOpen
11228 let file = match file.as_local() {
11229 Some(file) => file,
11230 None => continue,
11231 };
11232
11233 let local = self.as_local_mut().unwrap();
11234
11235 let buffer_id = buffer.remote_id();
11236 if local.registered_buffers.contains_key(&buffer_id) {
11237 let versions = local
11238 .buffer_snapshots
11239 .entry(buffer_id)
11240 .or_default()
11241 .entry(server_id)
11242 .and_modify(|_| {
11243 assert!(
11244 false,
11245 "There should not be an existing snapshot for a newly inserted buffer"
11246 )
11247 })
11248 .or_insert_with(|| {
11249 vec![LspBufferSnapshot {
11250 version: 0,
11251 snapshot: buffer.text_snapshot(),
11252 }]
11253 });
11254
11255 let snapshot = versions.last().unwrap();
11256 let version = snapshot.version;
11257 let initial_snapshot = &snapshot.snapshot;
11258 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11259 language_server.register_buffer(
11260 uri,
11261 adapter.language_id(&language.name()),
11262 version,
11263 initial_snapshot.text(),
11264 );
11265 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11266 local
11267 .buffers_opened_in_servers
11268 .entry(buffer_id)
11269 .or_default()
11270 .insert(server_id);
11271 }
11272 buffer_handle.update(cx, |buffer, cx| {
11273 buffer.set_completion_triggers(
11274 server_id,
11275 language_server
11276 .capabilities()
11277 .completion_provider
11278 .as_ref()
11279 .and_then(|provider| {
11280 provider
11281 .trigger_characters
11282 .as_ref()
11283 .map(|characters| characters.iter().cloned().collect())
11284 })
11285 .unwrap_or_default(),
11286 cx,
11287 )
11288 });
11289 }
11290 });
11291
11292 for (buffer_id, abs_path) in buffer_paths_registered {
11293 cx.emit(LspStoreEvent::LanguageServerUpdate {
11294 language_server_id: server_id,
11295 name: Some(adapter.name()),
11296 message: proto::update_language_server::Variant::RegisteredForBuffer(
11297 proto::RegisteredForBuffer {
11298 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11299 buffer_id: buffer_id.to_proto(),
11300 },
11301 ),
11302 });
11303 }
11304
11305 cx.notify();
11306 }
11307
11308 pub fn language_servers_running_disk_based_diagnostics(
11309 &self,
11310 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11311 self.language_server_statuses
11312 .iter()
11313 .filter_map(|(id, status)| {
11314 if status.has_pending_diagnostic_updates {
11315 Some(*id)
11316 } else {
11317 None
11318 }
11319 })
11320 }
11321
11322 pub(crate) fn cancel_language_server_work_for_buffers(
11323 &mut self,
11324 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11325 cx: &mut Context<Self>,
11326 ) {
11327 if let Some((client, project_id)) = self.upstream_client() {
11328 let request = client.request(proto::CancelLanguageServerWork {
11329 project_id,
11330 work: Some(proto::cancel_language_server_work::Work::Buffers(
11331 proto::cancel_language_server_work::Buffers {
11332 buffer_ids: buffers
11333 .into_iter()
11334 .map(|b| b.read(cx).remote_id().to_proto())
11335 .collect(),
11336 },
11337 )),
11338 });
11339 cx.background_spawn(request).detach_and_log_err(cx);
11340 } else if let Some(local) = self.as_local() {
11341 let servers = buffers
11342 .into_iter()
11343 .flat_map(|buffer| {
11344 buffer.update(cx, |buffer, cx| {
11345 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11346 })
11347 })
11348 .collect::<HashSet<_>>();
11349 for server_id in servers {
11350 self.cancel_language_server_work(server_id, None, cx);
11351 }
11352 }
11353 }
11354
11355 pub(crate) fn cancel_language_server_work(
11356 &mut self,
11357 server_id: LanguageServerId,
11358 token_to_cancel: Option<ProgressToken>,
11359 cx: &mut Context<Self>,
11360 ) {
11361 if let Some(local) = self.as_local() {
11362 let status = self.language_server_statuses.get(&server_id);
11363 let server = local.language_servers.get(&server_id);
11364 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11365 {
11366 for (token, progress) in &status.pending_work {
11367 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11368 && token != token_to_cancel
11369 {
11370 continue;
11371 }
11372 if progress.is_cancellable {
11373 server
11374 .notify::<lsp::notification::WorkDoneProgressCancel>(
11375 WorkDoneProgressCancelParams {
11376 token: token.to_lsp(),
11377 },
11378 )
11379 .ok();
11380 }
11381 }
11382 }
11383 } else if let Some((client, project_id)) = self.upstream_client() {
11384 let request = client.request(proto::CancelLanguageServerWork {
11385 project_id,
11386 work: Some(
11387 proto::cancel_language_server_work::Work::LanguageServerWork(
11388 proto::cancel_language_server_work::LanguageServerWork {
11389 language_server_id: server_id.to_proto(),
11390 token: token_to_cancel.map(|token| token.to_proto()),
11391 },
11392 ),
11393 ),
11394 });
11395 cx.background_spawn(request).detach_and_log_err(cx);
11396 }
11397 }
11398
11399 fn register_supplementary_language_server(
11400 &mut self,
11401 id: LanguageServerId,
11402 name: LanguageServerName,
11403 server: Arc<LanguageServer>,
11404 cx: &mut Context<Self>,
11405 ) {
11406 if let Some(local) = self.as_local_mut() {
11407 local
11408 .supplementary_language_servers
11409 .insert(id, (name.clone(), server));
11410 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11411 }
11412 }
11413
11414 fn unregister_supplementary_language_server(
11415 &mut self,
11416 id: LanguageServerId,
11417 cx: &mut Context<Self>,
11418 ) {
11419 if let Some(local) = self.as_local_mut() {
11420 local.supplementary_language_servers.remove(&id);
11421 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11422 }
11423 }
11424
11425 pub(crate) fn supplementary_language_servers(
11426 &self,
11427 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11428 self.as_local().into_iter().flat_map(|local| {
11429 local
11430 .supplementary_language_servers
11431 .iter()
11432 .map(|(id, (name, _))| (*id, name.clone()))
11433 })
11434 }
11435
11436 pub fn language_server_adapter_for_id(
11437 &self,
11438 id: LanguageServerId,
11439 ) -> Option<Arc<CachedLspAdapter>> {
11440 self.as_local()
11441 .and_then(|local| local.language_servers.get(&id))
11442 .and_then(|language_server_state| match language_server_state {
11443 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11444 _ => None,
11445 })
11446 }
11447
11448 pub(super) fn update_local_worktree_language_servers(
11449 &mut self,
11450 worktree_handle: &Entity<Worktree>,
11451 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11452 cx: &mut Context<Self>,
11453 ) {
11454 if changes.is_empty() {
11455 return;
11456 }
11457
11458 let Some(local) = self.as_local() else { return };
11459
11460 local.prettier_store.update(cx, |prettier_store, cx| {
11461 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11462 });
11463
11464 let worktree_id = worktree_handle.read(cx).id();
11465 let mut language_server_ids = local
11466 .language_server_ids
11467 .iter()
11468 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11469 .collect::<Vec<_>>();
11470 language_server_ids.sort();
11471 language_server_ids.dedup();
11472
11473 // let abs_path = worktree_handle.read(cx).abs_path();
11474 for server_id in &language_server_ids {
11475 if let Some(LanguageServerState::Running { server, .. }) =
11476 local.language_servers.get(server_id)
11477 && let Some(watched_paths) = local
11478 .language_server_watched_paths
11479 .get(server_id)
11480 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11481 {
11482 let params = lsp::DidChangeWatchedFilesParams {
11483 changes: changes
11484 .iter()
11485 .filter_map(|(path, _, change)| {
11486 if !watched_paths.is_match(path.as_std_path()) {
11487 return None;
11488 }
11489 let typ = match change {
11490 PathChange::Loaded => return None,
11491 PathChange::Added => lsp::FileChangeType::CREATED,
11492 PathChange::Removed => lsp::FileChangeType::DELETED,
11493 PathChange::Updated => lsp::FileChangeType::CHANGED,
11494 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11495 };
11496 let uri = lsp::Uri::from_file_path(
11497 worktree_handle.read(cx).absolutize(&path),
11498 )
11499 .ok()?;
11500 Some(lsp::FileEvent { uri, typ })
11501 })
11502 .collect(),
11503 };
11504 if !params.changes.is_empty() {
11505 server
11506 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11507 .ok();
11508 }
11509 }
11510 }
11511 for (path, _, _) in changes {
11512 if let Some(file_name) = path.file_name()
11513 && local.watched_manifest_filenames.contains(file_name)
11514 {
11515 self.request_workspace_config_refresh();
11516 break;
11517 }
11518 }
11519 }
11520
11521 pub fn wait_for_remote_buffer(
11522 &mut self,
11523 id: BufferId,
11524 cx: &mut Context<Self>,
11525 ) -> Task<Result<Entity<Buffer>>> {
11526 self.buffer_store.update(cx, |buffer_store, cx| {
11527 buffer_store.wait_for_remote_buffer(id, cx)
11528 })
11529 }
11530
11531 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11532 let mut result = proto::Symbol {
11533 language_server_name: symbol.language_server_name.0.to_string(),
11534 source_worktree_id: symbol.source_worktree_id.to_proto(),
11535 language_server_id: symbol.source_language_server_id.to_proto(),
11536 name: symbol.name.clone(),
11537 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11538 start: Some(proto::PointUtf16 {
11539 row: symbol.range.start.0.row,
11540 column: symbol.range.start.0.column,
11541 }),
11542 end: Some(proto::PointUtf16 {
11543 row: symbol.range.end.0.row,
11544 column: symbol.range.end.0.column,
11545 }),
11546 worktree_id: Default::default(),
11547 path: Default::default(),
11548 signature: Default::default(),
11549 };
11550 match &symbol.path {
11551 SymbolLocation::InProject(path) => {
11552 result.worktree_id = path.worktree_id.to_proto();
11553 result.path = path.path.to_proto();
11554 }
11555 SymbolLocation::OutsideProject {
11556 abs_path,
11557 signature,
11558 } => {
11559 result.path = abs_path.to_string_lossy().into_owned();
11560 result.signature = signature.to_vec();
11561 }
11562 }
11563 result
11564 }
11565
11566 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11567 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11568 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11569 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11570
11571 let path = if serialized_symbol.signature.is_empty() {
11572 SymbolLocation::InProject(ProjectPath {
11573 worktree_id,
11574 path: RelPath::from_proto(&serialized_symbol.path)
11575 .context("invalid symbol path")?,
11576 })
11577 } else {
11578 SymbolLocation::OutsideProject {
11579 abs_path: Path::new(&serialized_symbol.path).into(),
11580 signature: serialized_symbol
11581 .signature
11582 .try_into()
11583 .map_err(|_| anyhow!("invalid signature"))?,
11584 }
11585 };
11586
11587 let start = serialized_symbol.start.context("invalid start")?;
11588 let end = serialized_symbol.end.context("invalid end")?;
11589 Ok(CoreSymbol {
11590 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11591 source_worktree_id,
11592 source_language_server_id: LanguageServerId::from_proto(
11593 serialized_symbol.language_server_id,
11594 ),
11595 path,
11596 name: serialized_symbol.name,
11597 range: Unclipped(PointUtf16::new(start.row, start.column))
11598 ..Unclipped(PointUtf16::new(end.row, end.column)),
11599 kind,
11600 })
11601 }
11602
11603 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11604 let mut serialized_completion = proto::Completion {
11605 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11606 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11607 new_text: completion.new_text.clone(),
11608 ..proto::Completion::default()
11609 };
11610 match &completion.source {
11611 CompletionSource::Lsp {
11612 insert_range,
11613 server_id,
11614 lsp_completion,
11615 lsp_defaults,
11616 resolved,
11617 } => {
11618 let (old_insert_start, old_insert_end) = insert_range
11619 .as_ref()
11620 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11621 .unzip();
11622
11623 serialized_completion.old_insert_start = old_insert_start;
11624 serialized_completion.old_insert_end = old_insert_end;
11625 serialized_completion.source = proto::completion::Source::Lsp as i32;
11626 serialized_completion.server_id = server_id.0 as u64;
11627 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11628 serialized_completion.lsp_defaults = lsp_defaults
11629 .as_deref()
11630 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11631 serialized_completion.resolved = *resolved;
11632 }
11633 CompletionSource::BufferWord {
11634 word_range,
11635 resolved,
11636 } => {
11637 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11638 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11639 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11640 serialized_completion.resolved = *resolved;
11641 }
11642 CompletionSource::Custom => {
11643 serialized_completion.source = proto::completion::Source::Custom as i32;
11644 serialized_completion.resolved = true;
11645 }
11646 CompletionSource::Dap { sort_text } => {
11647 serialized_completion.source = proto::completion::Source::Dap as i32;
11648 serialized_completion.sort_text = Some(sort_text.clone());
11649 }
11650 }
11651
11652 serialized_completion
11653 }
11654
11655 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11656 let old_replace_start = completion
11657 .old_replace_start
11658 .and_then(deserialize_anchor)
11659 .context("invalid old start")?;
11660 let old_replace_end = completion
11661 .old_replace_end
11662 .and_then(deserialize_anchor)
11663 .context("invalid old end")?;
11664 let insert_range = {
11665 match completion.old_insert_start.zip(completion.old_insert_end) {
11666 Some((start, end)) => {
11667 let start = deserialize_anchor(start).context("invalid insert old start")?;
11668 let end = deserialize_anchor(end).context("invalid insert old end")?;
11669 Some(start..end)
11670 }
11671 None => None,
11672 }
11673 };
11674 Ok(CoreCompletion {
11675 replace_range: old_replace_start..old_replace_end,
11676 new_text: completion.new_text,
11677 source: match proto::completion::Source::from_i32(completion.source) {
11678 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11679 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11680 insert_range,
11681 server_id: LanguageServerId::from_proto(completion.server_id),
11682 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11683 lsp_defaults: completion
11684 .lsp_defaults
11685 .as_deref()
11686 .map(serde_json::from_slice)
11687 .transpose()?,
11688 resolved: completion.resolved,
11689 },
11690 Some(proto::completion::Source::BufferWord) => {
11691 let word_range = completion
11692 .buffer_word_start
11693 .and_then(deserialize_anchor)
11694 .context("invalid buffer word start")?
11695 ..completion
11696 .buffer_word_end
11697 .and_then(deserialize_anchor)
11698 .context("invalid buffer word end")?;
11699 CompletionSource::BufferWord {
11700 word_range,
11701 resolved: completion.resolved,
11702 }
11703 }
11704 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11705 sort_text: completion
11706 .sort_text
11707 .context("expected sort text to exist")?,
11708 },
11709 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11710 },
11711 })
11712 }
11713
11714 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11715 let (kind, lsp_action) = match &action.lsp_action {
11716 LspAction::Action(code_action) => (
11717 proto::code_action::Kind::Action as i32,
11718 serde_json::to_vec(code_action).unwrap(),
11719 ),
11720 LspAction::Command(command) => (
11721 proto::code_action::Kind::Command as i32,
11722 serde_json::to_vec(command).unwrap(),
11723 ),
11724 LspAction::CodeLens(code_lens) => (
11725 proto::code_action::Kind::CodeLens as i32,
11726 serde_json::to_vec(code_lens).unwrap(),
11727 ),
11728 };
11729
11730 proto::CodeAction {
11731 server_id: action.server_id.0 as u64,
11732 start: Some(serialize_anchor(&action.range.start)),
11733 end: Some(serialize_anchor(&action.range.end)),
11734 lsp_action,
11735 kind,
11736 resolved: action.resolved,
11737 }
11738 }
11739
11740 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11741 let start = action
11742 .start
11743 .and_then(deserialize_anchor)
11744 .context("invalid start")?;
11745 let end = action
11746 .end
11747 .and_then(deserialize_anchor)
11748 .context("invalid end")?;
11749 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11750 Some(proto::code_action::Kind::Action) => {
11751 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11752 }
11753 Some(proto::code_action::Kind::Command) => {
11754 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11755 }
11756 Some(proto::code_action::Kind::CodeLens) => {
11757 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11758 }
11759 None => anyhow::bail!("Unknown action kind {}", action.kind),
11760 };
11761 Ok(CodeAction {
11762 server_id: LanguageServerId(action.server_id as usize),
11763 range: start..end,
11764 resolved: action.resolved,
11765 lsp_action,
11766 })
11767 }
11768
11769 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11770 match &formatting_result {
11771 Ok(_) => self.last_formatting_failure = None,
11772 Err(error) => {
11773 let error_string = format!("{error:#}");
11774 log::error!("Formatting failed: {error_string}");
11775 self.last_formatting_failure
11776 .replace(error_string.lines().join(" "));
11777 }
11778 }
11779 }
11780
11781 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11782 self.lsp_server_capabilities.remove(&for_server);
11783 for lsp_data in self.lsp_data.values_mut() {
11784 lsp_data.remove_server_data(for_server);
11785 }
11786 if let Some(local) = self.as_local_mut() {
11787 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11788 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11789 buffer_servers.remove(&for_server);
11790 }
11791 }
11792 }
11793
11794 pub fn result_id(
11795 &self,
11796 server_id: LanguageServerId,
11797 buffer_id: BufferId,
11798 cx: &App,
11799 ) -> Option<String> {
11800 let abs_path = self
11801 .buffer_store
11802 .read(cx)
11803 .get(buffer_id)
11804 .and_then(|b| File::from_dyn(b.read(cx).file()))
11805 .map(|f| f.abs_path(cx))?;
11806 self.as_local()?
11807 .buffer_pull_diagnostics_result_ids
11808 .get(&server_id)?
11809 .get(&abs_path)?
11810 .clone()
11811 }
11812
11813 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11814 let Some(local) = self.as_local() else {
11815 return HashMap::default();
11816 };
11817 local
11818 .buffer_pull_diagnostics_result_ids
11819 .get(&server_id)
11820 .into_iter()
11821 .flatten()
11822 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11823 .collect()
11824 }
11825
11826 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11827 if let Some(LanguageServerState::Running {
11828 workspace_diagnostics_refresh_tasks,
11829 ..
11830 }) = self
11831 .as_local_mut()
11832 .and_then(|local| local.language_servers.get_mut(&server_id))
11833 {
11834 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11835 diagnostics.refresh_tx.try_send(()).ok();
11836 }
11837 }
11838 }
11839
11840 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11841 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11842 return;
11843 };
11844 let Some(local) = self.as_local_mut() else {
11845 return;
11846 };
11847
11848 for server_id in buffer.update(cx, |buffer, cx| {
11849 local.language_server_ids_for_buffer(buffer, cx)
11850 }) {
11851 if let Some(LanguageServerState::Running {
11852 workspace_diagnostics_refresh_tasks,
11853 ..
11854 }) = local.language_servers.get_mut(&server_id)
11855 {
11856 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11857 diagnostics.refresh_tx.try_send(()).ok();
11858 }
11859 }
11860 }
11861 }
11862
11863 fn apply_workspace_diagnostic_report(
11864 &mut self,
11865 server_id: LanguageServerId,
11866 report: lsp::WorkspaceDiagnosticReportResult,
11867 cx: &mut Context<Self>,
11868 ) {
11869 let workspace_diagnostics =
11870 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11871 let mut unchanged_buffers = HashSet::default();
11872 let mut changed_buffers = HashSet::default();
11873 let workspace_diagnostics_updates = workspace_diagnostics
11874 .into_iter()
11875 .filter_map(
11876 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11877 LspPullDiagnostics::Response {
11878 server_id,
11879 uri,
11880 diagnostics,
11881 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11882 LspPullDiagnostics::Default => None,
11883 },
11884 )
11885 .fold(
11886 HashMap::default(),
11887 |mut acc, (server_id, uri, diagnostics, version)| {
11888 let (result_id, diagnostics) = match diagnostics {
11889 PulledDiagnostics::Unchanged { result_id } => {
11890 unchanged_buffers.insert(uri.clone());
11891 (Some(result_id), Vec::new())
11892 }
11893 PulledDiagnostics::Changed {
11894 result_id,
11895 diagnostics,
11896 } => {
11897 changed_buffers.insert(uri.clone());
11898 (result_id, diagnostics)
11899 }
11900 };
11901 let disk_based_sources = Cow::Owned(
11902 self.language_server_adapter_for_id(server_id)
11903 .as_ref()
11904 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11905 .unwrap_or(&[])
11906 .to_vec(),
11907 );
11908 acc.entry(server_id)
11909 .or_insert_with(Vec::new)
11910 .push(DocumentDiagnosticsUpdate {
11911 server_id,
11912 diagnostics: lsp::PublishDiagnosticsParams {
11913 uri,
11914 diagnostics,
11915 version,
11916 },
11917 result_id,
11918 disk_based_sources,
11919 });
11920 acc
11921 },
11922 );
11923
11924 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11925 self.merge_lsp_diagnostics(
11926 DiagnosticSourceKind::Pulled,
11927 diagnostic_updates,
11928 |buffer, old_diagnostic, cx| {
11929 File::from_dyn(buffer.file())
11930 .and_then(|file| {
11931 let abs_path = file.as_local()?.abs_path(cx);
11932 lsp::Uri::from_file_path(abs_path).ok()
11933 })
11934 .is_none_or(|buffer_uri| {
11935 unchanged_buffers.contains(&buffer_uri)
11936 || match old_diagnostic.source_kind {
11937 DiagnosticSourceKind::Pulled => {
11938 !changed_buffers.contains(&buffer_uri)
11939 }
11940 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11941 true
11942 }
11943 }
11944 })
11945 },
11946 cx,
11947 )
11948 .log_err();
11949 }
11950 }
11951
11952 fn register_server_capabilities(
11953 &mut self,
11954 server_id: LanguageServerId,
11955 params: lsp::RegistrationParams,
11956 cx: &mut Context<Self>,
11957 ) -> anyhow::Result<()> {
11958 let server = self
11959 .language_server_for_id(server_id)
11960 .with_context(|| format!("no server {server_id} found"))?;
11961 for reg in params.registrations {
11962 match reg.method.as_str() {
11963 "workspace/didChangeWatchedFiles" => {
11964 if let Some(options) = reg.register_options {
11965 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11966 let caps = serde_json::from_value(options)?;
11967 local_lsp_store
11968 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11969 true
11970 } else {
11971 false
11972 };
11973 if notify {
11974 notify_server_capabilities_updated(&server, cx);
11975 }
11976 }
11977 }
11978 "workspace/didChangeConfiguration" => {
11979 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11980 }
11981 "workspace/didChangeWorkspaceFolders" => {
11982 // In this case register options is an empty object, we can ignore it
11983 let caps = lsp::WorkspaceFoldersServerCapabilities {
11984 supported: Some(true),
11985 change_notifications: Some(OneOf::Right(reg.id)),
11986 };
11987 server.update_capabilities(|capabilities| {
11988 capabilities
11989 .workspace
11990 .get_or_insert_default()
11991 .workspace_folders = Some(caps);
11992 });
11993 notify_server_capabilities_updated(&server, cx);
11994 }
11995 "workspace/symbol" => {
11996 let options = parse_register_capabilities(reg)?;
11997 server.update_capabilities(|capabilities| {
11998 capabilities.workspace_symbol_provider = Some(options);
11999 });
12000 notify_server_capabilities_updated(&server, cx);
12001 }
12002 "workspace/fileOperations" => {
12003 if let Some(options) = reg.register_options {
12004 let caps = serde_json::from_value(options)?;
12005 server.update_capabilities(|capabilities| {
12006 capabilities
12007 .workspace
12008 .get_or_insert_default()
12009 .file_operations = Some(caps);
12010 });
12011 notify_server_capabilities_updated(&server, cx);
12012 }
12013 }
12014 "workspace/executeCommand" => {
12015 if let Some(options) = reg.register_options {
12016 let options = serde_json::from_value(options)?;
12017 server.update_capabilities(|capabilities| {
12018 capabilities.execute_command_provider = Some(options);
12019 });
12020 notify_server_capabilities_updated(&server, cx);
12021 }
12022 }
12023 "textDocument/rangeFormatting" => {
12024 let options = parse_register_capabilities(reg)?;
12025 server.update_capabilities(|capabilities| {
12026 capabilities.document_range_formatting_provider = Some(options);
12027 });
12028 notify_server_capabilities_updated(&server, cx);
12029 }
12030 "textDocument/onTypeFormatting" => {
12031 if let Some(options) = reg
12032 .register_options
12033 .map(serde_json::from_value)
12034 .transpose()?
12035 {
12036 server.update_capabilities(|capabilities| {
12037 capabilities.document_on_type_formatting_provider = Some(options);
12038 });
12039 notify_server_capabilities_updated(&server, cx);
12040 }
12041 }
12042 "textDocument/formatting" => {
12043 let options = parse_register_capabilities(reg)?;
12044 server.update_capabilities(|capabilities| {
12045 capabilities.document_formatting_provider = Some(options);
12046 });
12047 notify_server_capabilities_updated(&server, cx);
12048 }
12049 "textDocument/rename" => {
12050 let options = parse_register_capabilities(reg)?;
12051 server.update_capabilities(|capabilities| {
12052 capabilities.rename_provider = Some(options);
12053 });
12054 notify_server_capabilities_updated(&server, cx);
12055 }
12056 "textDocument/inlayHint" => {
12057 let options = parse_register_capabilities(reg)?;
12058 server.update_capabilities(|capabilities| {
12059 capabilities.inlay_hint_provider = Some(options);
12060 });
12061 notify_server_capabilities_updated(&server, cx);
12062 }
12063 "textDocument/documentSymbol" => {
12064 let options = parse_register_capabilities(reg)?;
12065 server.update_capabilities(|capabilities| {
12066 capabilities.document_symbol_provider = Some(options);
12067 });
12068 notify_server_capabilities_updated(&server, cx);
12069 }
12070 "textDocument/codeAction" => {
12071 let options = parse_register_capabilities(reg)?;
12072 let provider = match options {
12073 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12074 OneOf::Right(caps) => caps,
12075 };
12076 server.update_capabilities(|capabilities| {
12077 capabilities.code_action_provider = Some(provider);
12078 });
12079 notify_server_capabilities_updated(&server, cx);
12080 }
12081 "textDocument/definition" => {
12082 let options = parse_register_capabilities(reg)?;
12083 server.update_capabilities(|capabilities| {
12084 capabilities.definition_provider = Some(options);
12085 });
12086 notify_server_capabilities_updated(&server, cx);
12087 }
12088 "textDocument/completion" => {
12089 if let Some(caps) = reg
12090 .register_options
12091 .map(serde_json::from_value::<CompletionOptions>)
12092 .transpose()?
12093 {
12094 server.update_capabilities(|capabilities| {
12095 capabilities.completion_provider = Some(caps.clone());
12096 });
12097
12098 if let Some(local) = self.as_local() {
12099 let mut buffers_with_language_server = Vec::new();
12100 for handle in self.buffer_store.read(cx).buffers() {
12101 let buffer_id = handle.read(cx).remote_id();
12102 if local
12103 .buffers_opened_in_servers
12104 .get(&buffer_id)
12105 .filter(|s| s.contains(&server_id))
12106 .is_some()
12107 {
12108 buffers_with_language_server.push(handle);
12109 }
12110 }
12111 let triggers = caps
12112 .trigger_characters
12113 .unwrap_or_default()
12114 .into_iter()
12115 .collect::<BTreeSet<_>>();
12116 for handle in buffers_with_language_server {
12117 let triggers = triggers.clone();
12118 let _ = handle.update(cx, move |buffer, cx| {
12119 buffer.set_completion_triggers(server_id, triggers, cx);
12120 });
12121 }
12122 }
12123 notify_server_capabilities_updated(&server, cx);
12124 }
12125 }
12126 "textDocument/hover" => {
12127 let options = parse_register_capabilities(reg)?;
12128 let provider = match options {
12129 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12130 OneOf::Right(caps) => caps,
12131 };
12132 server.update_capabilities(|capabilities| {
12133 capabilities.hover_provider = Some(provider);
12134 });
12135 notify_server_capabilities_updated(&server, cx);
12136 }
12137 "textDocument/signatureHelp" => {
12138 if let Some(caps) = reg
12139 .register_options
12140 .map(serde_json::from_value)
12141 .transpose()?
12142 {
12143 server.update_capabilities(|capabilities| {
12144 capabilities.signature_help_provider = Some(caps);
12145 });
12146 notify_server_capabilities_updated(&server, cx);
12147 }
12148 }
12149 "textDocument/didChange" => {
12150 if let Some(sync_kind) = reg
12151 .register_options
12152 .and_then(|opts| opts.get("syncKind").cloned())
12153 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12154 .transpose()?
12155 {
12156 server.update_capabilities(|capabilities| {
12157 let mut sync_options =
12158 Self::take_text_document_sync_options(capabilities);
12159 sync_options.change = Some(sync_kind);
12160 capabilities.text_document_sync =
12161 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12162 });
12163 notify_server_capabilities_updated(&server, cx);
12164 }
12165 }
12166 "textDocument/didSave" => {
12167 if let Some(include_text) = reg
12168 .register_options
12169 .map(|opts| {
12170 let transpose = opts
12171 .get("includeText")
12172 .cloned()
12173 .map(serde_json::from_value::<Option<bool>>)
12174 .transpose();
12175 match transpose {
12176 Ok(value) => Ok(value.flatten()),
12177 Err(e) => Err(e),
12178 }
12179 })
12180 .transpose()?
12181 {
12182 server.update_capabilities(|capabilities| {
12183 let mut sync_options =
12184 Self::take_text_document_sync_options(capabilities);
12185 sync_options.save =
12186 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12187 include_text,
12188 }));
12189 capabilities.text_document_sync =
12190 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12191 });
12192 notify_server_capabilities_updated(&server, cx);
12193 }
12194 }
12195 "textDocument/codeLens" => {
12196 if let Some(caps) = reg
12197 .register_options
12198 .map(serde_json::from_value)
12199 .transpose()?
12200 {
12201 server.update_capabilities(|capabilities| {
12202 capabilities.code_lens_provider = Some(caps);
12203 });
12204 notify_server_capabilities_updated(&server, cx);
12205 }
12206 }
12207 "textDocument/diagnostic" => {
12208 if let Some(caps) = reg
12209 .register_options
12210 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12211 .transpose()?
12212 {
12213 let local = self
12214 .as_local_mut()
12215 .context("Expected LSP Store to be local")?;
12216 let state = local
12217 .language_servers
12218 .get_mut(&server_id)
12219 .context("Could not obtain Language Servers state")?;
12220 local
12221 .language_server_dynamic_registrations
12222 .entry(server_id)
12223 .or_default()
12224 .diagnostics
12225 .insert(Some(reg.id.clone()), caps.clone());
12226
12227 if let LanguageServerState::Running {
12228 workspace_diagnostics_refresh_tasks,
12229 ..
12230 } = state
12231 && let Some(task) = lsp_workspace_diagnostics_refresh(
12232 Some(reg.id.clone()),
12233 caps.clone(),
12234 server.clone(),
12235 cx,
12236 )
12237 {
12238 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12239 }
12240
12241 let mut did_update_caps = false;
12242 server.update_capabilities(|capabilities| {
12243 if capabilities.diagnostic_provider.as_ref().is_none_or(
12244 |current_caps| {
12245 let supports_workspace_diagnostics =
12246 |capabilities: &DiagnosticServerCapabilities| {
12247 match capabilities {
12248 DiagnosticServerCapabilities::Options(
12249 diagnostic_options,
12250 ) => diagnostic_options.workspace_diagnostics,
12251 DiagnosticServerCapabilities::RegistrationOptions(
12252 diagnostic_registration_options,
12253 ) => {
12254 diagnostic_registration_options
12255 .diagnostic_options
12256 .workspace_diagnostics
12257 }
12258 }
12259 };
12260 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12261 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12262 // as it'll think that they're not supported.
12263 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12264 !supports_workspace_diagnostics(current_caps)
12265 & supports_workspace_diagnostics(&caps)
12266 },
12267 ) {
12268 did_update_caps = true;
12269 capabilities.diagnostic_provider = Some(caps);
12270 }
12271 });
12272 if did_update_caps {
12273 notify_server_capabilities_updated(&server, cx);
12274 }
12275 }
12276 }
12277 "textDocument/documentColor" => {
12278 let options = parse_register_capabilities(reg)?;
12279 let provider = match options {
12280 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12281 OneOf::Right(caps) => caps,
12282 };
12283 server.update_capabilities(|capabilities| {
12284 capabilities.color_provider = Some(provider);
12285 });
12286 notify_server_capabilities_updated(&server, cx);
12287 }
12288 _ => log::warn!("unhandled capability registration: {reg:?}"),
12289 }
12290 }
12291
12292 Ok(())
12293 }
12294
12295 fn unregister_server_capabilities(
12296 &mut self,
12297 server_id: LanguageServerId,
12298 params: lsp::UnregistrationParams,
12299 cx: &mut Context<Self>,
12300 ) -> anyhow::Result<()> {
12301 let server = self
12302 .language_server_for_id(server_id)
12303 .with_context(|| format!("no server {server_id} found"))?;
12304 for unreg in params.unregisterations.iter() {
12305 match unreg.method.as_str() {
12306 "workspace/didChangeWatchedFiles" => {
12307 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12308 local_lsp_store
12309 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12310 true
12311 } else {
12312 false
12313 };
12314 if notify {
12315 notify_server_capabilities_updated(&server, cx);
12316 }
12317 }
12318 "workspace/didChangeConfiguration" => {
12319 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12320 }
12321 "workspace/didChangeWorkspaceFolders" => {
12322 server.update_capabilities(|capabilities| {
12323 capabilities
12324 .workspace
12325 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12326 workspace_folders: None,
12327 file_operations: None,
12328 })
12329 .workspace_folders = None;
12330 });
12331 notify_server_capabilities_updated(&server, cx);
12332 }
12333 "workspace/symbol" => {
12334 server.update_capabilities(|capabilities| {
12335 capabilities.workspace_symbol_provider = None
12336 });
12337 notify_server_capabilities_updated(&server, cx);
12338 }
12339 "workspace/fileOperations" => {
12340 server.update_capabilities(|capabilities| {
12341 capabilities
12342 .workspace
12343 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12344 workspace_folders: None,
12345 file_operations: None,
12346 })
12347 .file_operations = None;
12348 });
12349 notify_server_capabilities_updated(&server, cx);
12350 }
12351 "workspace/executeCommand" => {
12352 server.update_capabilities(|capabilities| {
12353 capabilities.execute_command_provider = None;
12354 });
12355 notify_server_capabilities_updated(&server, cx);
12356 }
12357 "textDocument/rangeFormatting" => {
12358 server.update_capabilities(|capabilities| {
12359 capabilities.document_range_formatting_provider = None
12360 });
12361 notify_server_capabilities_updated(&server, cx);
12362 }
12363 "textDocument/onTypeFormatting" => {
12364 server.update_capabilities(|capabilities| {
12365 capabilities.document_on_type_formatting_provider = None;
12366 });
12367 notify_server_capabilities_updated(&server, cx);
12368 }
12369 "textDocument/formatting" => {
12370 server.update_capabilities(|capabilities| {
12371 capabilities.document_formatting_provider = None;
12372 });
12373 notify_server_capabilities_updated(&server, cx);
12374 }
12375 "textDocument/rename" => {
12376 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12377 notify_server_capabilities_updated(&server, cx);
12378 }
12379 "textDocument/codeAction" => {
12380 server.update_capabilities(|capabilities| {
12381 capabilities.code_action_provider = None;
12382 });
12383 notify_server_capabilities_updated(&server, cx);
12384 }
12385 "textDocument/definition" => {
12386 server.update_capabilities(|capabilities| {
12387 capabilities.definition_provider = None;
12388 });
12389 notify_server_capabilities_updated(&server, cx);
12390 }
12391 "textDocument/completion" => {
12392 server.update_capabilities(|capabilities| {
12393 capabilities.completion_provider = None;
12394 });
12395 notify_server_capabilities_updated(&server, cx);
12396 }
12397 "textDocument/hover" => {
12398 server.update_capabilities(|capabilities| {
12399 capabilities.hover_provider = None;
12400 });
12401 notify_server_capabilities_updated(&server, cx);
12402 }
12403 "textDocument/signatureHelp" => {
12404 server.update_capabilities(|capabilities| {
12405 capabilities.signature_help_provider = None;
12406 });
12407 notify_server_capabilities_updated(&server, cx);
12408 }
12409 "textDocument/didChange" => {
12410 server.update_capabilities(|capabilities| {
12411 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12412 sync_options.change = None;
12413 capabilities.text_document_sync =
12414 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12415 });
12416 notify_server_capabilities_updated(&server, cx);
12417 }
12418 "textDocument/didSave" => {
12419 server.update_capabilities(|capabilities| {
12420 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12421 sync_options.save = None;
12422 capabilities.text_document_sync =
12423 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12424 });
12425 notify_server_capabilities_updated(&server, cx);
12426 }
12427 "textDocument/codeLens" => {
12428 server.update_capabilities(|capabilities| {
12429 capabilities.code_lens_provider = None;
12430 });
12431 notify_server_capabilities_updated(&server, cx);
12432 }
12433 "textDocument/diagnostic" => {
12434 let local = self
12435 .as_local_mut()
12436 .context("Expected LSP Store to be local")?;
12437
12438 let state = local
12439 .language_servers
12440 .get_mut(&server_id)
12441 .context("Could not obtain Language Servers state")?;
12442 let options = local
12443 .language_server_dynamic_registrations
12444 .get_mut(&server_id)
12445 .with_context(|| {
12446 format!("Expected dynamic registration to exist for server {server_id}")
12447 })?.diagnostics
12448 .remove(&Some(unreg.id.clone()))
12449 .with_context(|| format!(
12450 "Attempted to unregister non-existent diagnostic registration with ID {}",
12451 unreg.id)
12452 )?;
12453
12454 let mut has_any_diagnostic_providers_still = true;
12455 if let Some(identifier) = diagnostic_identifier(&options)
12456 && let LanguageServerState::Running {
12457 workspace_diagnostics_refresh_tasks,
12458 ..
12459 } = state
12460 {
12461 workspace_diagnostics_refresh_tasks.remove(&identifier);
12462 has_any_diagnostic_providers_still =
12463 !workspace_diagnostics_refresh_tasks.is_empty();
12464 }
12465
12466 if !has_any_diagnostic_providers_still {
12467 server.update_capabilities(|capabilities| {
12468 debug_assert!(capabilities.diagnostic_provider.is_some());
12469 capabilities.diagnostic_provider = None;
12470 });
12471 }
12472
12473 notify_server_capabilities_updated(&server, cx);
12474 }
12475 "textDocument/documentColor" => {
12476 server.update_capabilities(|capabilities| {
12477 capabilities.color_provider = None;
12478 });
12479 notify_server_capabilities_updated(&server, cx);
12480 }
12481 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12482 }
12483 }
12484
12485 Ok(())
12486 }
12487
12488 async fn deduplicate_range_based_lsp_requests<T>(
12489 lsp_store: &Entity<Self>,
12490 server_id: Option<LanguageServerId>,
12491 lsp_request_id: LspRequestId,
12492 proto_request: &T::ProtoRequest,
12493 range: Range<Anchor>,
12494 cx: &mut AsyncApp,
12495 ) -> Result<()>
12496 where
12497 T: LspCommand,
12498 T::ProtoRequest: proto::LspRequestMessage,
12499 {
12500 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12501 let version = deserialize_version(proto_request.buffer_version());
12502 let buffer = lsp_store.update(cx, |this, cx| {
12503 this.buffer_store.read(cx).get_existing(buffer_id)
12504 })??;
12505 buffer
12506 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12507 .await?;
12508 lsp_store.update(cx, |lsp_store, cx| {
12509 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12510 let chunks_queried_for = lsp_data
12511 .inlay_hints
12512 .applicable_chunks(&[range])
12513 .collect::<Vec<_>>();
12514 match chunks_queried_for.as_slice() {
12515 &[chunk] => {
12516 let key = LspKey {
12517 request_type: TypeId::of::<T>(),
12518 server_queried: server_id,
12519 };
12520 let previous_request = lsp_data
12521 .chunk_lsp_requests
12522 .entry(key)
12523 .or_default()
12524 .insert(chunk, lsp_request_id);
12525 if let Some((previous_request, running_requests)) =
12526 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12527 {
12528 running_requests.remove(&previous_request);
12529 }
12530 }
12531 _ambiguous_chunks => {
12532 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12533 // there, a buffer version-based check will be performed and outdated requests discarded.
12534 }
12535 }
12536 anyhow::Ok(())
12537 })??;
12538
12539 Ok(())
12540 }
12541
12542 async fn query_lsp_locally<T>(
12543 lsp_store: Entity<Self>,
12544 for_server_id: Option<LanguageServerId>,
12545 sender_id: proto::PeerId,
12546 lsp_request_id: LspRequestId,
12547 proto_request: T::ProtoRequest,
12548 position: Option<Anchor>,
12549 cx: &mut AsyncApp,
12550 ) -> Result<()>
12551 where
12552 T: LspCommand + Clone,
12553 T::ProtoRequest: proto::LspRequestMessage,
12554 <T::ProtoRequest as proto::RequestMessage>::Response:
12555 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12556 {
12557 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12558 let version = deserialize_version(proto_request.buffer_version());
12559 let buffer = lsp_store.update(cx, |this, cx| {
12560 this.buffer_store.read(cx).get_existing(buffer_id)
12561 })??;
12562 buffer
12563 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12564 .await?;
12565 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12566 let request =
12567 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12568 let key = LspKey {
12569 request_type: TypeId::of::<T>(),
12570 server_queried: for_server_id,
12571 };
12572 lsp_store.update(cx, |lsp_store, cx| {
12573 let request_task = match for_server_id {
12574 Some(server_id) => {
12575 let server_task = lsp_store.request_lsp(
12576 buffer.clone(),
12577 LanguageServerToQuery::Other(server_id),
12578 request.clone(),
12579 cx,
12580 );
12581 cx.background_spawn(async move {
12582 let mut responses = Vec::new();
12583 match server_task.await {
12584 Ok(response) => responses.push((server_id, response)),
12585 // rust-analyzer likes to error with this when its still loading up
12586 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12587 Err(e) => log::error!(
12588 "Error handling response for request {request:?}: {e:#}"
12589 ),
12590 }
12591 responses
12592 })
12593 }
12594 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12595 };
12596 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12597 if T::ProtoRequest::stop_previous_requests() {
12598 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12599 lsp_requests.clear();
12600 }
12601 }
12602 lsp_data.lsp_requests.entry(key).or_default().insert(
12603 lsp_request_id,
12604 cx.spawn(async move |lsp_store, cx| {
12605 let response = request_task.await;
12606 lsp_store
12607 .update(cx, |lsp_store, cx| {
12608 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12609 {
12610 let response = response
12611 .into_iter()
12612 .map(|(server_id, response)| {
12613 (
12614 server_id.to_proto(),
12615 T::response_to_proto(
12616 response,
12617 lsp_store,
12618 sender_id,
12619 &buffer_version,
12620 cx,
12621 )
12622 .into(),
12623 )
12624 })
12625 .collect::<HashMap<_, _>>();
12626 match client.send_lsp_response::<T::ProtoRequest>(
12627 project_id,
12628 lsp_request_id,
12629 response,
12630 ) {
12631 Ok(()) => {}
12632 Err(e) => {
12633 log::error!("Failed to send LSP response: {e:#}",)
12634 }
12635 }
12636 }
12637 })
12638 .ok();
12639 }),
12640 );
12641 })?;
12642 Ok(())
12643 }
12644
12645 fn take_text_document_sync_options(
12646 capabilities: &mut lsp::ServerCapabilities,
12647 ) -> lsp::TextDocumentSyncOptions {
12648 match capabilities.text_document_sync.take() {
12649 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12650 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12651 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12652 sync_options.change = Some(sync_kind);
12653 sync_options
12654 }
12655 None => lsp::TextDocumentSyncOptions::default(),
12656 }
12657 }
12658
12659 #[cfg(any(test, feature = "test-support"))]
12660 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12661 Some(
12662 self.lsp_data
12663 .get_mut(&buffer_id)?
12664 .code_lens
12665 .take()?
12666 .update
12667 .take()?
12668 .1,
12669 )
12670 }
12671
12672 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12673 self.downstream_client.clone()
12674 }
12675
12676 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12677 self.worktree_store.clone()
12678 }
12679
12680 /// Gets what's stored in the LSP data for the given buffer.
12681 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12682 self.lsp_data.get_mut(&buffer_id)
12683 }
12684
12685 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12686 /// new [`BufferLspData`] will be created to replace the previous state.
12687 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12688 let (buffer_id, buffer_version) =
12689 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12690 let lsp_data = self
12691 .lsp_data
12692 .entry(buffer_id)
12693 .or_insert_with(|| BufferLspData::new(buffer, cx));
12694 if buffer_version.changed_since(&lsp_data.buffer_version) {
12695 *lsp_data = BufferLspData::new(buffer, cx);
12696 }
12697 lsp_data
12698 }
12699}
12700
12701// Registration with registerOptions as null, should fallback to true.
12702// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12703fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12704 reg: lsp::Registration,
12705) -> Result<OneOf<bool, T>> {
12706 Ok(match reg.register_options {
12707 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12708 None => OneOf::Left(true),
12709 })
12710}
12711
12712fn subscribe_to_binary_statuses(
12713 languages: &Arc<LanguageRegistry>,
12714 cx: &mut Context<'_, LspStore>,
12715) -> Task<()> {
12716 let mut server_statuses = languages.language_server_binary_statuses();
12717 cx.spawn(async move |lsp_store, cx| {
12718 while let Some((server_name, binary_status)) = server_statuses.next().await {
12719 if lsp_store
12720 .update(cx, |_, cx| {
12721 let mut message = None;
12722 let binary_status = match binary_status {
12723 BinaryStatus::None => proto::ServerBinaryStatus::None,
12724 BinaryStatus::CheckingForUpdate => {
12725 proto::ServerBinaryStatus::CheckingForUpdate
12726 }
12727 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12728 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12729 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12730 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12731 BinaryStatus::Failed { error } => {
12732 message = Some(error);
12733 proto::ServerBinaryStatus::Failed
12734 }
12735 };
12736 cx.emit(LspStoreEvent::LanguageServerUpdate {
12737 // Binary updates are about the binary that might not have any language server id at that point.
12738 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12739 language_server_id: LanguageServerId(0),
12740 name: Some(server_name),
12741 message: proto::update_language_server::Variant::StatusUpdate(
12742 proto::StatusUpdate {
12743 message,
12744 status: Some(proto::status_update::Status::Binary(
12745 binary_status as i32,
12746 )),
12747 },
12748 ),
12749 });
12750 })
12751 .is_err()
12752 {
12753 break;
12754 }
12755 }
12756 })
12757}
12758
12759fn lsp_workspace_diagnostics_refresh(
12760 registration_id: Option<String>,
12761 options: DiagnosticServerCapabilities,
12762 server: Arc<LanguageServer>,
12763 cx: &mut Context<'_, LspStore>,
12764) -> Option<WorkspaceRefreshTask> {
12765 let identifier = diagnostic_identifier(&options)?;
12766
12767 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12768 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12769 refresh_tx.try_send(()).ok();
12770
12771 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12772 let mut attempts = 0;
12773 let max_attempts = 50;
12774 let mut requests = 0;
12775
12776 loop {
12777 let Some(()) = refresh_rx.recv().await else {
12778 return;
12779 };
12780
12781 'request: loop {
12782 requests += 1;
12783 if attempts > max_attempts {
12784 log::error!(
12785 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12786 );
12787 return;
12788 }
12789 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12790 cx.background_executor()
12791 .timer(Duration::from_millis(backoff_millis))
12792 .await;
12793 attempts += 1;
12794
12795 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12796 lsp_store
12797 .all_result_ids(server.server_id())
12798 .into_iter()
12799 .filter_map(|(abs_path, result_id)| {
12800 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12801 Some(lsp::PreviousResultId {
12802 uri,
12803 value: result_id,
12804 })
12805 })
12806 .collect()
12807 }) else {
12808 return;
12809 };
12810
12811 let token = if let Some(identifier) = ®istration_id {
12812 format!(
12813 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12814 server.server_id(),
12815 )
12816 } else {
12817 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12818 };
12819
12820 progress_rx.try_recv().ok();
12821 let timer =
12822 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12823 let progress = pin!(progress_rx.recv().fuse());
12824 let response_result = server
12825 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12826 lsp::WorkspaceDiagnosticParams {
12827 previous_result_ids,
12828 identifier: identifier.clone(),
12829 work_done_progress_params: Default::default(),
12830 partial_result_params: lsp::PartialResultParams {
12831 partial_result_token: Some(lsp::ProgressToken::String(token)),
12832 },
12833 },
12834 select(timer, progress).then(|either| match either {
12835 Either::Left((message, ..)) => ready(message).left_future(),
12836 Either::Right(..) => pending::<String>().right_future(),
12837 }),
12838 )
12839 .await;
12840
12841 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12842 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12843 match response_result {
12844 ConnectionResult::Timeout => {
12845 log::error!("Timeout during workspace diagnostics pull");
12846 continue 'request;
12847 }
12848 ConnectionResult::ConnectionReset => {
12849 log::error!("Server closed a workspace diagnostics pull request");
12850 continue 'request;
12851 }
12852 ConnectionResult::Result(Err(e)) => {
12853 log::error!("Error during workspace diagnostics pull: {e:#}");
12854 break 'request;
12855 }
12856 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12857 attempts = 0;
12858 if lsp_store
12859 .update(cx, |lsp_store, cx| {
12860 lsp_store.apply_workspace_diagnostic_report(
12861 server.server_id(),
12862 pulled_diagnostics,
12863 cx,
12864 )
12865 })
12866 .is_err()
12867 {
12868 return;
12869 }
12870 break 'request;
12871 }
12872 }
12873 }
12874 }
12875 });
12876
12877 Some(WorkspaceRefreshTask {
12878 refresh_tx,
12879 progress_tx,
12880 task: workspace_query_language_server,
12881 })
12882}
12883
12884fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12885 match &options {
12886 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12887 if !diagnostic_options.workspace_diagnostics {
12888 return None;
12889 }
12890 Some(diagnostic_options.identifier.clone())
12891 }
12892 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12893 let diagnostic_options = ®istration_options.diagnostic_options;
12894 if !diagnostic_options.workspace_diagnostics {
12895 return None;
12896 }
12897 Some(diagnostic_options.identifier.clone())
12898 }
12899 }
12900}
12901
12902fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12903 let CompletionSource::BufferWord {
12904 word_range,
12905 resolved,
12906 } = &mut completion.source
12907 else {
12908 return;
12909 };
12910 if *resolved {
12911 return;
12912 }
12913
12914 if completion.new_text
12915 != snapshot
12916 .text_for_range(word_range.clone())
12917 .collect::<String>()
12918 {
12919 return;
12920 }
12921
12922 let mut offset = 0;
12923 for chunk in snapshot.chunks(word_range.clone(), true) {
12924 let end_offset = offset + chunk.text.len();
12925 if let Some(highlight_id) = chunk.syntax_highlight_id {
12926 completion
12927 .label
12928 .runs
12929 .push((offset..end_offset, highlight_id));
12930 }
12931 offset = end_offset;
12932 }
12933 *resolved = true;
12934}
12935
12936impl EventEmitter<LspStoreEvent> for LspStore {}
12937
12938fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12939 hover
12940 .contents
12941 .retain(|hover_block| !hover_block.text.trim().is_empty());
12942 if hover.contents.is_empty() {
12943 None
12944 } else {
12945 Some(hover)
12946 }
12947}
12948
12949async fn populate_labels_for_completions(
12950 new_completions: Vec<CoreCompletion>,
12951 language: Option<Arc<Language>>,
12952 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12953) -> Vec<Completion> {
12954 let lsp_completions = new_completions
12955 .iter()
12956 .filter_map(|new_completion| {
12957 new_completion
12958 .source
12959 .lsp_completion(true)
12960 .map(|lsp_completion| lsp_completion.into_owned())
12961 })
12962 .collect::<Vec<_>>();
12963
12964 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12965 lsp_adapter
12966 .labels_for_completions(&lsp_completions, language)
12967 .await
12968 .log_err()
12969 .unwrap_or_default()
12970 } else {
12971 Vec::new()
12972 }
12973 .into_iter()
12974 .fuse();
12975
12976 let mut completions = Vec::new();
12977 for completion in new_completions {
12978 match completion.source.lsp_completion(true) {
12979 Some(lsp_completion) => {
12980 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12981
12982 let mut label = labels.next().flatten().unwrap_or_else(|| {
12983 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12984 });
12985 ensure_uniform_list_compatible_label(&mut label);
12986 completions.push(Completion {
12987 label,
12988 documentation,
12989 replace_range: completion.replace_range,
12990 new_text: completion.new_text,
12991 insert_text_mode: lsp_completion.insert_text_mode,
12992 source: completion.source,
12993 icon_path: None,
12994 confirm: None,
12995 match_start: None,
12996 snippet_deduplication_key: None,
12997 });
12998 }
12999 None => {
13000 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13001 ensure_uniform_list_compatible_label(&mut label);
13002 completions.push(Completion {
13003 label,
13004 documentation: None,
13005 replace_range: completion.replace_range,
13006 new_text: completion.new_text,
13007 source: completion.source,
13008 insert_text_mode: None,
13009 icon_path: None,
13010 confirm: None,
13011 match_start: None,
13012 snippet_deduplication_key: None,
13013 });
13014 }
13015 }
13016 }
13017 completions
13018}
13019
13020#[derive(Debug)]
13021pub enum LanguageServerToQuery {
13022 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13023 FirstCapable,
13024 /// Query a specific language server.
13025 Other(LanguageServerId),
13026}
13027
13028#[derive(Default)]
13029struct RenamePathsWatchedForServer {
13030 did_rename: Vec<RenameActionPredicate>,
13031 will_rename: Vec<RenameActionPredicate>,
13032}
13033
13034impl RenamePathsWatchedForServer {
13035 fn with_did_rename_patterns(
13036 mut self,
13037 did_rename: Option<&FileOperationRegistrationOptions>,
13038 ) -> Self {
13039 if let Some(did_rename) = did_rename {
13040 self.did_rename = did_rename
13041 .filters
13042 .iter()
13043 .filter_map(|filter| filter.try_into().log_err())
13044 .collect();
13045 }
13046 self
13047 }
13048 fn with_will_rename_patterns(
13049 mut self,
13050 will_rename: Option<&FileOperationRegistrationOptions>,
13051 ) -> Self {
13052 if let Some(will_rename) = will_rename {
13053 self.will_rename = will_rename
13054 .filters
13055 .iter()
13056 .filter_map(|filter| filter.try_into().log_err())
13057 .collect();
13058 }
13059 self
13060 }
13061
13062 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13063 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13064 }
13065 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13066 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13067 }
13068}
13069
13070impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13071 type Error = globset::Error;
13072 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13073 Ok(Self {
13074 kind: ops.pattern.matches.clone(),
13075 glob: GlobBuilder::new(&ops.pattern.glob)
13076 .case_insensitive(
13077 ops.pattern
13078 .options
13079 .as_ref()
13080 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13081 )
13082 .build()?
13083 .compile_matcher(),
13084 })
13085 }
13086}
13087struct RenameActionPredicate {
13088 glob: GlobMatcher,
13089 kind: Option<FileOperationPatternKind>,
13090}
13091
13092impl RenameActionPredicate {
13093 // Returns true if language server should be notified
13094 fn eval(&self, path: &str, is_dir: bool) -> bool {
13095 self.kind.as_ref().is_none_or(|kind| {
13096 let expected_kind = if is_dir {
13097 FileOperationPatternKind::Folder
13098 } else {
13099 FileOperationPatternKind::File
13100 };
13101 kind == &expected_kind
13102 }) && self.glob.is_match(path)
13103 }
13104}
13105
13106#[derive(Default)]
13107struct LanguageServerWatchedPaths {
13108 worktree_paths: HashMap<WorktreeId, GlobSet>,
13109 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13110}
13111
13112#[derive(Default)]
13113struct LanguageServerWatchedPathsBuilder {
13114 worktree_paths: HashMap<WorktreeId, GlobSet>,
13115 abs_paths: HashMap<Arc<Path>, GlobSet>,
13116}
13117
13118impl LanguageServerWatchedPathsBuilder {
13119 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13120 self.worktree_paths.insert(worktree_id, glob_set);
13121 }
13122 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13123 self.abs_paths.insert(path, glob_set);
13124 }
13125 fn build(
13126 self,
13127 fs: Arc<dyn Fs>,
13128 language_server_id: LanguageServerId,
13129 cx: &mut Context<LspStore>,
13130 ) -> LanguageServerWatchedPaths {
13131 let lsp_store = cx.weak_entity();
13132
13133 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13134 let abs_paths = self
13135 .abs_paths
13136 .into_iter()
13137 .map(|(abs_path, globset)| {
13138 let task = cx.spawn({
13139 let abs_path = abs_path.clone();
13140 let fs = fs.clone();
13141
13142 let lsp_store = lsp_store.clone();
13143 async move |_, cx| {
13144 maybe!(async move {
13145 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13146 while let Some(update) = push_updates.0.next().await {
13147 let action = lsp_store
13148 .update(cx, |this, _| {
13149 let Some(local) = this.as_local() else {
13150 return ControlFlow::Break(());
13151 };
13152 let Some(watcher) = local
13153 .language_server_watched_paths
13154 .get(&language_server_id)
13155 else {
13156 return ControlFlow::Break(());
13157 };
13158 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13159 "Watched abs path is not registered with a watcher",
13160 );
13161 let matching_entries = update
13162 .into_iter()
13163 .filter(|event| globs.is_match(&event.path))
13164 .collect::<Vec<_>>();
13165 this.lsp_notify_abs_paths_changed(
13166 language_server_id,
13167 matching_entries,
13168 );
13169 ControlFlow::Continue(())
13170 })
13171 .ok()?;
13172
13173 if action.is_break() {
13174 break;
13175 }
13176 }
13177 Some(())
13178 })
13179 .await;
13180 }
13181 });
13182 (abs_path, (globset, task))
13183 })
13184 .collect();
13185 LanguageServerWatchedPaths {
13186 worktree_paths: self.worktree_paths,
13187 abs_paths,
13188 }
13189 }
13190}
13191
13192struct LspBufferSnapshot {
13193 version: i32,
13194 snapshot: TextBufferSnapshot,
13195}
13196
13197/// A prompt requested by LSP server.
13198#[derive(Clone, Debug)]
13199pub struct LanguageServerPromptRequest {
13200 pub level: PromptLevel,
13201 pub message: String,
13202 pub actions: Vec<MessageActionItem>,
13203 pub lsp_name: String,
13204 pub(crate) response_channel: Sender<MessageActionItem>,
13205}
13206
13207impl LanguageServerPromptRequest {
13208 pub async fn respond(self, index: usize) -> Option<()> {
13209 if let Some(response) = self.actions.into_iter().nth(index) {
13210 self.response_channel.send(response).await.ok()
13211 } else {
13212 None
13213 }
13214 }
13215}
13216impl PartialEq for LanguageServerPromptRequest {
13217 fn eq(&self, other: &Self) -> bool {
13218 self.message == other.message && self.actions == other.actions
13219 }
13220}
13221
13222#[derive(Clone, Debug, PartialEq)]
13223pub enum LanguageServerLogType {
13224 Log(MessageType),
13225 Trace { verbose_info: Option<String> },
13226 Rpc { received: bool },
13227}
13228
13229impl LanguageServerLogType {
13230 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13231 match self {
13232 Self::Log(log_type) => {
13233 use proto::log_message::LogLevel;
13234 let level = match *log_type {
13235 MessageType::ERROR => LogLevel::Error,
13236 MessageType::WARNING => LogLevel::Warning,
13237 MessageType::INFO => LogLevel::Info,
13238 MessageType::LOG => LogLevel::Log,
13239 other => {
13240 log::warn!("Unknown lsp log message type: {other:?}");
13241 LogLevel::Log
13242 }
13243 };
13244 proto::language_server_log::LogType::Log(proto::LogMessage {
13245 level: level as i32,
13246 })
13247 }
13248 Self::Trace { verbose_info } => {
13249 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13250 verbose_info: verbose_info.to_owned(),
13251 })
13252 }
13253 Self::Rpc { received } => {
13254 let kind = if *received {
13255 proto::rpc_message::Kind::Received
13256 } else {
13257 proto::rpc_message::Kind::Sent
13258 };
13259 let kind = kind as i32;
13260 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13261 }
13262 }
13263 }
13264
13265 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13266 use proto::log_message::LogLevel;
13267 use proto::rpc_message;
13268 match log_type {
13269 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13270 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13271 LogLevel::Error => MessageType::ERROR,
13272 LogLevel::Warning => MessageType::WARNING,
13273 LogLevel::Info => MessageType::INFO,
13274 LogLevel::Log => MessageType::LOG,
13275 },
13276 ),
13277 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13278 verbose_info: trace_message.verbose_info,
13279 },
13280 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13281 received: match rpc_message::Kind::from_i32(message.kind)
13282 .unwrap_or(rpc_message::Kind::Received)
13283 {
13284 rpc_message::Kind::Received => true,
13285 rpc_message::Kind::Sent => false,
13286 },
13287 },
13288 }
13289 }
13290}
13291
13292pub struct WorkspaceRefreshTask {
13293 refresh_tx: mpsc::Sender<()>,
13294 progress_tx: mpsc::Sender<()>,
13295 #[allow(dead_code)]
13296 task: Task<()>,
13297}
13298
13299pub enum LanguageServerState {
13300 Starting {
13301 startup: Task<Option<Arc<LanguageServer>>>,
13302 /// List of language servers that will be added to the workspace once it's initialization completes.
13303 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13304 },
13305
13306 Running {
13307 adapter: Arc<CachedLspAdapter>,
13308 server: Arc<LanguageServer>,
13309 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13310 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13311 },
13312}
13313
13314impl LanguageServerState {
13315 fn add_workspace_folder(&self, uri: Uri) {
13316 match self {
13317 LanguageServerState::Starting {
13318 pending_workspace_folders,
13319 ..
13320 } => {
13321 pending_workspace_folders.lock().insert(uri);
13322 }
13323 LanguageServerState::Running { server, .. } => {
13324 server.add_workspace_folder(uri);
13325 }
13326 }
13327 }
13328 fn _remove_workspace_folder(&self, uri: Uri) {
13329 match self {
13330 LanguageServerState::Starting {
13331 pending_workspace_folders,
13332 ..
13333 } => {
13334 pending_workspace_folders.lock().remove(&uri);
13335 }
13336 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13337 }
13338 }
13339}
13340
13341impl std::fmt::Debug for LanguageServerState {
13342 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13343 match self {
13344 LanguageServerState::Starting { .. } => {
13345 f.debug_struct("LanguageServerState::Starting").finish()
13346 }
13347 LanguageServerState::Running { .. } => {
13348 f.debug_struct("LanguageServerState::Running").finish()
13349 }
13350 }
13351 }
13352}
13353
13354#[derive(Clone, Debug, Serialize)]
13355pub struct LanguageServerProgress {
13356 pub is_disk_based_diagnostics_progress: bool,
13357 pub is_cancellable: bool,
13358 pub title: Option<String>,
13359 pub message: Option<String>,
13360 pub percentage: Option<usize>,
13361 #[serde(skip_serializing)]
13362 pub last_update_at: Instant,
13363}
13364
13365#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13366pub struct DiagnosticSummary {
13367 pub error_count: usize,
13368 pub warning_count: usize,
13369}
13370
13371impl DiagnosticSummary {
13372 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13373 let mut this = Self {
13374 error_count: 0,
13375 warning_count: 0,
13376 };
13377
13378 for entry in diagnostics {
13379 if entry.diagnostic.is_primary {
13380 match entry.diagnostic.severity {
13381 DiagnosticSeverity::ERROR => this.error_count += 1,
13382 DiagnosticSeverity::WARNING => this.warning_count += 1,
13383 _ => {}
13384 }
13385 }
13386 }
13387
13388 this
13389 }
13390
13391 pub fn is_empty(&self) -> bool {
13392 self.error_count == 0 && self.warning_count == 0
13393 }
13394
13395 pub fn to_proto(
13396 self,
13397 language_server_id: LanguageServerId,
13398 path: &RelPath,
13399 ) -> proto::DiagnosticSummary {
13400 proto::DiagnosticSummary {
13401 path: path.to_proto(),
13402 language_server_id: language_server_id.0 as u64,
13403 error_count: self.error_count as u32,
13404 warning_count: self.warning_count as u32,
13405 }
13406 }
13407}
13408
13409#[derive(Clone, Debug)]
13410pub enum CompletionDocumentation {
13411 /// There is no documentation for this completion.
13412 Undocumented,
13413 /// A single line of documentation.
13414 SingleLine(SharedString),
13415 /// Multiple lines of plain text documentation.
13416 MultiLinePlainText(SharedString),
13417 /// Markdown documentation.
13418 MultiLineMarkdown(SharedString),
13419 /// Both single line and multiple lines of plain text documentation.
13420 SingleLineAndMultiLinePlainText {
13421 single_line: SharedString,
13422 plain_text: Option<SharedString>,
13423 },
13424}
13425
13426impl CompletionDocumentation {
13427 #[cfg(any(test, feature = "test-support"))]
13428 pub fn text(&self) -> SharedString {
13429 match self {
13430 CompletionDocumentation::Undocumented => "".into(),
13431 CompletionDocumentation::SingleLine(s) => s.clone(),
13432 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13433 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13434 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13435 single_line.clone()
13436 }
13437 }
13438 }
13439}
13440
13441impl From<lsp::Documentation> for CompletionDocumentation {
13442 fn from(docs: lsp::Documentation) -> Self {
13443 match docs {
13444 lsp::Documentation::String(text) => {
13445 if text.lines().count() <= 1 {
13446 CompletionDocumentation::SingleLine(text.into())
13447 } else {
13448 CompletionDocumentation::MultiLinePlainText(text.into())
13449 }
13450 }
13451
13452 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13453 lsp::MarkupKind::PlainText => {
13454 if value.lines().count() <= 1 {
13455 CompletionDocumentation::SingleLine(value.into())
13456 } else {
13457 CompletionDocumentation::MultiLinePlainText(value.into())
13458 }
13459 }
13460
13461 lsp::MarkupKind::Markdown => {
13462 CompletionDocumentation::MultiLineMarkdown(value.into())
13463 }
13464 },
13465 }
13466 }
13467}
13468
13469pub enum ResolvedHint {
13470 Resolved(InlayHint),
13471 Resolving(Shared<Task<()>>),
13472}
13473
13474fn glob_literal_prefix(glob: &Path) -> PathBuf {
13475 glob.components()
13476 .take_while(|component| match component {
13477 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13478 _ => true,
13479 })
13480 .collect()
13481}
13482
13483pub struct SshLspAdapter {
13484 name: LanguageServerName,
13485 binary: LanguageServerBinary,
13486 initialization_options: Option<String>,
13487 code_action_kinds: Option<Vec<CodeActionKind>>,
13488}
13489
13490impl SshLspAdapter {
13491 pub fn new(
13492 name: LanguageServerName,
13493 binary: LanguageServerBinary,
13494 initialization_options: Option<String>,
13495 code_action_kinds: Option<String>,
13496 ) -> Self {
13497 Self {
13498 name,
13499 binary,
13500 initialization_options,
13501 code_action_kinds: code_action_kinds
13502 .as_ref()
13503 .and_then(|c| serde_json::from_str(c).ok()),
13504 }
13505 }
13506}
13507
13508impl LspInstaller for SshLspAdapter {
13509 type BinaryVersion = ();
13510 async fn check_if_user_installed(
13511 &self,
13512 _: &dyn LspAdapterDelegate,
13513 _: Option<Toolchain>,
13514 _: &AsyncApp,
13515 ) -> Option<LanguageServerBinary> {
13516 Some(self.binary.clone())
13517 }
13518
13519 async fn cached_server_binary(
13520 &self,
13521 _: PathBuf,
13522 _: &dyn LspAdapterDelegate,
13523 ) -> Option<LanguageServerBinary> {
13524 None
13525 }
13526
13527 async fn fetch_latest_server_version(
13528 &self,
13529 _: &dyn LspAdapterDelegate,
13530 _: bool,
13531 _: &mut AsyncApp,
13532 ) -> Result<()> {
13533 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13534 }
13535
13536 async fn fetch_server_binary(
13537 &self,
13538 _: (),
13539 _: PathBuf,
13540 _: &dyn LspAdapterDelegate,
13541 ) -> Result<LanguageServerBinary> {
13542 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13543 }
13544}
13545
13546#[async_trait(?Send)]
13547impl LspAdapter for SshLspAdapter {
13548 fn name(&self) -> LanguageServerName {
13549 self.name.clone()
13550 }
13551
13552 async fn initialization_options(
13553 self: Arc<Self>,
13554 _: &Arc<dyn LspAdapterDelegate>,
13555 ) -> Result<Option<serde_json::Value>> {
13556 let Some(options) = &self.initialization_options else {
13557 return Ok(None);
13558 };
13559 let result = serde_json::from_str(options)?;
13560 Ok(result)
13561 }
13562
13563 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13564 self.code_action_kinds.clone()
13565 }
13566}
13567
13568pub fn language_server_settings<'a>(
13569 delegate: &'a dyn LspAdapterDelegate,
13570 language: &LanguageServerName,
13571 cx: &'a App,
13572) -> Option<&'a LspSettings> {
13573 language_server_settings_for(
13574 SettingsLocation {
13575 worktree_id: delegate.worktree_id(),
13576 path: RelPath::empty(),
13577 },
13578 language,
13579 cx,
13580 )
13581}
13582
13583pub(crate) fn language_server_settings_for<'a>(
13584 location: SettingsLocation<'a>,
13585 language: &LanguageServerName,
13586 cx: &'a App,
13587) -> Option<&'a LspSettings> {
13588 ProjectSettings::get(Some(location), cx).lsp.get(language)
13589}
13590
13591pub struct LocalLspAdapterDelegate {
13592 lsp_store: WeakEntity<LspStore>,
13593 worktree: worktree::Snapshot,
13594 fs: Arc<dyn Fs>,
13595 http_client: Arc<dyn HttpClient>,
13596 language_registry: Arc<LanguageRegistry>,
13597 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13598}
13599
13600impl LocalLspAdapterDelegate {
13601 pub fn new(
13602 language_registry: Arc<LanguageRegistry>,
13603 environment: &Entity<ProjectEnvironment>,
13604 lsp_store: WeakEntity<LspStore>,
13605 worktree: &Entity<Worktree>,
13606 http_client: Arc<dyn HttpClient>,
13607 fs: Arc<dyn Fs>,
13608 cx: &mut App,
13609 ) -> Arc<Self> {
13610 let load_shell_env_task =
13611 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13612
13613 Arc::new(Self {
13614 lsp_store,
13615 worktree: worktree.read(cx).snapshot(),
13616 fs,
13617 http_client,
13618 language_registry,
13619 load_shell_env_task,
13620 })
13621 }
13622
13623 fn from_local_lsp(
13624 local: &LocalLspStore,
13625 worktree: &Entity<Worktree>,
13626 cx: &mut App,
13627 ) -> Arc<Self> {
13628 Self::new(
13629 local.languages.clone(),
13630 &local.environment,
13631 local.weak.clone(),
13632 worktree,
13633 local.http_client.clone(),
13634 local.fs.clone(),
13635 cx,
13636 )
13637 }
13638}
13639
13640#[async_trait]
13641impl LspAdapterDelegate for LocalLspAdapterDelegate {
13642 fn show_notification(&self, message: &str, cx: &mut App) {
13643 self.lsp_store
13644 .update(cx, |_, cx| {
13645 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13646 })
13647 .ok();
13648 }
13649
13650 fn http_client(&self) -> Arc<dyn HttpClient> {
13651 self.http_client.clone()
13652 }
13653
13654 fn worktree_id(&self) -> WorktreeId {
13655 self.worktree.id()
13656 }
13657
13658 fn worktree_root_path(&self) -> &Path {
13659 self.worktree.abs_path().as_ref()
13660 }
13661
13662 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13663 self.worktree.resolve_executable_path(path)
13664 }
13665
13666 async fn shell_env(&self) -> HashMap<String, String> {
13667 let task = self.load_shell_env_task.clone();
13668 task.await.unwrap_or_default()
13669 }
13670
13671 async fn npm_package_installed_version(
13672 &self,
13673 package_name: &str,
13674 ) -> Result<Option<(PathBuf, String)>> {
13675 let local_package_directory = self.worktree_root_path();
13676 let node_modules_directory = local_package_directory.join("node_modules");
13677
13678 if let Some(version) =
13679 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13680 {
13681 return Ok(Some((node_modules_directory, version)));
13682 }
13683 let Some(npm) = self.which("npm".as_ref()).await else {
13684 log::warn!(
13685 "Failed to find npm executable for {:?}",
13686 local_package_directory
13687 );
13688 return Ok(None);
13689 };
13690
13691 let env = self.shell_env().await;
13692 let output = util::command::new_smol_command(&npm)
13693 .args(["root", "-g"])
13694 .envs(env)
13695 .current_dir(local_package_directory)
13696 .output()
13697 .await?;
13698 let global_node_modules =
13699 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13700
13701 if let Some(version) =
13702 read_package_installed_version(global_node_modules.clone(), package_name).await?
13703 {
13704 return Ok(Some((global_node_modules, version)));
13705 }
13706 return Ok(None);
13707 }
13708
13709 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13710 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13711 if self.fs.is_file(&worktree_abs_path).await {
13712 worktree_abs_path.pop();
13713 }
13714
13715 let env = self.shell_env().await;
13716
13717 let shell_path = env.get("PATH").cloned();
13718
13719 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13720 }
13721
13722 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13723 let mut working_dir = self.worktree_root_path().to_path_buf();
13724 if self.fs.is_file(&working_dir).await {
13725 working_dir.pop();
13726 }
13727 let output = util::command::new_smol_command(&command.path)
13728 .args(command.arguments)
13729 .envs(command.env.clone().unwrap_or_default())
13730 .current_dir(working_dir)
13731 .output()
13732 .await?;
13733
13734 anyhow::ensure!(
13735 output.status.success(),
13736 "{}, stdout: {:?}, stderr: {:?}",
13737 output.status,
13738 String::from_utf8_lossy(&output.stdout),
13739 String::from_utf8_lossy(&output.stderr)
13740 );
13741 Ok(())
13742 }
13743
13744 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13745 self.language_registry
13746 .update_lsp_binary_status(server_name, status);
13747 }
13748
13749 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13750 self.language_registry
13751 .all_lsp_adapters()
13752 .into_iter()
13753 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13754 .collect()
13755 }
13756
13757 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13758 let dir = self.language_registry.language_server_download_dir(name)?;
13759
13760 if !dir.exists() {
13761 smol::fs::create_dir_all(&dir)
13762 .await
13763 .context("failed to create container directory")
13764 .log_err()?;
13765 }
13766
13767 Some(dir)
13768 }
13769
13770 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13771 let entry = self
13772 .worktree
13773 .entry_for_path(path)
13774 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13775 let abs_path = self.worktree.absolutize(&entry.path);
13776 self.fs.load(&abs_path).await
13777 }
13778}
13779
13780async fn populate_labels_for_symbols(
13781 symbols: Vec<CoreSymbol>,
13782 language_registry: &Arc<LanguageRegistry>,
13783 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13784 output: &mut Vec<Symbol>,
13785) {
13786 #[allow(clippy::mutable_key_type)]
13787 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13788
13789 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13790 for symbol in symbols {
13791 let Some(file_name) = symbol.path.file_name() else {
13792 continue;
13793 };
13794 let language = language_registry
13795 .load_language_for_file_path(Path::new(file_name))
13796 .await
13797 .ok()
13798 .or_else(|| {
13799 unknown_paths.insert(file_name.into());
13800 None
13801 });
13802 symbols_by_language
13803 .entry(language)
13804 .or_default()
13805 .push(symbol);
13806 }
13807
13808 for unknown_path in unknown_paths {
13809 log::info!("no language found for symbol in file {unknown_path:?}");
13810 }
13811
13812 let mut label_params = Vec::new();
13813 for (language, mut symbols) in symbols_by_language {
13814 label_params.clear();
13815 label_params.extend(
13816 symbols
13817 .iter_mut()
13818 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13819 );
13820
13821 let mut labels = Vec::new();
13822 if let Some(language) = language {
13823 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13824 language_registry
13825 .lsp_adapters(&language.name())
13826 .first()
13827 .cloned()
13828 });
13829 if let Some(lsp_adapter) = lsp_adapter {
13830 labels = lsp_adapter
13831 .labels_for_symbols(&label_params, &language)
13832 .await
13833 .log_err()
13834 .unwrap_or_default();
13835 }
13836 }
13837
13838 for ((symbol, (name, _)), label) in symbols
13839 .into_iter()
13840 .zip(label_params.drain(..))
13841 .zip(labels.into_iter().chain(iter::repeat(None)))
13842 {
13843 output.push(Symbol {
13844 language_server_name: symbol.language_server_name,
13845 source_worktree_id: symbol.source_worktree_id,
13846 source_language_server_id: symbol.source_language_server_id,
13847 path: symbol.path,
13848 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13849 name,
13850 kind: symbol.kind,
13851 range: symbol.range,
13852 });
13853 }
13854 }
13855}
13856
13857fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13858 match server.capabilities().text_document_sync.as_ref()? {
13859 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13860 // Server wants didSave but didn't specify includeText.
13861 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13862 // Server doesn't want didSave at all.
13863 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13864 // Server provided SaveOptions.
13865 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13866 Some(save_options.include_text.unwrap_or(false))
13867 }
13868 },
13869 // We do not have any save info. Kind affects didChange only.
13870 lsp::TextDocumentSyncCapability::Kind(_) => None,
13871 }
13872}
13873
13874/// Completion items are displayed in a `UniformList`.
13875/// Usually, those items are single-line strings, but in LSP responses,
13876/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13877/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13878/// 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,
13879/// breaking the completions menu presentation.
13880///
13881/// 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.
13882fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13883 let mut new_text = String::with_capacity(label.text.len());
13884 let mut offset_map = vec![0; label.text.len() + 1];
13885 let mut last_char_was_space = false;
13886 let mut new_idx = 0;
13887 let chars = label.text.char_indices().fuse();
13888 let mut newlines_removed = false;
13889
13890 for (idx, c) in chars {
13891 offset_map[idx] = new_idx;
13892
13893 match c {
13894 '\n' if last_char_was_space => {
13895 newlines_removed = true;
13896 }
13897 '\t' | ' ' if last_char_was_space => {}
13898 '\n' if !last_char_was_space => {
13899 new_text.push(' ');
13900 new_idx += 1;
13901 last_char_was_space = true;
13902 newlines_removed = true;
13903 }
13904 ' ' | '\t' => {
13905 new_text.push(' ');
13906 new_idx += 1;
13907 last_char_was_space = true;
13908 }
13909 _ => {
13910 new_text.push(c);
13911 new_idx += c.len_utf8();
13912 last_char_was_space = false;
13913 }
13914 }
13915 }
13916 offset_map[label.text.len()] = new_idx;
13917
13918 // Only modify the label if newlines were removed.
13919 if !newlines_removed {
13920 return;
13921 }
13922
13923 let last_index = new_idx;
13924 let mut run_ranges_errors = Vec::new();
13925 label.runs.retain_mut(|(range, _)| {
13926 match offset_map.get(range.start) {
13927 Some(&start) => range.start = start,
13928 None => {
13929 run_ranges_errors.push(range.clone());
13930 return false;
13931 }
13932 }
13933
13934 match offset_map.get(range.end) {
13935 Some(&end) => range.end = end,
13936 None => {
13937 run_ranges_errors.push(range.clone());
13938 range.end = last_index;
13939 }
13940 }
13941 true
13942 });
13943 if !run_ranges_errors.is_empty() {
13944 log::error!(
13945 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13946 label.text
13947 );
13948 }
13949
13950 let mut wrong_filter_range = None;
13951 if label.filter_range == (0..label.text.len()) {
13952 label.filter_range = 0..new_text.len();
13953 } else {
13954 let mut original_filter_range = Some(label.filter_range.clone());
13955 match offset_map.get(label.filter_range.start) {
13956 Some(&start) => label.filter_range.start = start,
13957 None => {
13958 wrong_filter_range = original_filter_range.take();
13959 label.filter_range.start = last_index;
13960 }
13961 }
13962
13963 match offset_map.get(label.filter_range.end) {
13964 Some(&end) => label.filter_range.end = end,
13965 None => {
13966 wrong_filter_range = original_filter_range.take();
13967 label.filter_range.end = last_index;
13968 }
13969 }
13970 }
13971 if let Some(wrong_filter_range) = wrong_filter_range {
13972 log::error!(
13973 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13974 label.text
13975 );
13976 }
13977
13978 label.text = new_text;
13979}
13980
13981#[cfg(test)]
13982mod tests {
13983 use language::HighlightId;
13984
13985 use super::*;
13986
13987 #[test]
13988 fn test_glob_literal_prefix() {
13989 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13990 assert_eq!(
13991 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13992 Path::new("node_modules")
13993 );
13994 assert_eq!(
13995 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13996 Path::new("foo")
13997 );
13998 assert_eq!(
13999 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14000 Path::new("foo/bar/baz.js")
14001 );
14002
14003 #[cfg(target_os = "windows")]
14004 {
14005 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14006 assert_eq!(
14007 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14008 Path::new("node_modules")
14009 );
14010 assert_eq!(
14011 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14012 Path::new("foo")
14013 );
14014 assert_eq!(
14015 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14016 Path::new("foo/bar/baz.js")
14017 );
14018 }
14019 }
14020
14021 #[test]
14022 fn test_multi_len_chars_normalization() {
14023 let mut label = CodeLabel::new(
14024 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14025 0..6,
14026 vec![(0..6, HighlightId(1))],
14027 );
14028 ensure_uniform_list_compatible_label(&mut label);
14029 assert_eq!(
14030 label,
14031 CodeLabel::new(
14032 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14033 0..6,
14034 vec![(0..6, HighlightId(1))],
14035 )
14036 );
14037 }
14038}