1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 worktree_store::{WorktreeStore, WorktreeStoreEvent},
42 yarn::YarnPathStore,
43};
44use anyhow::{Context as _, Result, anyhow};
45use async_trait::async_trait;
46use client::{TypedEnvelope, proto};
47use clock::Global;
48use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
49use futures::{
50 AsyncWriteExt, Future, FutureExt, StreamExt,
51 future::{Either, Shared, join_all, pending, select},
52 select, select_biased,
53 stream::FuturesUnordered,
54};
55use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
56use gpui::{
57 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
58 WeakEntity,
59};
60use http_client::HttpClient;
61use itertools::Itertools as _;
62use language::{
63 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
64 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
65 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
66 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
67 Transaction, Unclipped,
68 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
69 point_to_lsp,
70 proto::{
71 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
72 serialize_lsp_edit, serialize_version,
73 },
74 range_from_lsp, range_to_lsp,
75 row_chunk::RowChunk,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use serde_json::Value;
97use settings::{Settings, SettingsLocation, SettingsStore};
98use sha2::{Digest, Sha256};
99use smol::channel::Sender;
100use snippet::Snippet;
101use std::{
102 any::TypeId,
103 borrow::Cow,
104 cell::RefCell,
105 cmp::{Ordering, Reverse},
106 convert::TryInto,
107 ffi::OsStr,
108 future::ready,
109 iter, mem,
110 ops::{ControlFlow, Range},
111 path::{self, Path, PathBuf},
112 pin::pin,
113 rc::Rc,
114 sync::{
115 Arc,
116 atomic::{self, AtomicUsize},
117 },
118 time::{Duration, Instant},
119};
120use sum_tree::Dimensions;
121use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
122
123use util::{
124 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
125 paths::{PathStyle, SanitizedPath},
126 post_inc,
127 rel_path::RelPath,
128};
129
130pub use fs::*;
131pub use language::Location;
132pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
133#[cfg(any(test, feature = "test-support"))]
134pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
135pub use worktree::{
136 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
137 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
138};
139
140const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
141pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
142const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
143const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
144
145#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
146pub enum ProgressToken {
147 Number(i32),
148 String(SharedString),
149}
150
151impl std::fmt::Display for ProgressToken {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 Self::Number(number) => write!(f, "{number}"),
155 Self::String(string) => write!(f, "{string}"),
156 }
157 }
158}
159
160impl ProgressToken {
161 fn from_lsp(value: lsp::NumberOrString) -> Self {
162 match value {
163 lsp::NumberOrString::Number(number) => Self::Number(number),
164 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
165 }
166 }
167
168 fn to_lsp(&self) -> lsp::NumberOrString {
169 match self {
170 Self::Number(number) => lsp::NumberOrString::Number(*number),
171 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
172 }
173 }
174
175 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
176 Some(match value.value? {
177 proto::progress_token::Value::Number(number) => Self::Number(number),
178 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
179 })
180 }
181
182 fn to_proto(&self) -> proto::ProgressToken {
183 proto::ProgressToken {
184 value: Some(match self {
185 Self::Number(number) => proto::progress_token::Value::Number(*number),
186 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
187 }),
188 }
189 }
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum FormatTrigger {
194 Save,
195 Manual,
196}
197
198pub enum LspFormatTarget {
199 Buffers,
200 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
201}
202
203pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
204
205impl FormatTrigger {
206 fn from_proto(value: i32) -> FormatTrigger {
207 match value {
208 0 => FormatTrigger::Save,
209 1 => FormatTrigger::Manual,
210 _ => FormatTrigger::Save,
211 }
212 }
213}
214
215#[derive(Clone)]
216struct UnifiedLanguageServer {
217 id: LanguageServerId,
218 project_roots: HashSet<Arc<RelPath>>,
219}
220
221#[derive(Clone, Hash, PartialEq, Eq)]
222struct LanguageServerSeed {
223 worktree_id: WorktreeId,
224 name: LanguageServerName,
225 toolchain: Option<Toolchain>,
226 settings: Arc<LspSettings>,
227}
228
229#[derive(Debug)]
230pub struct DocumentDiagnosticsUpdate<'a, D> {
231 pub diagnostics: D,
232 pub result_id: Option<String>,
233 pub server_id: LanguageServerId,
234 pub disk_based_sources: Cow<'a, [String]>,
235}
236
237pub struct DocumentDiagnostics {
238 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
239 document_abs_path: PathBuf,
240 version: Option<i32>,
241}
242
243#[derive(Default, Debug)]
244struct DynamicRegistrations {
245 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
246 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
247}
248
249pub struct LocalLspStore {
250 weak: WeakEntity<LspStore>,
251 worktree_store: Entity<WorktreeStore>,
252 toolchain_store: Entity<LocalToolchainStore>,
253 http_client: Arc<dyn HttpClient>,
254 environment: Entity<ProjectEnvironment>,
255 fs: Arc<dyn Fs>,
256 languages: Arc<LanguageRegistry>,
257 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
258 yarn: Entity<YarnPathStore>,
259 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
260 buffers_being_formatted: HashSet<BufferId>,
261 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
262 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
263 watched_manifest_filenames: HashSet<ManifestName>,
264 language_server_paths_watched_for_rename:
265 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
266 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
267 supplementary_language_servers:
268 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
269 prettier_store: Entity<PrettierStore>,
270 next_diagnostic_group_id: usize,
271 diagnostics: HashMap<
272 WorktreeId,
273 HashMap<
274 Arc<RelPath>,
275 Vec<(
276 LanguageServerId,
277 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
278 )>,
279 >,
280 >,
281 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
282 _subscription: gpui::Subscription,
283 lsp_tree: LanguageServerTree,
284 registered_buffers: HashMap<BufferId, usize>,
285 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
286 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
287}
288
289impl LocalLspStore {
290 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
291 pub fn running_language_server_for_id(
292 &self,
293 id: LanguageServerId,
294 ) -> Option<&Arc<LanguageServer>> {
295 let language_server_state = self.language_servers.get(&id)?;
296
297 match language_server_state {
298 LanguageServerState::Running { server, .. } => Some(server),
299 LanguageServerState::Starting { .. } => None,
300 }
301 }
302
303 fn get_or_insert_language_server(
304 &mut self,
305 worktree_handle: &Entity<Worktree>,
306 delegate: Arc<LocalLspAdapterDelegate>,
307 disposition: &Arc<LaunchDisposition>,
308 language_name: &LanguageName,
309 cx: &mut App,
310 ) -> LanguageServerId {
311 let key = LanguageServerSeed {
312 worktree_id: worktree_handle.read(cx).id(),
313 name: disposition.server_name.clone(),
314 settings: disposition.settings.clone(),
315 toolchain: disposition.toolchain.clone(),
316 };
317 if let Some(state) = self.language_server_ids.get_mut(&key) {
318 state.project_roots.insert(disposition.path.path.clone());
319 state.id
320 } else {
321 let adapter = self
322 .languages
323 .lsp_adapters(language_name)
324 .into_iter()
325 .find(|adapter| adapter.name() == disposition.server_name)
326 .expect("To find LSP adapter");
327 let new_language_server_id = self.start_language_server(
328 worktree_handle,
329 delegate,
330 adapter,
331 disposition.settings.clone(),
332 key.clone(),
333 cx,
334 );
335 if let Some(state) = self.language_server_ids.get_mut(&key) {
336 state.project_roots.insert(disposition.path.path.clone());
337 } else {
338 debug_assert!(
339 false,
340 "Expected `start_language_server` to ensure that `key` exists in a map"
341 );
342 }
343 new_language_server_id
344 }
345 }
346
347 fn start_language_server(
348 &mut self,
349 worktree_handle: &Entity<Worktree>,
350 delegate: Arc<LocalLspAdapterDelegate>,
351 adapter: Arc<CachedLspAdapter>,
352 settings: Arc<LspSettings>,
353 key: LanguageServerSeed,
354 cx: &mut App,
355 ) -> LanguageServerId {
356 let worktree = worktree_handle.read(cx);
357
358 let root_path = worktree.abs_path();
359 let toolchain = key.toolchain.clone();
360 let override_options = settings.initialization_options.clone();
361
362 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
363
364 let server_id = self.languages.next_language_server_id();
365 log::trace!(
366 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
367 adapter.name.0
368 );
369
370 let binary = self.get_language_server_binary(
371 adapter.clone(),
372 settings,
373 toolchain.clone(),
374 delegate.clone(),
375 true,
376 cx,
377 );
378 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
379
380 let pending_server = cx.spawn({
381 let adapter = adapter.clone();
382 let server_name = adapter.name.clone();
383 let stderr_capture = stderr_capture.clone();
384 #[cfg(any(test, feature = "test-support"))]
385 let lsp_store = self.weak.clone();
386 let pending_workspace_folders = pending_workspace_folders.clone();
387 async move |cx| {
388 let binary = binary.await?;
389 #[cfg(any(test, feature = "test-support"))]
390 if let Some(server) = lsp_store
391 .update(&mut cx.clone(), |this, cx| {
392 this.languages.create_fake_language_server(
393 server_id,
394 &server_name,
395 binary.clone(),
396 &mut cx.to_async(),
397 )
398 })
399 .ok()
400 .flatten()
401 {
402 return Ok(server);
403 }
404
405 let code_action_kinds = adapter.code_action_kinds();
406 lsp::LanguageServer::new(
407 stderr_capture,
408 server_id,
409 server_name,
410 binary,
411 &root_path,
412 code_action_kinds,
413 Some(pending_workspace_folders),
414 cx,
415 )
416 }
417 });
418
419 let startup = {
420 let server_name = adapter.name.0.clone();
421 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
422 let key = key.clone();
423 let adapter = adapter.clone();
424 let lsp_store = self.weak.clone();
425 let pending_workspace_folders = pending_workspace_folders.clone();
426
427 let pull_diagnostics = ProjectSettings::get_global(cx)
428 .diagnostics
429 .lsp_pull_diagnostics
430 .enabled;
431 cx.spawn(async move |cx| {
432 let result = async {
433 let language_server = pending_server.await?;
434
435 let workspace_config = Self::workspace_configuration_for_adapter(
436 adapter.adapter.clone(),
437 &delegate,
438 toolchain,
439 cx,
440 )
441 .await?;
442
443 let mut initialization_options = Self::initialization_options_for_adapter(
444 adapter.adapter.clone(),
445 &delegate,
446 )
447 .await?;
448
449 match (&mut initialization_options, override_options) {
450 (Some(initialization_options), Some(override_options)) => {
451 merge_json_value_into(override_options, initialization_options);
452 }
453 (None, override_options) => initialization_options = override_options,
454 _ => {}
455 }
456
457 let initialization_params = cx.update(|cx| {
458 let mut params =
459 language_server.default_initialize_params(pull_diagnostics, cx);
460 params.initialization_options = initialization_options;
461 adapter.adapter.prepare_initialize_params(params, cx)
462 })??;
463
464 Self::setup_lsp_messages(
465 lsp_store.clone(),
466 &language_server,
467 delegate.clone(),
468 adapter.clone(),
469 );
470
471 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
472 settings: workspace_config,
473 };
474 let language_server = cx
475 .update(|cx| {
476 language_server.initialize(
477 initialization_params,
478 Arc::new(did_change_configuration_params.clone()),
479 cx,
480 )
481 })?
482 .await
483 .inspect_err(|_| {
484 if let Some(lsp_store) = lsp_store.upgrade() {
485 lsp_store
486 .update(cx, |lsp_store, cx| {
487 lsp_store.cleanup_lsp_data(server_id);
488 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
489 })
490 .ok();
491 }
492 })?;
493
494 language_server.notify::<lsp::notification::DidChangeConfiguration>(
495 did_change_configuration_params,
496 )?;
497
498 anyhow::Ok(language_server)
499 }
500 .await;
501
502 match result {
503 Ok(server) => {
504 lsp_store
505 .update(cx, |lsp_store, cx| {
506 lsp_store.insert_newly_running_language_server(
507 adapter,
508 server.clone(),
509 server_id,
510 key,
511 pending_workspace_folders,
512 cx,
513 );
514 })
515 .ok();
516 stderr_capture.lock().take();
517 Some(server)
518 }
519
520 Err(err) => {
521 let log = stderr_capture.lock().take().unwrap_or_default();
522 delegate.update_status(
523 adapter.name(),
524 BinaryStatus::Failed {
525 error: if log.is_empty() {
526 format!("{err:#}")
527 } else {
528 format!("{err:#}\n-- stderr --\n{log}")
529 },
530 },
531 );
532 log::error!("Failed to start language server {server_name:?}: {err:?}");
533 if !log.is_empty() {
534 log::error!("server stderr: {log}");
535 }
536 None
537 }
538 }
539 })
540 };
541 let state = LanguageServerState::Starting {
542 startup,
543 pending_workspace_folders,
544 };
545
546 self.languages
547 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
548
549 self.language_servers.insert(server_id, state);
550 self.language_server_ids
551 .entry(key)
552 .or_insert(UnifiedLanguageServer {
553 id: server_id,
554 project_roots: Default::default(),
555 });
556 server_id
557 }
558
559 fn get_language_server_binary(
560 &self,
561 adapter: Arc<CachedLspAdapter>,
562 settings: Arc<LspSettings>,
563 toolchain: Option<Toolchain>,
564 delegate: Arc<dyn LspAdapterDelegate>,
565 allow_binary_download: bool,
566 cx: &mut App,
567 ) -> Task<Result<LanguageServerBinary>> {
568 if let Some(settings) = &settings.binary
569 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
570 {
571 let settings = settings.clone();
572
573 return cx.background_spawn(async move {
574 let mut env = delegate.shell_env().await;
575 env.extend(settings.env.unwrap_or_default());
576
577 Ok(LanguageServerBinary {
578 path: delegate.resolve_executable_path(path),
579 env: Some(env),
580 arguments: settings
581 .arguments
582 .unwrap_or_default()
583 .iter()
584 .map(Into::into)
585 .collect(),
586 })
587 });
588 }
589 let lsp_binary_options = LanguageServerBinaryOptions {
590 allow_path_lookup: !settings
591 .binary
592 .as_ref()
593 .and_then(|b| b.ignore_system_version)
594 .unwrap_or_default(),
595 allow_binary_download,
596 pre_release: settings
597 .fetch
598 .as_ref()
599 .and_then(|f| f.pre_release)
600 .unwrap_or(false),
601 };
602
603 cx.spawn(async move |cx| {
604 let (existing_binary, maybe_download_binary) = adapter
605 .clone()
606 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
607 .await
608 .await;
609
610 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
611
612 let mut binary = match (existing_binary, maybe_download_binary) {
613 (binary, None) => binary?,
614 (Err(_), Some(downloader)) => downloader.await?,
615 (Ok(existing_binary), Some(downloader)) => {
616 let mut download_timeout = cx
617 .background_executor()
618 .timer(SERVER_DOWNLOAD_TIMEOUT)
619 .fuse();
620 let mut downloader = downloader.fuse();
621 futures::select! {
622 _ = download_timeout => {
623 // Return existing binary and kick the existing work to the background.
624 cx.spawn(async move |_| downloader.await).detach();
625 Ok(existing_binary)
626 },
627 downloaded_or_existing_binary = downloader => {
628 // If download fails, this results in the existing binary.
629 downloaded_or_existing_binary
630 }
631 }?
632 }
633 };
634 let mut shell_env = delegate.shell_env().await;
635
636 shell_env.extend(binary.env.unwrap_or_default());
637
638 if let Some(settings) = settings.binary.as_ref() {
639 if let Some(arguments) = &settings.arguments {
640 binary.arguments = arguments.iter().map(Into::into).collect();
641 }
642 if let Some(env) = &settings.env {
643 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
644 }
645 }
646
647 binary.env = Some(shell_env);
648 Ok(binary)
649 })
650 }
651
652 fn setup_lsp_messages(
653 lsp_store: WeakEntity<LspStore>,
654 language_server: &LanguageServer,
655 delegate: Arc<dyn LspAdapterDelegate>,
656 adapter: Arc<CachedLspAdapter>,
657 ) {
658 let name = language_server.name();
659 let server_id = language_server.server_id();
660 language_server
661 .on_notification::<lsp::notification::PublishDiagnostics, _>({
662 let adapter = adapter.clone();
663 let this = lsp_store.clone();
664 move |mut params, cx| {
665 let adapter = adapter.clone();
666 if let Some(this) = this.upgrade() {
667 this.update(cx, |this, cx| {
668 {
669 let buffer = params
670 .uri
671 .to_file_path()
672 .map(|file_path| this.get_buffer(&file_path, cx))
673 .ok()
674 .flatten();
675 adapter.process_diagnostics(&mut params, server_id, buffer);
676 }
677
678 this.merge_lsp_diagnostics(
679 DiagnosticSourceKind::Pushed,
680 vec![DocumentDiagnosticsUpdate {
681 server_id,
682 diagnostics: params,
683 result_id: None,
684 disk_based_sources: Cow::Borrowed(
685 &adapter.disk_based_diagnostic_sources,
686 ),
687 }],
688 |_, diagnostic, cx| match diagnostic.source_kind {
689 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
690 adapter.retain_old_diagnostic(diagnostic, cx)
691 }
692 DiagnosticSourceKind::Pulled => true,
693 },
694 cx,
695 )
696 .log_err();
697 })
698 .ok();
699 }
700 }
701 })
702 .detach();
703 language_server
704 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
705 let adapter = adapter.adapter.clone();
706 let delegate = delegate.clone();
707 let this = lsp_store.clone();
708 move |params, cx| {
709 let adapter = adapter.clone();
710 let delegate = delegate.clone();
711 let this = this.clone();
712 let mut cx = cx.clone();
713 async move {
714 let toolchain_for_id = this
715 .update(&mut cx, |this, _| {
716 this.as_local()?.language_server_ids.iter().find_map(
717 |(seed, value)| {
718 (value.id == server_id).then(|| seed.toolchain.clone())
719 },
720 )
721 })?
722 .context("Expected the LSP store to be in a local mode")?;
723 let workspace_config = Self::workspace_configuration_for_adapter(
724 adapter.clone(),
725 &delegate,
726 toolchain_for_id,
727 &mut cx,
728 )
729 .await?;
730
731 Ok(params
732 .items
733 .into_iter()
734 .map(|item| {
735 if let Some(section) = &item.section {
736 workspace_config
737 .get(section)
738 .cloned()
739 .unwrap_or(serde_json::Value::Null)
740 } else {
741 workspace_config.clone()
742 }
743 })
744 .collect())
745 }
746 }
747 })
748 .detach();
749
750 language_server
751 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
752 let this = lsp_store.clone();
753 move |_, cx| {
754 let this = this.clone();
755 let cx = cx.clone();
756 async move {
757 let Some(server) =
758 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
759 else {
760 return Ok(None);
761 };
762 let root = server.workspace_folders();
763 Ok(Some(
764 root.into_iter()
765 .map(|uri| WorkspaceFolder {
766 uri,
767 name: Default::default(),
768 })
769 .collect(),
770 ))
771 }
772 }
773 })
774 .detach();
775 // Even though we don't have handling for these requests, respond to them to
776 // avoid stalling any language server like `gopls` which waits for a response
777 // to these requests when initializing.
778 language_server
779 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
780 let this = lsp_store.clone();
781 move |params, cx| {
782 let this = this.clone();
783 let mut cx = cx.clone();
784 async move {
785 this.update(&mut cx, |this, _| {
786 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
787 {
788 status
789 .progress_tokens
790 .insert(ProgressToken::from_lsp(params.token));
791 }
792 })?;
793
794 Ok(())
795 }
796 }
797 })
798 .detach();
799
800 language_server
801 .on_request::<lsp::request::RegisterCapability, _, _>({
802 let lsp_store = lsp_store.clone();
803 move |params, cx| {
804 let lsp_store = lsp_store.clone();
805 let mut cx = cx.clone();
806 async move {
807 lsp_store
808 .update(&mut cx, |lsp_store, cx| {
809 if lsp_store.as_local().is_some() {
810 match lsp_store
811 .register_server_capabilities(server_id, params, cx)
812 {
813 Ok(()) => {}
814 Err(e) => {
815 log::error!(
816 "Failed to register server capabilities: {e:#}"
817 );
818 }
819 };
820 }
821 })
822 .ok();
823 Ok(())
824 }
825 }
826 })
827 .detach();
828
829 language_server
830 .on_request::<lsp::request::UnregisterCapability, _, _>({
831 let lsp_store = lsp_store.clone();
832 move |params, cx| {
833 let lsp_store = lsp_store.clone();
834 let mut cx = cx.clone();
835 async move {
836 lsp_store
837 .update(&mut cx, |lsp_store, cx| {
838 if lsp_store.as_local().is_some() {
839 match lsp_store
840 .unregister_server_capabilities(server_id, params, cx)
841 {
842 Ok(()) => {}
843 Err(e) => {
844 log::error!(
845 "Failed to unregister server capabilities: {e:#}"
846 );
847 }
848 }
849 }
850 })
851 .ok();
852 Ok(())
853 }
854 }
855 })
856 .detach();
857
858 language_server
859 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
860 let this = lsp_store.clone();
861 move |params, cx| {
862 let mut cx = cx.clone();
863 let this = this.clone();
864 async move {
865 LocalLspStore::on_lsp_workspace_edit(
866 this.clone(),
867 params,
868 server_id,
869 &mut cx,
870 )
871 .await
872 }
873 }
874 })
875 .detach();
876
877 language_server
878 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
879 let lsp_store = lsp_store.clone();
880 let request_id = Arc::new(AtomicUsize::new(0));
881 move |(), cx| {
882 let lsp_store = lsp_store.clone();
883 let request_id = request_id.clone();
884 let mut cx = cx.clone();
885 async move {
886 lsp_store
887 .update(&mut cx, |lsp_store, cx| {
888 let request_id =
889 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
890 cx.emit(LspStoreEvent::RefreshInlayHints {
891 server_id,
892 request_id,
893 });
894 lsp_store
895 .downstream_client
896 .as_ref()
897 .map(|(client, project_id)| {
898 client.send(proto::RefreshInlayHints {
899 project_id: *project_id,
900 server_id: server_id.to_proto(),
901 request_id: request_id.map(|id| id as u64),
902 })
903 })
904 })?
905 .transpose()?;
906 Ok(())
907 }
908 }
909 })
910 .detach();
911
912 language_server
913 .on_request::<lsp::request::CodeLensRefresh, _, _>({
914 let this = lsp_store.clone();
915 move |(), cx| {
916 let this = this.clone();
917 let mut cx = cx.clone();
918 async move {
919 this.update(&mut cx, |this, cx| {
920 cx.emit(LspStoreEvent::RefreshCodeLens);
921 this.downstream_client.as_ref().map(|(client, project_id)| {
922 client.send(proto::RefreshCodeLens {
923 project_id: *project_id,
924 })
925 })
926 })?
927 .transpose()?;
928 Ok(())
929 }
930 }
931 })
932 .detach();
933
934 language_server
935 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
936 let this = lsp_store.clone();
937 move |(), cx| {
938 let this = this.clone();
939 let mut cx = cx.clone();
940 async move {
941 this.update(&mut cx, |lsp_store, _| {
942 lsp_store.pull_workspace_diagnostics(server_id);
943 lsp_store
944 .downstream_client
945 .as_ref()
946 .map(|(client, project_id)| {
947 client.send(proto::PullWorkspaceDiagnostics {
948 project_id: *project_id,
949 server_id: server_id.to_proto(),
950 })
951 })
952 })?
953 .transpose()?;
954 Ok(())
955 }
956 }
957 })
958 .detach();
959
960 language_server
961 .on_request::<lsp::request::ShowMessageRequest, _, _>({
962 let this = lsp_store.clone();
963 let name = name.to_string();
964 move |params, cx| {
965 let this = this.clone();
966 let name = name.to_string();
967 let mut cx = cx.clone();
968 async move {
969 let actions = params.actions.unwrap_or_default();
970 let (tx, rx) = smol::channel::bounded(1);
971 let request = LanguageServerPromptRequest {
972 level: match params.typ {
973 lsp::MessageType::ERROR => PromptLevel::Critical,
974 lsp::MessageType::WARNING => PromptLevel::Warning,
975 _ => PromptLevel::Info,
976 },
977 message: params.message,
978 actions,
979 response_channel: tx,
980 lsp_name: name.clone(),
981 };
982
983 let did_update = this
984 .update(&mut cx, |_, cx| {
985 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
986 })
987 .is_ok();
988 if did_update {
989 let response = rx.recv().await.ok();
990 Ok(response)
991 } else {
992 Ok(None)
993 }
994 }
995 }
996 })
997 .detach();
998 language_server
999 .on_notification::<lsp::notification::ShowMessage, _>({
1000 let this = lsp_store.clone();
1001 let name = name.to_string();
1002 move |params, cx| {
1003 let this = this.clone();
1004 let name = name.to_string();
1005 let mut cx = cx.clone();
1006
1007 let (tx, _) = smol::channel::bounded(1);
1008 let request = LanguageServerPromptRequest {
1009 level: match params.typ {
1010 lsp::MessageType::ERROR => PromptLevel::Critical,
1011 lsp::MessageType::WARNING => PromptLevel::Warning,
1012 _ => PromptLevel::Info,
1013 },
1014 message: params.message,
1015 actions: vec![],
1016 response_channel: tx,
1017 lsp_name: name,
1018 };
1019
1020 let _ = this.update(&mut cx, |_, cx| {
1021 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1022 });
1023 }
1024 })
1025 .detach();
1026
1027 let disk_based_diagnostics_progress_token =
1028 adapter.disk_based_diagnostics_progress_token.clone();
1029
1030 language_server
1031 .on_notification::<lsp::notification::Progress, _>({
1032 let this = lsp_store.clone();
1033 move |params, cx| {
1034 if let Some(this) = this.upgrade() {
1035 this.update(cx, |this, cx| {
1036 this.on_lsp_progress(
1037 params,
1038 server_id,
1039 disk_based_diagnostics_progress_token.clone(),
1040 cx,
1041 );
1042 })
1043 .ok();
1044 }
1045 }
1046 })
1047 .detach();
1048
1049 language_server
1050 .on_notification::<lsp::notification::LogMessage, _>({
1051 let this = lsp_store.clone();
1052 move |params, cx| {
1053 if let Some(this) = this.upgrade() {
1054 this.update(cx, |_, cx| {
1055 cx.emit(LspStoreEvent::LanguageServerLog(
1056 server_id,
1057 LanguageServerLogType::Log(params.typ),
1058 params.message,
1059 ));
1060 })
1061 .ok();
1062 }
1063 }
1064 })
1065 .detach();
1066
1067 language_server
1068 .on_notification::<lsp::notification::LogTrace, _>({
1069 let this = lsp_store.clone();
1070 move |params, cx| {
1071 let mut cx = cx.clone();
1072 if let Some(this) = this.upgrade() {
1073 this.update(&mut cx, |_, cx| {
1074 cx.emit(LspStoreEvent::LanguageServerLog(
1075 server_id,
1076 LanguageServerLogType::Trace {
1077 verbose_info: params.verbose,
1078 },
1079 params.message,
1080 ));
1081 })
1082 .ok();
1083 }
1084 }
1085 })
1086 .detach();
1087
1088 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1089 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1090 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1091 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1092 }
1093
1094 fn shutdown_language_servers_on_quit(
1095 &mut self,
1096 _: &mut Context<LspStore>,
1097 ) -> impl Future<Output = ()> + use<> {
1098 let shutdown_futures = self
1099 .language_servers
1100 .drain()
1101 .map(|(_, server_state)| Self::shutdown_server(server_state))
1102 .collect::<Vec<_>>();
1103
1104 async move {
1105 join_all(shutdown_futures).await;
1106 }
1107 }
1108
1109 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1110 match server_state {
1111 LanguageServerState::Running { server, .. } => {
1112 if let Some(shutdown) = server.shutdown() {
1113 shutdown.await;
1114 }
1115 }
1116 LanguageServerState::Starting { startup, .. } => {
1117 if let Some(server) = startup.await
1118 && let Some(shutdown) = server.shutdown()
1119 {
1120 shutdown.await;
1121 }
1122 }
1123 }
1124 Ok(())
1125 }
1126
1127 fn language_servers_for_worktree(
1128 &self,
1129 worktree_id: WorktreeId,
1130 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1131 self.language_server_ids
1132 .iter()
1133 .filter_map(move |(seed, state)| {
1134 if seed.worktree_id != worktree_id {
1135 return None;
1136 }
1137
1138 if let Some(LanguageServerState::Running { server, .. }) =
1139 self.language_servers.get(&state.id)
1140 {
1141 Some(server)
1142 } else {
1143 None
1144 }
1145 })
1146 }
1147
1148 fn language_server_ids_for_project_path(
1149 &self,
1150 project_path: ProjectPath,
1151 language: &Language,
1152 cx: &mut App,
1153 ) -> Vec<LanguageServerId> {
1154 let Some(worktree) = self
1155 .worktree_store
1156 .read(cx)
1157 .worktree_for_id(project_path.worktree_id, cx)
1158 else {
1159 return Vec::new();
1160 };
1161 let delegate: Arc<dyn ManifestDelegate> =
1162 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1163
1164 self.lsp_tree
1165 .get(
1166 project_path,
1167 language.name(),
1168 language.manifest(),
1169 &delegate,
1170 cx,
1171 )
1172 .collect::<Vec<_>>()
1173 }
1174
1175 fn language_server_ids_for_buffer(
1176 &self,
1177 buffer: &Buffer,
1178 cx: &mut App,
1179 ) -> Vec<LanguageServerId> {
1180 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1181 let worktree_id = file.worktree_id(cx);
1182
1183 let path: Arc<RelPath> = file
1184 .path()
1185 .parent()
1186 .map(Arc::from)
1187 .unwrap_or_else(|| file.path().clone());
1188 let worktree_path = ProjectPath { worktree_id, path };
1189 self.language_server_ids_for_project_path(worktree_path, language, cx)
1190 } else {
1191 Vec::new()
1192 }
1193 }
1194
1195 fn language_servers_for_buffer<'a>(
1196 &'a self,
1197 buffer: &'a Buffer,
1198 cx: &'a mut App,
1199 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1200 self.language_server_ids_for_buffer(buffer, cx)
1201 .into_iter()
1202 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1203 LanguageServerState::Running {
1204 adapter, server, ..
1205 } => Some((adapter, server)),
1206 _ => None,
1207 })
1208 }
1209
1210 async fn execute_code_action_kind_locally(
1211 lsp_store: WeakEntity<LspStore>,
1212 mut buffers: Vec<Entity<Buffer>>,
1213 kind: CodeActionKind,
1214 push_to_history: bool,
1215 cx: &mut AsyncApp,
1216 ) -> anyhow::Result<ProjectTransaction> {
1217 // Do not allow multiple concurrent code actions requests for the
1218 // same buffer.
1219 lsp_store.update(cx, |this, cx| {
1220 let this = this.as_local_mut().unwrap();
1221 buffers.retain(|buffer| {
1222 this.buffers_being_formatted
1223 .insert(buffer.read(cx).remote_id())
1224 });
1225 })?;
1226 let _cleanup = defer({
1227 let this = lsp_store.clone();
1228 let mut cx = cx.clone();
1229 let buffers = &buffers;
1230 move || {
1231 this.update(&mut cx, |this, cx| {
1232 let this = this.as_local_mut().unwrap();
1233 for buffer in buffers {
1234 this.buffers_being_formatted
1235 .remove(&buffer.read(cx).remote_id());
1236 }
1237 })
1238 .ok();
1239 }
1240 });
1241 let mut project_transaction = ProjectTransaction::default();
1242
1243 for buffer in &buffers {
1244 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1245 buffer.update(cx, |buffer, cx| {
1246 lsp_store
1247 .as_local()
1248 .unwrap()
1249 .language_servers_for_buffer(buffer, cx)
1250 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1251 .collect::<Vec<_>>()
1252 })
1253 })?;
1254 for (_, language_server) in adapters_and_servers.iter() {
1255 let actions = Self::get_server_code_actions_from_action_kinds(
1256 &lsp_store,
1257 language_server.server_id(),
1258 vec![kind.clone()],
1259 buffer,
1260 cx,
1261 )
1262 .await?;
1263 Self::execute_code_actions_on_server(
1264 &lsp_store,
1265 language_server,
1266 actions,
1267 push_to_history,
1268 &mut project_transaction,
1269 cx,
1270 )
1271 .await?;
1272 }
1273 }
1274 Ok(project_transaction)
1275 }
1276
1277 async fn format_locally(
1278 lsp_store: WeakEntity<LspStore>,
1279 mut buffers: Vec<FormattableBuffer>,
1280 push_to_history: bool,
1281 trigger: FormatTrigger,
1282 logger: zlog::Logger,
1283 cx: &mut AsyncApp,
1284 ) -> anyhow::Result<ProjectTransaction> {
1285 // Do not allow multiple concurrent formatting requests for the
1286 // same buffer.
1287 lsp_store.update(cx, |this, cx| {
1288 let this = this.as_local_mut().unwrap();
1289 buffers.retain(|buffer| {
1290 this.buffers_being_formatted
1291 .insert(buffer.handle.read(cx).remote_id())
1292 });
1293 })?;
1294
1295 let _cleanup = defer({
1296 let this = lsp_store.clone();
1297 let mut cx = cx.clone();
1298 let buffers = &buffers;
1299 move || {
1300 this.update(&mut cx, |this, cx| {
1301 let this = this.as_local_mut().unwrap();
1302 for buffer in buffers {
1303 this.buffers_being_formatted
1304 .remove(&buffer.handle.read(cx).remote_id());
1305 }
1306 })
1307 .ok();
1308 }
1309 });
1310
1311 let mut project_transaction = ProjectTransaction::default();
1312
1313 for buffer in &buffers {
1314 zlog::debug!(
1315 logger =>
1316 "formatting buffer '{:?}'",
1317 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1318 );
1319 // Create an empty transaction to hold all of the formatting edits.
1320 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1321 // ensure no transactions created while formatting are
1322 // grouped with the previous transaction in the history
1323 // based on the transaction group interval
1324 buffer.finalize_last_transaction();
1325 buffer
1326 .start_transaction()
1327 .context("transaction already open")?;
1328 buffer.end_transaction(cx);
1329 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1330 buffer.finalize_last_transaction();
1331 anyhow::Ok(transaction_id)
1332 })??;
1333
1334 let result = Self::format_buffer_locally(
1335 lsp_store.clone(),
1336 buffer,
1337 formatting_transaction_id,
1338 trigger,
1339 logger,
1340 cx,
1341 )
1342 .await;
1343
1344 buffer.handle.update(cx, |buffer, cx| {
1345 let Some(formatting_transaction) =
1346 buffer.get_transaction(formatting_transaction_id).cloned()
1347 else {
1348 zlog::warn!(logger => "no formatting transaction");
1349 return;
1350 };
1351 if formatting_transaction.edit_ids.is_empty() {
1352 zlog::debug!(logger => "no changes made while formatting");
1353 buffer.forget_transaction(formatting_transaction_id);
1354 return;
1355 }
1356 if !push_to_history {
1357 zlog::trace!(logger => "forgetting format transaction");
1358 buffer.forget_transaction(formatting_transaction.id);
1359 }
1360 project_transaction
1361 .0
1362 .insert(cx.entity(), formatting_transaction);
1363 })?;
1364
1365 result?;
1366 }
1367
1368 Ok(project_transaction)
1369 }
1370
1371 async fn format_buffer_locally(
1372 lsp_store: WeakEntity<LspStore>,
1373 buffer: &FormattableBuffer,
1374 formatting_transaction_id: clock::Lamport,
1375 trigger: FormatTrigger,
1376 logger: zlog::Logger,
1377 cx: &mut AsyncApp,
1378 ) -> Result<()> {
1379 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1380 buffer.handle.update(cx, |buffer, cx| {
1381 let adapters_and_servers = lsp_store
1382 .as_local()
1383 .unwrap()
1384 .language_servers_for_buffer(buffer, cx)
1385 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1386 .collect::<Vec<_>>();
1387 let settings =
1388 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1389 .into_owned();
1390 (adapters_and_servers, settings)
1391 })
1392 })?;
1393
1394 /// Apply edits to the buffer that will become part of the formatting transaction.
1395 /// Fails if the buffer has been edited since the start of that transaction.
1396 fn extend_formatting_transaction(
1397 buffer: &FormattableBuffer,
1398 formatting_transaction_id: text::TransactionId,
1399 cx: &mut AsyncApp,
1400 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1401 ) -> anyhow::Result<()> {
1402 buffer.handle.update(cx, |buffer, cx| {
1403 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1404 if last_transaction_id != Some(formatting_transaction_id) {
1405 anyhow::bail!("Buffer edited while formatting. Aborting")
1406 }
1407 buffer.start_transaction();
1408 operation(buffer, cx);
1409 if let Some(transaction_id) = buffer.end_transaction(cx) {
1410 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1411 }
1412 Ok(())
1413 })?
1414 }
1415
1416 // handle whitespace formatting
1417 if settings.remove_trailing_whitespace_on_save {
1418 zlog::trace!(logger => "removing trailing whitespace");
1419 let diff = buffer
1420 .handle
1421 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1422 .await;
1423 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1424 buffer.apply_diff(diff, cx);
1425 })?;
1426 }
1427
1428 if settings.ensure_final_newline_on_save {
1429 zlog::trace!(logger => "ensuring final newline");
1430 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1431 buffer.ensure_final_newline(cx);
1432 })?;
1433 }
1434
1435 // Formatter for `code_actions_on_format` that runs before
1436 // the rest of the formatters
1437 let mut code_actions_on_format_formatters = None;
1438 let should_run_code_actions_on_format = !matches!(
1439 (trigger, &settings.format_on_save),
1440 (FormatTrigger::Save, &FormatOnSave::Off)
1441 );
1442 if should_run_code_actions_on_format {
1443 let have_code_actions_to_run_on_format = settings
1444 .code_actions_on_format
1445 .values()
1446 .any(|enabled| *enabled);
1447 if have_code_actions_to_run_on_format {
1448 zlog::trace!(logger => "going to run code actions on format");
1449 code_actions_on_format_formatters = Some(
1450 settings
1451 .code_actions_on_format
1452 .iter()
1453 .filter_map(|(action, enabled)| enabled.then_some(action))
1454 .cloned()
1455 .map(Formatter::CodeAction)
1456 .collect::<Vec<_>>(),
1457 );
1458 }
1459 }
1460
1461 let formatters = match (trigger, &settings.format_on_save) {
1462 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1463 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1464 settings.formatter.as_ref()
1465 }
1466 };
1467
1468 let formatters = code_actions_on_format_formatters
1469 .iter()
1470 .flatten()
1471 .chain(formatters);
1472
1473 for formatter in formatters {
1474 let formatter = if formatter == &Formatter::Auto {
1475 if settings.prettier.allowed {
1476 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1477 &Formatter::Prettier
1478 } else {
1479 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1480 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1481 }
1482 } else {
1483 formatter
1484 };
1485 match formatter {
1486 Formatter::Auto => unreachable!("Auto resolved above"),
1487 Formatter::Prettier => {
1488 let logger = zlog::scoped!(logger => "prettier");
1489 zlog::trace!(logger => "formatting");
1490 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1491
1492 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1493 lsp_store.prettier_store().unwrap().downgrade()
1494 })?;
1495 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1496 .await
1497 .transpose()?;
1498 let Some(diff) = diff else {
1499 zlog::trace!(logger => "No changes");
1500 continue;
1501 };
1502
1503 extend_formatting_transaction(
1504 buffer,
1505 formatting_transaction_id,
1506 cx,
1507 |buffer, cx| {
1508 buffer.apply_diff(diff, cx);
1509 },
1510 )?;
1511 }
1512 Formatter::External { command, arguments } => {
1513 let logger = zlog::scoped!(logger => "command");
1514 zlog::trace!(logger => "formatting");
1515 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1516
1517 let diff = Self::format_via_external_command(
1518 buffer,
1519 command.as_ref(),
1520 arguments.as_deref(),
1521 cx,
1522 )
1523 .await
1524 .with_context(|| {
1525 format!("Failed to format buffer via external command: {}", command)
1526 })?;
1527 let Some(diff) = diff else {
1528 zlog::trace!(logger => "No changes");
1529 continue;
1530 };
1531
1532 extend_formatting_transaction(
1533 buffer,
1534 formatting_transaction_id,
1535 cx,
1536 |buffer, cx| {
1537 buffer.apply_diff(diff, cx);
1538 },
1539 )?;
1540 }
1541 Formatter::LanguageServer(specifier) => {
1542 let logger = zlog::scoped!(logger => "language-server");
1543 zlog::trace!(logger => "formatting");
1544 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1545
1546 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1547 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1548 continue;
1549 };
1550
1551 let language_server = match specifier {
1552 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1553 adapters_and_servers.iter().find_map(|(adapter, server)| {
1554 if adapter.name.0.as_ref() == name {
1555 Some(server.clone())
1556 } else {
1557 None
1558 }
1559 })
1560 }
1561 settings::LanguageServerFormatterSpecifier::Current => {
1562 adapters_and_servers.first().map(|e| e.1.clone())
1563 }
1564 };
1565
1566 let Some(language_server) = language_server else {
1567 log::debug!(
1568 "No language server found to format buffer '{:?}'. Skipping",
1569 buffer_path_abs.as_path().to_string_lossy()
1570 );
1571 continue;
1572 };
1573
1574 zlog::trace!(
1575 logger =>
1576 "Formatting buffer '{:?}' using language server '{:?}'",
1577 buffer_path_abs.as_path().to_string_lossy(),
1578 language_server.name()
1579 );
1580
1581 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1582 zlog::trace!(logger => "formatting ranges");
1583 Self::format_ranges_via_lsp(
1584 &lsp_store,
1585 &buffer.handle,
1586 ranges,
1587 buffer_path_abs,
1588 &language_server,
1589 &settings,
1590 cx,
1591 )
1592 .await
1593 .context("Failed to format ranges via language server")?
1594 } else {
1595 zlog::trace!(logger => "formatting full");
1596 Self::format_via_lsp(
1597 &lsp_store,
1598 &buffer.handle,
1599 buffer_path_abs,
1600 &language_server,
1601 &settings,
1602 cx,
1603 )
1604 .await
1605 .context("failed to format via language server")?
1606 };
1607
1608 if edits.is_empty() {
1609 zlog::trace!(logger => "No changes");
1610 continue;
1611 }
1612 extend_formatting_transaction(
1613 buffer,
1614 formatting_transaction_id,
1615 cx,
1616 |buffer, cx| {
1617 buffer.edit(edits, None, cx);
1618 },
1619 )?;
1620 }
1621 Formatter::CodeAction(code_action_name) => {
1622 let logger = zlog::scoped!(logger => "code-actions");
1623 zlog::trace!(logger => "formatting");
1624 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1625
1626 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1627 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1628 continue;
1629 };
1630
1631 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1632 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1633
1634 let mut actions_and_servers = Vec::new();
1635
1636 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1637 let actions_result = Self::get_server_code_actions_from_action_kinds(
1638 &lsp_store,
1639 language_server.server_id(),
1640 vec![code_action_kind.clone()],
1641 &buffer.handle,
1642 cx,
1643 )
1644 .await
1645 .with_context(|| {
1646 format!(
1647 "Failed to resolve code action {:?} with language server {}",
1648 code_action_kind,
1649 language_server.name()
1650 )
1651 });
1652 let Ok(actions) = actions_result else {
1653 // note: it may be better to set result to the error and break formatters here
1654 // but for now we try to execute the actions that we can resolve and skip the rest
1655 zlog::error!(
1656 logger =>
1657 "Failed to resolve code action {:?} with language server {}",
1658 code_action_kind,
1659 language_server.name()
1660 );
1661 continue;
1662 };
1663 for action in actions {
1664 actions_and_servers.push((action, index));
1665 }
1666 }
1667
1668 if actions_and_servers.is_empty() {
1669 zlog::warn!(logger => "No code actions were resolved, continuing");
1670 continue;
1671 }
1672
1673 'actions: for (mut action, server_index) in actions_and_servers {
1674 let server = &adapters_and_servers[server_index].1;
1675
1676 let describe_code_action = |action: &CodeAction| {
1677 format!(
1678 "code action '{}' with title \"{}\" on server {}",
1679 action
1680 .lsp_action
1681 .action_kind()
1682 .unwrap_or("unknown".into())
1683 .as_str(),
1684 action.lsp_action.title(),
1685 server.name(),
1686 )
1687 };
1688
1689 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1690
1691 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1692 zlog::error!(
1693 logger =>
1694 "Failed to resolve {}. Error: {}",
1695 describe_code_action(&action),
1696 err
1697 );
1698 continue;
1699 }
1700
1701 if let Some(edit) = action.lsp_action.edit().cloned() {
1702 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1703 // but filters out and logs warnings for code actions that require unreasonably
1704 // difficult handling on our part, such as:
1705 // - applying edits that call commands
1706 // which can result in arbitrary workspace edits being sent from the server that
1707 // have no way of being tied back to the command that initiated them (i.e. we
1708 // can't know which edits are part of the format request, or if the server is done sending
1709 // actions in response to the command)
1710 // - actions that create/delete/modify/rename files other than the one we are formatting
1711 // as we then would need to handle such changes correctly in the local history as well
1712 // as the remote history through the ProjectTransaction
1713 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1714 // Supporting these actions is not impossible, but not supported as of yet.
1715 if edit.changes.is_none() && edit.document_changes.is_none() {
1716 zlog::trace!(
1717 logger =>
1718 "No changes for code action. Skipping {}",
1719 describe_code_action(&action),
1720 );
1721 continue;
1722 }
1723
1724 let mut operations = Vec::new();
1725 if let Some(document_changes) = edit.document_changes {
1726 match document_changes {
1727 lsp::DocumentChanges::Edits(edits) => operations.extend(
1728 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1729 ),
1730 lsp::DocumentChanges::Operations(ops) => operations = ops,
1731 }
1732 } else if let Some(changes) = edit.changes {
1733 operations.extend(changes.into_iter().map(|(uri, edits)| {
1734 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1735 text_document:
1736 lsp::OptionalVersionedTextDocumentIdentifier {
1737 uri,
1738 version: None,
1739 },
1740 edits: edits.into_iter().map(Edit::Plain).collect(),
1741 })
1742 }));
1743 }
1744
1745 let mut edits = Vec::with_capacity(operations.len());
1746
1747 if operations.is_empty() {
1748 zlog::trace!(
1749 logger =>
1750 "No changes for code action. Skipping {}",
1751 describe_code_action(&action),
1752 );
1753 continue;
1754 }
1755 for operation in operations {
1756 let op = match operation {
1757 lsp::DocumentChangeOperation::Edit(op) => op,
1758 lsp::DocumentChangeOperation::Op(_) => {
1759 zlog::warn!(
1760 logger =>
1761 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1762 describe_code_action(&action),
1763 );
1764 continue 'actions;
1765 }
1766 };
1767 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1768 zlog::warn!(
1769 logger =>
1770 "Failed to convert URI '{:?}' to file path. Skipping {}",
1771 &op.text_document.uri,
1772 describe_code_action(&action),
1773 );
1774 continue 'actions;
1775 };
1776 if &file_path != buffer_path_abs {
1777 zlog::warn!(
1778 logger =>
1779 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1780 file_path,
1781 buffer_path_abs,
1782 describe_code_action(&action),
1783 );
1784 continue 'actions;
1785 }
1786
1787 let mut lsp_edits = Vec::new();
1788 for edit in op.edits {
1789 match edit {
1790 Edit::Plain(edit) => {
1791 if !lsp_edits.contains(&edit) {
1792 lsp_edits.push(edit);
1793 }
1794 }
1795 Edit::Annotated(edit) => {
1796 if !lsp_edits.contains(&edit.text_edit) {
1797 lsp_edits.push(edit.text_edit);
1798 }
1799 }
1800 Edit::Snippet(_) => {
1801 zlog::warn!(
1802 logger =>
1803 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1804 describe_code_action(&action),
1805 );
1806 continue 'actions;
1807 }
1808 }
1809 }
1810 let edits_result = lsp_store
1811 .update(cx, |lsp_store, cx| {
1812 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1813 &buffer.handle,
1814 lsp_edits,
1815 server.server_id(),
1816 op.text_document.version,
1817 cx,
1818 )
1819 })?
1820 .await;
1821 let Ok(resolved_edits) = edits_result else {
1822 zlog::warn!(
1823 logger =>
1824 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1825 buffer_path_abs.as_path(),
1826 describe_code_action(&action),
1827 );
1828 continue 'actions;
1829 };
1830 edits.extend(resolved_edits);
1831 }
1832
1833 if edits.is_empty() {
1834 zlog::warn!(logger => "No edits resolved from LSP");
1835 continue;
1836 }
1837
1838 extend_formatting_transaction(
1839 buffer,
1840 formatting_transaction_id,
1841 cx,
1842 |buffer, cx| {
1843 zlog::info!(
1844 "Applying edits {edits:?}. Content: {:?}",
1845 buffer.text()
1846 );
1847 buffer.edit(edits, None, cx);
1848 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1849 },
1850 )?;
1851 }
1852
1853 if let Some(command) = action.lsp_action.command() {
1854 zlog::warn!(
1855 logger =>
1856 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1857 &command.command,
1858 );
1859
1860 // bail early if command is invalid
1861 let server_capabilities = server.capabilities();
1862 let available_commands = server_capabilities
1863 .execute_command_provider
1864 .as_ref()
1865 .map(|options| options.commands.as_slice())
1866 .unwrap_or_default();
1867 if !available_commands.contains(&command.command) {
1868 zlog::warn!(
1869 logger =>
1870 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1871 command.command,
1872 server.name(),
1873 );
1874 continue;
1875 }
1876
1877 // noop so we just ensure buffer hasn't been edited since resolving code actions
1878 extend_formatting_transaction(
1879 buffer,
1880 formatting_transaction_id,
1881 cx,
1882 |_, _| {},
1883 )?;
1884 zlog::info!(logger => "Executing command {}", &command.command);
1885
1886 lsp_store.update(cx, |this, _| {
1887 this.as_local_mut()
1888 .unwrap()
1889 .last_workspace_edits_by_language_server
1890 .remove(&server.server_id());
1891 })?;
1892
1893 let execute_command_result = server
1894 .request::<lsp::request::ExecuteCommand>(
1895 lsp::ExecuteCommandParams {
1896 command: command.command.clone(),
1897 arguments: command.arguments.clone().unwrap_or_default(),
1898 ..Default::default()
1899 },
1900 )
1901 .await
1902 .into_response();
1903
1904 if execute_command_result.is_err() {
1905 zlog::error!(
1906 logger =>
1907 "Failed to execute command '{}' as part of {}",
1908 &command.command,
1909 describe_code_action(&action),
1910 );
1911 continue 'actions;
1912 }
1913
1914 let mut project_transaction_command =
1915 lsp_store.update(cx, |this, _| {
1916 this.as_local_mut()
1917 .unwrap()
1918 .last_workspace_edits_by_language_server
1919 .remove(&server.server_id())
1920 .unwrap_or_default()
1921 })?;
1922
1923 if let Some(transaction) =
1924 project_transaction_command.0.remove(&buffer.handle)
1925 {
1926 zlog::trace!(
1927 logger =>
1928 "Successfully captured {} edits that resulted from command {}",
1929 transaction.edit_ids.len(),
1930 &command.command,
1931 );
1932 let transaction_id_project_transaction = transaction.id;
1933 buffer.handle.update(cx, |buffer, _| {
1934 // it may have been removed from history if push_to_history was
1935 // false in deserialize_workspace_edit. If so push it so we
1936 // can merge it with the format transaction
1937 // and pop the combined transaction off the history stack
1938 // later if push_to_history is false
1939 if buffer.get_transaction(transaction.id).is_none() {
1940 buffer.push_transaction(transaction, Instant::now());
1941 }
1942 buffer.merge_transactions(
1943 transaction_id_project_transaction,
1944 formatting_transaction_id,
1945 );
1946 })?;
1947 }
1948
1949 if !project_transaction_command.0.is_empty() {
1950 let mut extra_buffers = String::new();
1951 for buffer in project_transaction_command.0.keys() {
1952 buffer
1953 .read_with(cx, |b, cx| {
1954 if let Some(path) = b.project_path(cx) {
1955 if !extra_buffers.is_empty() {
1956 extra_buffers.push_str(", ");
1957 }
1958 extra_buffers.push_str(path.path.as_unix_str());
1959 }
1960 })
1961 .ok();
1962 }
1963 zlog::warn!(
1964 logger =>
1965 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1966 &command.command,
1967 extra_buffers,
1968 );
1969 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1970 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1971 // add it so it's included, and merge it into the format transaction when its created later
1972 }
1973 }
1974 }
1975 }
1976 }
1977 }
1978
1979 Ok(())
1980 }
1981
1982 pub async fn format_ranges_via_lsp(
1983 this: &WeakEntity<LspStore>,
1984 buffer_handle: &Entity<Buffer>,
1985 ranges: &[Range<Anchor>],
1986 abs_path: &Path,
1987 language_server: &Arc<LanguageServer>,
1988 settings: &LanguageSettings,
1989 cx: &mut AsyncApp,
1990 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1991 let capabilities = &language_server.capabilities();
1992 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1993 if range_formatting_provider == Some(&OneOf::Left(false)) {
1994 anyhow::bail!(
1995 "{} language server does not support range formatting",
1996 language_server.name()
1997 );
1998 }
1999
2000 let uri = file_path_to_lsp_url(abs_path)?;
2001 let text_document = lsp::TextDocumentIdentifier::new(uri);
2002
2003 let lsp_edits = {
2004 let mut lsp_ranges = Vec::new();
2005 this.update(cx, |_this, cx| {
2006 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2007 // not have been sent to the language server. This seems like a fairly systemic
2008 // issue, though, the resolution probably is not specific to formatting.
2009 //
2010 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2011 // LSP.
2012 let snapshot = buffer_handle.read(cx).snapshot();
2013 for range in ranges {
2014 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2015 }
2016 anyhow::Ok(())
2017 })??;
2018
2019 let mut edits = None;
2020 for range in lsp_ranges {
2021 if let Some(mut edit) = language_server
2022 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2023 text_document: text_document.clone(),
2024 range,
2025 options: lsp_command::lsp_formatting_options(settings),
2026 work_done_progress_params: Default::default(),
2027 })
2028 .await
2029 .into_response()?
2030 {
2031 edits.get_or_insert_with(Vec::new).append(&mut edit);
2032 }
2033 }
2034 edits
2035 };
2036
2037 if let Some(lsp_edits) = lsp_edits {
2038 this.update(cx, |this, cx| {
2039 this.as_local_mut().unwrap().edits_from_lsp(
2040 buffer_handle,
2041 lsp_edits,
2042 language_server.server_id(),
2043 None,
2044 cx,
2045 )
2046 })?
2047 .await
2048 } else {
2049 Ok(Vec::with_capacity(0))
2050 }
2051 }
2052
2053 async fn format_via_lsp(
2054 this: &WeakEntity<LspStore>,
2055 buffer: &Entity<Buffer>,
2056 abs_path: &Path,
2057 language_server: &Arc<LanguageServer>,
2058 settings: &LanguageSettings,
2059 cx: &mut AsyncApp,
2060 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2061 let logger = zlog::scoped!("lsp_format");
2062 zlog::debug!(logger => "Formatting via LSP");
2063
2064 let uri = file_path_to_lsp_url(abs_path)?;
2065 let text_document = lsp::TextDocumentIdentifier::new(uri);
2066 let capabilities = &language_server.capabilities();
2067
2068 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2069 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2070
2071 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2072 let _timer = zlog::time!(logger => "format-full");
2073 language_server
2074 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2075 text_document,
2076 options: lsp_command::lsp_formatting_options(settings),
2077 work_done_progress_params: Default::default(),
2078 })
2079 .await
2080 .into_response()?
2081 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2082 let _timer = zlog::time!(logger => "format-range");
2083 let buffer_start = lsp::Position::new(0, 0);
2084 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2085 language_server
2086 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2087 text_document: text_document.clone(),
2088 range: lsp::Range::new(buffer_start, buffer_end),
2089 options: lsp_command::lsp_formatting_options(settings),
2090 work_done_progress_params: Default::default(),
2091 })
2092 .await
2093 .into_response()?
2094 } else {
2095 None
2096 };
2097
2098 if let Some(lsp_edits) = lsp_edits {
2099 this.update(cx, |this, cx| {
2100 this.as_local_mut().unwrap().edits_from_lsp(
2101 buffer,
2102 lsp_edits,
2103 language_server.server_id(),
2104 None,
2105 cx,
2106 )
2107 })?
2108 .await
2109 } else {
2110 Ok(Vec::with_capacity(0))
2111 }
2112 }
2113
2114 async fn format_via_external_command(
2115 buffer: &FormattableBuffer,
2116 command: &str,
2117 arguments: Option<&[String]>,
2118 cx: &mut AsyncApp,
2119 ) -> Result<Option<Diff>> {
2120 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2121 let file = File::from_dyn(buffer.file())?;
2122 let worktree = file.worktree.read(cx);
2123 let mut worktree_path = worktree.abs_path().to_path_buf();
2124 if worktree.root_entry()?.is_file() {
2125 worktree_path.pop();
2126 }
2127 Some(worktree_path)
2128 })?;
2129
2130 let mut child = util::command::new_smol_command(command);
2131
2132 if let Some(buffer_env) = buffer.env.as_ref() {
2133 child.envs(buffer_env);
2134 }
2135
2136 if let Some(working_dir_path) = working_dir_path {
2137 child.current_dir(working_dir_path);
2138 }
2139
2140 if let Some(arguments) = arguments {
2141 child.args(arguments.iter().map(|arg| {
2142 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2143 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2144 } else {
2145 arg.replace("{buffer_path}", "Untitled")
2146 }
2147 }));
2148 }
2149
2150 let mut child = child
2151 .stdin(smol::process::Stdio::piped())
2152 .stdout(smol::process::Stdio::piped())
2153 .stderr(smol::process::Stdio::piped())
2154 .spawn()?;
2155
2156 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2157 let text = buffer
2158 .handle
2159 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2160 for chunk in text.chunks() {
2161 stdin.write_all(chunk.as_bytes()).await?;
2162 }
2163 stdin.flush().await?;
2164
2165 let output = child.output().await?;
2166 anyhow::ensure!(
2167 output.status.success(),
2168 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2169 output.status.code(),
2170 String::from_utf8_lossy(&output.stdout),
2171 String::from_utf8_lossy(&output.stderr),
2172 );
2173
2174 let stdout = String::from_utf8(output.stdout)?;
2175 Ok(Some(
2176 buffer
2177 .handle
2178 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2179 .await,
2180 ))
2181 }
2182
2183 async fn try_resolve_code_action(
2184 lang_server: &LanguageServer,
2185 action: &mut CodeAction,
2186 ) -> anyhow::Result<()> {
2187 match &mut action.lsp_action {
2188 LspAction::Action(lsp_action) => {
2189 if !action.resolved
2190 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2191 && lsp_action.data.is_some()
2192 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2193 {
2194 *lsp_action = Box::new(
2195 lang_server
2196 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2197 .await
2198 .into_response()?,
2199 );
2200 }
2201 }
2202 LspAction::CodeLens(lens) => {
2203 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2204 *lens = lang_server
2205 .request::<lsp::request::CodeLensResolve>(lens.clone())
2206 .await
2207 .into_response()?;
2208 }
2209 }
2210 LspAction::Command(_) => {}
2211 }
2212
2213 action.resolved = true;
2214 anyhow::Ok(())
2215 }
2216
2217 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2218 let buffer = buffer_handle.read(cx);
2219
2220 let file = buffer.file().cloned();
2221
2222 let Some(file) = File::from_dyn(file.as_ref()) else {
2223 return;
2224 };
2225 if !file.is_local() {
2226 return;
2227 }
2228 let path = ProjectPath::from_file(file, cx);
2229 let worktree_id = file.worktree_id(cx);
2230 let language = buffer.language().cloned();
2231
2232 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2233 for (server_id, diagnostics) in
2234 diagnostics.get(file.path()).cloned().unwrap_or_default()
2235 {
2236 self.update_buffer_diagnostics(
2237 buffer_handle,
2238 server_id,
2239 None,
2240 None,
2241 diagnostics,
2242 Vec::new(),
2243 cx,
2244 )
2245 .log_err();
2246 }
2247 }
2248 let Some(language) = language else {
2249 return;
2250 };
2251 let Some(snapshot) = self
2252 .worktree_store
2253 .read(cx)
2254 .worktree_for_id(worktree_id, cx)
2255 .map(|worktree| worktree.read(cx).snapshot())
2256 else {
2257 return;
2258 };
2259 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2260
2261 for server_id in
2262 self.lsp_tree
2263 .get(path, language.name(), language.manifest(), &delegate, cx)
2264 {
2265 let server = self
2266 .language_servers
2267 .get(&server_id)
2268 .and_then(|server_state| {
2269 if let LanguageServerState::Running { server, .. } = server_state {
2270 Some(server.clone())
2271 } else {
2272 None
2273 }
2274 });
2275 let server = match server {
2276 Some(server) => server,
2277 None => continue,
2278 };
2279
2280 buffer_handle.update(cx, |buffer, cx| {
2281 buffer.set_completion_triggers(
2282 server.server_id(),
2283 server
2284 .capabilities()
2285 .completion_provider
2286 .as_ref()
2287 .and_then(|provider| {
2288 provider
2289 .trigger_characters
2290 .as_ref()
2291 .map(|characters| characters.iter().cloned().collect())
2292 })
2293 .unwrap_or_default(),
2294 cx,
2295 );
2296 });
2297 }
2298 }
2299
2300 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2301 buffer.update(cx, |buffer, cx| {
2302 let Some(language) = buffer.language() else {
2303 return;
2304 };
2305 let path = ProjectPath {
2306 worktree_id: old_file.worktree_id(cx),
2307 path: old_file.path.clone(),
2308 };
2309 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2310 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2311 buffer.set_completion_triggers(server_id, Default::default(), cx);
2312 }
2313 });
2314 }
2315
2316 fn update_buffer_diagnostics(
2317 &mut self,
2318 buffer: &Entity<Buffer>,
2319 server_id: LanguageServerId,
2320 result_id: Option<String>,
2321 version: Option<i32>,
2322 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2323 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2324 cx: &mut Context<LspStore>,
2325 ) -> Result<()> {
2326 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2327 Ordering::Equal
2328 .then_with(|| b.is_primary.cmp(&a.is_primary))
2329 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2330 .then_with(|| a.severity.cmp(&b.severity))
2331 .then_with(|| a.message.cmp(&b.message))
2332 }
2333
2334 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2335 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2336 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2337
2338 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2339 Ordering::Equal
2340 .then_with(|| a.range.start.cmp(&b.range.start))
2341 .then_with(|| b.range.end.cmp(&a.range.end))
2342 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2343 });
2344
2345 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2346
2347 let edits_since_save = std::cell::LazyCell::new(|| {
2348 let saved_version = buffer.read(cx).saved_version();
2349 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2350 });
2351
2352 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2353
2354 for (new_diagnostic, entry) in diagnostics {
2355 let start;
2356 let end;
2357 if new_diagnostic && entry.diagnostic.is_disk_based {
2358 // Some diagnostics are based on files on disk instead of buffers'
2359 // current contents. Adjust these diagnostics' ranges to reflect
2360 // any unsaved edits.
2361 // Do not alter the reused ones though, as their coordinates were stored as anchors
2362 // and were properly adjusted on reuse.
2363 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2364 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2365 } else {
2366 start = entry.range.start;
2367 end = entry.range.end;
2368 }
2369
2370 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2371 ..snapshot.clip_point_utf16(end, Bias::Right);
2372
2373 // Expand empty ranges by one codepoint
2374 if range.start == range.end {
2375 // This will be go to the next boundary when being clipped
2376 range.end.column += 1;
2377 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2378 if range.start == range.end && range.end.column > 0 {
2379 range.start.column -= 1;
2380 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2381 }
2382 }
2383
2384 sanitized_diagnostics.push(DiagnosticEntry {
2385 range,
2386 diagnostic: entry.diagnostic,
2387 });
2388 }
2389 drop(edits_since_save);
2390
2391 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2392 buffer.update(cx, |buffer, cx| {
2393 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2394 self.buffer_pull_diagnostics_result_ids
2395 .entry(server_id)
2396 .or_default()
2397 .insert(abs_path, result_id);
2398 }
2399
2400 buffer.update_diagnostics(server_id, set, cx)
2401 });
2402
2403 Ok(())
2404 }
2405
2406 fn register_language_server_for_invisible_worktree(
2407 &mut self,
2408 worktree: &Entity<Worktree>,
2409 language_server_id: LanguageServerId,
2410 cx: &mut App,
2411 ) {
2412 let worktree = worktree.read(cx);
2413 let worktree_id = worktree.id();
2414 debug_assert!(!worktree.is_visible());
2415 let Some(mut origin_seed) = self
2416 .language_server_ids
2417 .iter()
2418 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2419 else {
2420 return;
2421 };
2422 origin_seed.worktree_id = worktree_id;
2423 self.language_server_ids
2424 .entry(origin_seed)
2425 .or_insert_with(|| UnifiedLanguageServer {
2426 id: language_server_id,
2427 project_roots: Default::default(),
2428 });
2429 }
2430
2431 fn register_buffer_with_language_servers(
2432 &mut self,
2433 buffer_handle: &Entity<Buffer>,
2434 only_register_servers: HashSet<LanguageServerSelector>,
2435 cx: &mut Context<LspStore>,
2436 ) {
2437 let buffer = buffer_handle.read(cx);
2438 let buffer_id = buffer.remote_id();
2439
2440 let Some(file) = File::from_dyn(buffer.file()) else {
2441 return;
2442 };
2443 if !file.is_local() {
2444 return;
2445 }
2446
2447 let abs_path = file.abs_path(cx);
2448 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2449 return;
2450 };
2451 let initial_snapshot = buffer.text_snapshot();
2452 let worktree_id = file.worktree_id(cx);
2453
2454 let Some(language) = buffer.language().cloned() else {
2455 return;
2456 };
2457 let path: Arc<RelPath> = file
2458 .path()
2459 .parent()
2460 .map(Arc::from)
2461 .unwrap_or_else(|| file.path().clone());
2462 let Some(worktree) = self
2463 .worktree_store
2464 .read(cx)
2465 .worktree_for_id(worktree_id, cx)
2466 else {
2467 return;
2468 };
2469 let language_name = language.name();
2470 let (reused, delegate, servers) = self
2471 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2472 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2473 .unwrap_or_else(|| {
2474 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2475 let delegate: Arc<dyn ManifestDelegate> =
2476 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2477
2478 let servers = self
2479 .lsp_tree
2480 .walk(
2481 ProjectPath { worktree_id, path },
2482 language.name(),
2483 language.manifest(),
2484 &delegate,
2485 cx,
2486 )
2487 .collect::<Vec<_>>();
2488 (false, lsp_delegate, servers)
2489 });
2490 let servers_and_adapters = servers
2491 .into_iter()
2492 .filter_map(|server_node| {
2493 if reused && server_node.server_id().is_none() {
2494 return None;
2495 }
2496 if !only_register_servers.is_empty() {
2497 if let Some(server_id) = server_node.server_id()
2498 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2499 {
2500 return None;
2501 }
2502 if let Some(name) = server_node.name()
2503 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2504 {
2505 return None;
2506 }
2507 }
2508
2509 let server_id = server_node.server_id_or_init(|disposition| {
2510 let path = &disposition.path;
2511
2512 {
2513 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2514
2515 let server_id = self.get_or_insert_language_server(
2516 &worktree,
2517 delegate.clone(),
2518 disposition,
2519 &language_name,
2520 cx,
2521 );
2522
2523 if let Some(state) = self.language_servers.get(&server_id)
2524 && let Ok(uri) = uri
2525 {
2526 state.add_workspace_folder(uri);
2527 };
2528 server_id
2529 }
2530 })?;
2531 let server_state = self.language_servers.get(&server_id)?;
2532 if let LanguageServerState::Running {
2533 server, adapter, ..
2534 } = server_state
2535 {
2536 Some((server.clone(), adapter.clone()))
2537 } else {
2538 None
2539 }
2540 })
2541 .collect::<Vec<_>>();
2542 for (server, adapter) in servers_and_adapters {
2543 buffer_handle.update(cx, |buffer, cx| {
2544 buffer.set_completion_triggers(
2545 server.server_id(),
2546 server
2547 .capabilities()
2548 .completion_provider
2549 .as_ref()
2550 .and_then(|provider| {
2551 provider
2552 .trigger_characters
2553 .as_ref()
2554 .map(|characters| characters.iter().cloned().collect())
2555 })
2556 .unwrap_or_default(),
2557 cx,
2558 );
2559 });
2560
2561 let snapshot = LspBufferSnapshot {
2562 version: 0,
2563 snapshot: initial_snapshot.clone(),
2564 };
2565
2566 let mut registered = false;
2567 self.buffer_snapshots
2568 .entry(buffer_id)
2569 .or_default()
2570 .entry(server.server_id())
2571 .or_insert_with(|| {
2572 registered = true;
2573 server.register_buffer(
2574 uri.clone(),
2575 adapter.language_id(&language.name()),
2576 0,
2577 initial_snapshot.text(),
2578 );
2579
2580 vec![snapshot]
2581 });
2582
2583 self.buffers_opened_in_servers
2584 .entry(buffer_id)
2585 .or_default()
2586 .insert(server.server_id());
2587 if registered {
2588 cx.emit(LspStoreEvent::LanguageServerUpdate {
2589 language_server_id: server.server_id(),
2590 name: None,
2591 message: proto::update_language_server::Variant::RegisteredForBuffer(
2592 proto::RegisteredForBuffer {
2593 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2594 buffer_id: buffer_id.to_proto(),
2595 },
2596 ),
2597 });
2598 }
2599 }
2600 }
2601
2602 fn reuse_existing_language_server<'lang_name>(
2603 &self,
2604 server_tree: &LanguageServerTree,
2605 worktree: &Entity<Worktree>,
2606 language_name: &'lang_name LanguageName,
2607 cx: &mut App,
2608 ) -> Option<(
2609 Arc<LocalLspAdapterDelegate>,
2610 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2611 )> {
2612 if worktree.read(cx).is_visible() {
2613 return None;
2614 }
2615
2616 let worktree_store = self.worktree_store.read(cx);
2617 let servers = server_tree
2618 .instances
2619 .iter()
2620 .filter(|(worktree_id, _)| {
2621 worktree_store
2622 .worktree_for_id(**worktree_id, cx)
2623 .is_some_and(|worktree| worktree.read(cx).is_visible())
2624 })
2625 .flat_map(|(worktree_id, servers)| {
2626 servers
2627 .roots
2628 .iter()
2629 .flat_map(|(_, language_servers)| language_servers)
2630 .map(move |(_, (server_node, server_languages))| {
2631 (worktree_id, server_node, server_languages)
2632 })
2633 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2634 .map(|(worktree_id, server_node, _)| {
2635 (
2636 *worktree_id,
2637 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2638 )
2639 })
2640 })
2641 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2642 acc.entry(worktree_id)
2643 .or_insert_with(Vec::new)
2644 .push(server_node);
2645 acc
2646 })
2647 .into_values()
2648 .max_by_key(|servers| servers.len())?;
2649
2650 let worktree_id = worktree.read(cx).id();
2651 let apply = move |tree: &mut LanguageServerTree| {
2652 for server_node in &servers {
2653 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2654 }
2655 servers
2656 };
2657
2658 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2659 Some((delegate, apply))
2660 }
2661
2662 pub(crate) fn unregister_old_buffer_from_language_servers(
2663 &mut self,
2664 buffer: &Entity<Buffer>,
2665 old_file: &File,
2666 cx: &mut App,
2667 ) {
2668 let old_path = match old_file.as_local() {
2669 Some(local) => local.abs_path(cx),
2670 None => return,
2671 };
2672
2673 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2674 debug_panic!("{old_path:?} is not parseable as an URI");
2675 return;
2676 };
2677 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2678 }
2679
2680 pub(crate) fn unregister_buffer_from_language_servers(
2681 &mut self,
2682 buffer: &Entity<Buffer>,
2683 file_url: &lsp::Uri,
2684 cx: &mut App,
2685 ) {
2686 buffer.update(cx, |buffer, cx| {
2687 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2688
2689 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2690 if snapshots
2691 .as_mut()
2692 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2693 {
2694 language_server.unregister_buffer(file_url.clone());
2695 }
2696 }
2697 });
2698 }
2699
2700 fn buffer_snapshot_for_lsp_version(
2701 &mut self,
2702 buffer: &Entity<Buffer>,
2703 server_id: LanguageServerId,
2704 version: Option<i32>,
2705 cx: &App,
2706 ) -> Result<TextBufferSnapshot> {
2707 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2708
2709 if let Some(version) = version {
2710 let buffer_id = buffer.read(cx).remote_id();
2711 let snapshots = if let Some(snapshots) = self
2712 .buffer_snapshots
2713 .get_mut(&buffer_id)
2714 .and_then(|m| m.get_mut(&server_id))
2715 {
2716 snapshots
2717 } else if version == 0 {
2718 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2719 // We detect this case and treat it as if the version was `None`.
2720 return Ok(buffer.read(cx).text_snapshot());
2721 } else {
2722 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2723 };
2724
2725 let found_snapshot = snapshots
2726 .binary_search_by_key(&version, |e| e.version)
2727 .map(|ix| snapshots[ix].snapshot.clone())
2728 .map_err(|_| {
2729 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2730 })?;
2731
2732 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2733 Ok(found_snapshot)
2734 } else {
2735 Ok((buffer.read(cx)).text_snapshot())
2736 }
2737 }
2738
2739 async fn get_server_code_actions_from_action_kinds(
2740 lsp_store: &WeakEntity<LspStore>,
2741 language_server_id: LanguageServerId,
2742 code_action_kinds: Vec<lsp::CodeActionKind>,
2743 buffer: &Entity<Buffer>,
2744 cx: &mut AsyncApp,
2745 ) -> Result<Vec<CodeAction>> {
2746 let actions = lsp_store
2747 .update(cx, move |this, cx| {
2748 let request = GetCodeActions {
2749 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2750 kinds: Some(code_action_kinds),
2751 };
2752 let server = LanguageServerToQuery::Other(language_server_id);
2753 this.request_lsp(buffer.clone(), server, request, cx)
2754 })?
2755 .await?;
2756 Ok(actions)
2757 }
2758
2759 pub async fn execute_code_actions_on_server(
2760 lsp_store: &WeakEntity<LspStore>,
2761 language_server: &Arc<LanguageServer>,
2762
2763 actions: Vec<CodeAction>,
2764 push_to_history: bool,
2765 project_transaction: &mut ProjectTransaction,
2766 cx: &mut AsyncApp,
2767 ) -> anyhow::Result<()> {
2768 for mut action in actions {
2769 Self::try_resolve_code_action(language_server, &mut action)
2770 .await
2771 .context("resolving a formatting code action")?;
2772
2773 if let Some(edit) = action.lsp_action.edit() {
2774 if edit.changes.is_none() && edit.document_changes.is_none() {
2775 continue;
2776 }
2777
2778 let new = Self::deserialize_workspace_edit(
2779 lsp_store.upgrade().context("project dropped")?,
2780 edit.clone(),
2781 push_to_history,
2782 language_server.clone(),
2783 cx,
2784 )
2785 .await?;
2786 project_transaction.0.extend(new.0);
2787 }
2788
2789 if let Some(command) = action.lsp_action.command() {
2790 let server_capabilities = language_server.capabilities();
2791 let available_commands = server_capabilities
2792 .execute_command_provider
2793 .as_ref()
2794 .map(|options| options.commands.as_slice())
2795 .unwrap_or_default();
2796 if available_commands.contains(&command.command) {
2797 lsp_store.update(cx, |lsp_store, _| {
2798 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2799 mode.last_workspace_edits_by_language_server
2800 .remove(&language_server.server_id());
2801 }
2802 })?;
2803
2804 language_server
2805 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2806 command: command.command.clone(),
2807 arguments: command.arguments.clone().unwrap_or_default(),
2808 ..Default::default()
2809 })
2810 .await
2811 .into_response()
2812 .context("execute command")?;
2813
2814 lsp_store.update(cx, |this, _| {
2815 if let LspStoreMode::Local(mode) = &mut this.mode {
2816 project_transaction.0.extend(
2817 mode.last_workspace_edits_by_language_server
2818 .remove(&language_server.server_id())
2819 .unwrap_or_default()
2820 .0,
2821 )
2822 }
2823 })?;
2824 } else {
2825 log::warn!(
2826 "Cannot execute a command {} not listed in the language server capabilities",
2827 command.command
2828 )
2829 }
2830 }
2831 }
2832 Ok(())
2833 }
2834
2835 pub async fn deserialize_text_edits(
2836 this: Entity<LspStore>,
2837 buffer_to_edit: Entity<Buffer>,
2838 edits: Vec<lsp::TextEdit>,
2839 push_to_history: bool,
2840 _: Arc<CachedLspAdapter>,
2841 language_server: Arc<LanguageServer>,
2842 cx: &mut AsyncApp,
2843 ) -> Result<Option<Transaction>> {
2844 let edits = this
2845 .update(cx, |this, cx| {
2846 this.as_local_mut().unwrap().edits_from_lsp(
2847 &buffer_to_edit,
2848 edits,
2849 language_server.server_id(),
2850 None,
2851 cx,
2852 )
2853 })?
2854 .await?;
2855
2856 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2857 buffer.finalize_last_transaction();
2858 buffer.start_transaction();
2859 for (range, text) in edits {
2860 buffer.edit([(range, text)], None, cx);
2861 }
2862
2863 if buffer.end_transaction(cx).is_some() {
2864 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2865 if !push_to_history {
2866 buffer.forget_transaction(transaction.id);
2867 }
2868 Some(transaction)
2869 } else {
2870 None
2871 }
2872 })?;
2873
2874 Ok(transaction)
2875 }
2876
2877 #[allow(clippy::type_complexity)]
2878 pub(crate) fn edits_from_lsp(
2879 &mut self,
2880 buffer: &Entity<Buffer>,
2881 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2882 server_id: LanguageServerId,
2883 version: Option<i32>,
2884 cx: &mut Context<LspStore>,
2885 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2886 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2887 cx.background_spawn(async move {
2888 let snapshot = snapshot?;
2889 let mut lsp_edits = lsp_edits
2890 .into_iter()
2891 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2892 .collect::<Vec<_>>();
2893
2894 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2895
2896 let mut lsp_edits = lsp_edits.into_iter().peekable();
2897 let mut edits = Vec::new();
2898 while let Some((range, mut new_text)) = lsp_edits.next() {
2899 // Clip invalid ranges provided by the language server.
2900 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2901 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2902
2903 // Combine any LSP edits that are adjacent.
2904 //
2905 // Also, combine LSP edits that are separated from each other by only
2906 // a newline. This is important because for some code actions,
2907 // Rust-analyzer rewrites the entire buffer via a series of edits that
2908 // are separated by unchanged newline characters.
2909 //
2910 // In order for the diffing logic below to work properly, any edits that
2911 // cancel each other out must be combined into one.
2912 while let Some((next_range, next_text)) = lsp_edits.peek() {
2913 if next_range.start.0 > range.end {
2914 if next_range.start.0.row > range.end.row + 1
2915 || next_range.start.0.column > 0
2916 || snapshot.clip_point_utf16(
2917 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2918 Bias::Left,
2919 ) > range.end
2920 {
2921 break;
2922 }
2923 new_text.push('\n');
2924 }
2925 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2926 new_text.push_str(next_text);
2927 lsp_edits.next();
2928 }
2929
2930 // For multiline edits, perform a diff of the old and new text so that
2931 // we can identify the changes more precisely, preserving the locations
2932 // of any anchors positioned in the unchanged regions.
2933 if range.end.row > range.start.row {
2934 let offset = range.start.to_offset(&snapshot);
2935 let old_text = snapshot.text_for_range(range).collect::<String>();
2936 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2937 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2938 (
2939 snapshot.anchor_after(offset + range.start)
2940 ..snapshot.anchor_before(offset + range.end),
2941 replacement,
2942 )
2943 }));
2944 } else if range.end == range.start {
2945 let anchor = snapshot.anchor_after(range.start);
2946 edits.push((anchor..anchor, new_text.into()));
2947 } else {
2948 let edit_start = snapshot.anchor_after(range.start);
2949 let edit_end = snapshot.anchor_before(range.end);
2950 edits.push((edit_start..edit_end, new_text.into()));
2951 }
2952 }
2953
2954 Ok(edits)
2955 })
2956 }
2957
2958 pub(crate) async fn deserialize_workspace_edit(
2959 this: Entity<LspStore>,
2960 edit: lsp::WorkspaceEdit,
2961 push_to_history: bool,
2962 language_server: Arc<LanguageServer>,
2963 cx: &mut AsyncApp,
2964 ) -> Result<ProjectTransaction> {
2965 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2966
2967 let mut operations = Vec::new();
2968 if let Some(document_changes) = edit.document_changes {
2969 match document_changes {
2970 lsp::DocumentChanges::Edits(edits) => {
2971 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2972 }
2973 lsp::DocumentChanges::Operations(ops) => operations = ops,
2974 }
2975 } else if let Some(changes) = edit.changes {
2976 operations.extend(changes.into_iter().map(|(uri, edits)| {
2977 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2978 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2979 uri,
2980 version: None,
2981 },
2982 edits: edits.into_iter().map(Edit::Plain).collect(),
2983 })
2984 }));
2985 }
2986
2987 let mut project_transaction = ProjectTransaction::default();
2988 for operation in operations {
2989 match operation {
2990 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2991 let abs_path = op
2992 .uri
2993 .to_file_path()
2994 .map_err(|()| anyhow!("can't convert URI to path"))?;
2995
2996 if let Some(parent_path) = abs_path.parent() {
2997 fs.create_dir(parent_path).await?;
2998 }
2999 if abs_path.ends_with("/") {
3000 fs.create_dir(&abs_path).await?;
3001 } else {
3002 fs.create_file(
3003 &abs_path,
3004 op.options
3005 .map(|options| fs::CreateOptions {
3006 overwrite: options.overwrite.unwrap_or(false),
3007 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3008 })
3009 .unwrap_or_default(),
3010 )
3011 .await?;
3012 }
3013 }
3014
3015 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3016 let source_abs_path = op
3017 .old_uri
3018 .to_file_path()
3019 .map_err(|()| anyhow!("can't convert URI to path"))?;
3020 let target_abs_path = op
3021 .new_uri
3022 .to_file_path()
3023 .map_err(|()| anyhow!("can't convert URI to path"))?;
3024 fs.rename(
3025 &source_abs_path,
3026 &target_abs_path,
3027 op.options
3028 .map(|options| fs::RenameOptions {
3029 overwrite: options.overwrite.unwrap_or(false),
3030 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3031 })
3032 .unwrap_or_default(),
3033 )
3034 .await?;
3035 }
3036
3037 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3038 let abs_path = op
3039 .uri
3040 .to_file_path()
3041 .map_err(|()| anyhow!("can't convert URI to path"))?;
3042 let options = op
3043 .options
3044 .map(|options| fs::RemoveOptions {
3045 recursive: options.recursive.unwrap_or(false),
3046 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3047 })
3048 .unwrap_or_default();
3049 if abs_path.ends_with("/") {
3050 fs.remove_dir(&abs_path, options).await?;
3051 } else {
3052 fs.remove_file(&abs_path, options).await?;
3053 }
3054 }
3055
3056 lsp::DocumentChangeOperation::Edit(op) => {
3057 let buffer_to_edit = this
3058 .update(cx, |this, cx| {
3059 this.open_local_buffer_via_lsp(
3060 op.text_document.uri.clone(),
3061 language_server.server_id(),
3062 cx,
3063 )
3064 })?
3065 .await?;
3066
3067 let edits = this
3068 .update(cx, |this, cx| {
3069 let path = buffer_to_edit.read(cx).project_path(cx);
3070 let active_entry = this.active_entry;
3071 let is_active_entry = path.is_some_and(|project_path| {
3072 this.worktree_store
3073 .read(cx)
3074 .entry_for_path(&project_path, cx)
3075 .is_some_and(|entry| Some(entry.id) == active_entry)
3076 });
3077 let local = this.as_local_mut().unwrap();
3078
3079 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3080 for edit in op.edits {
3081 match edit {
3082 Edit::Plain(edit) => {
3083 if !edits.contains(&edit) {
3084 edits.push(edit)
3085 }
3086 }
3087 Edit::Annotated(edit) => {
3088 if !edits.contains(&edit.text_edit) {
3089 edits.push(edit.text_edit)
3090 }
3091 }
3092 Edit::Snippet(edit) => {
3093 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3094 else {
3095 continue;
3096 };
3097
3098 if is_active_entry {
3099 snippet_edits.push((edit.range, snippet));
3100 } else {
3101 // Since this buffer is not focused, apply a normal edit.
3102 let new_edit = TextEdit {
3103 range: edit.range,
3104 new_text: snippet.text,
3105 };
3106 if !edits.contains(&new_edit) {
3107 edits.push(new_edit);
3108 }
3109 }
3110 }
3111 }
3112 }
3113 if !snippet_edits.is_empty() {
3114 let buffer_id = buffer_to_edit.read(cx).remote_id();
3115 let version = if let Some(buffer_version) = op.text_document.version
3116 {
3117 local
3118 .buffer_snapshot_for_lsp_version(
3119 &buffer_to_edit,
3120 language_server.server_id(),
3121 Some(buffer_version),
3122 cx,
3123 )
3124 .ok()
3125 .map(|snapshot| snapshot.version)
3126 } else {
3127 Some(buffer_to_edit.read(cx).saved_version().clone())
3128 };
3129
3130 let most_recent_edit =
3131 version.and_then(|version| version.most_recent());
3132 // Check if the edit that triggered that edit has been made by this participant.
3133
3134 if let Some(most_recent_edit) = most_recent_edit {
3135 cx.emit(LspStoreEvent::SnippetEdit {
3136 buffer_id,
3137 edits: snippet_edits,
3138 most_recent_edit,
3139 });
3140 }
3141 }
3142
3143 local.edits_from_lsp(
3144 &buffer_to_edit,
3145 edits,
3146 language_server.server_id(),
3147 op.text_document.version,
3148 cx,
3149 )
3150 })?
3151 .await?;
3152
3153 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3154 buffer.finalize_last_transaction();
3155 buffer.start_transaction();
3156 for (range, text) in edits {
3157 buffer.edit([(range, text)], None, cx);
3158 }
3159
3160 buffer.end_transaction(cx).and_then(|transaction_id| {
3161 if push_to_history {
3162 buffer.finalize_last_transaction();
3163 buffer.get_transaction(transaction_id).cloned()
3164 } else {
3165 buffer.forget_transaction(transaction_id)
3166 }
3167 })
3168 })?;
3169 if let Some(transaction) = transaction {
3170 project_transaction.0.insert(buffer_to_edit, transaction);
3171 }
3172 }
3173 }
3174 }
3175
3176 Ok(project_transaction)
3177 }
3178
3179 async fn on_lsp_workspace_edit(
3180 this: WeakEntity<LspStore>,
3181 params: lsp::ApplyWorkspaceEditParams,
3182 server_id: LanguageServerId,
3183 cx: &mut AsyncApp,
3184 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3185 let this = this.upgrade().context("project project closed")?;
3186 let language_server = this
3187 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3188 .context("language server not found")?;
3189 let transaction = Self::deserialize_workspace_edit(
3190 this.clone(),
3191 params.edit,
3192 true,
3193 language_server.clone(),
3194 cx,
3195 )
3196 .await
3197 .log_err();
3198 this.update(cx, |this, _| {
3199 if let Some(transaction) = transaction {
3200 this.as_local_mut()
3201 .unwrap()
3202 .last_workspace_edits_by_language_server
3203 .insert(server_id, transaction);
3204 }
3205 })?;
3206 Ok(lsp::ApplyWorkspaceEditResponse {
3207 applied: true,
3208 failed_change: None,
3209 failure_reason: None,
3210 })
3211 }
3212
3213 fn remove_worktree(
3214 &mut self,
3215 id_to_remove: WorktreeId,
3216 cx: &mut Context<LspStore>,
3217 ) -> Vec<LanguageServerId> {
3218 self.diagnostics.remove(&id_to_remove);
3219 self.prettier_store.update(cx, |prettier_store, cx| {
3220 prettier_store.remove_worktree(id_to_remove, cx);
3221 });
3222
3223 let mut servers_to_remove = BTreeSet::default();
3224 let mut servers_to_preserve = HashSet::default();
3225 for (seed, state) in &self.language_server_ids {
3226 if seed.worktree_id == id_to_remove {
3227 servers_to_remove.insert(state.id);
3228 } else {
3229 servers_to_preserve.insert(state.id);
3230 }
3231 }
3232 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3233 self.language_server_ids
3234 .retain(|_, state| !servers_to_remove.contains(&state.id));
3235 for server_id_to_remove in &servers_to_remove {
3236 self.language_server_watched_paths
3237 .remove(server_id_to_remove);
3238 self.language_server_paths_watched_for_rename
3239 .remove(server_id_to_remove);
3240 self.last_workspace_edits_by_language_server
3241 .remove(server_id_to_remove);
3242 self.language_servers.remove(server_id_to_remove);
3243 self.buffer_pull_diagnostics_result_ids
3244 .remove(server_id_to_remove);
3245 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3246 buffer_servers.remove(server_id_to_remove);
3247 }
3248 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3249 }
3250 servers_to_remove.into_iter().collect()
3251 }
3252
3253 fn rebuild_watched_paths_inner<'a>(
3254 &'a self,
3255 language_server_id: LanguageServerId,
3256 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3257 cx: &mut Context<LspStore>,
3258 ) -> LanguageServerWatchedPathsBuilder {
3259 let worktrees = self
3260 .worktree_store
3261 .read(cx)
3262 .worktrees()
3263 .filter_map(|worktree| {
3264 self.language_servers_for_worktree(worktree.read(cx).id())
3265 .find(|server| server.server_id() == language_server_id)
3266 .map(|_| worktree)
3267 })
3268 .collect::<Vec<_>>();
3269
3270 let mut worktree_globs = HashMap::default();
3271 let mut abs_globs = HashMap::default();
3272 log::trace!(
3273 "Processing new watcher paths for language server with id {}",
3274 language_server_id
3275 );
3276
3277 for watcher in watchers {
3278 if let Some((worktree, literal_prefix, pattern)) =
3279 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3280 {
3281 worktree.update(cx, |worktree, _| {
3282 if let Some((tree, glob)) =
3283 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3284 {
3285 tree.add_path_prefix_to_scan(literal_prefix);
3286 worktree_globs
3287 .entry(tree.id())
3288 .or_insert_with(GlobSetBuilder::new)
3289 .add(glob);
3290 }
3291 });
3292 } else {
3293 let (path, pattern) = match &watcher.glob_pattern {
3294 lsp::GlobPattern::String(s) => {
3295 let watcher_path = SanitizedPath::new(s);
3296 let path = glob_literal_prefix(watcher_path.as_path());
3297 let pattern = watcher_path
3298 .as_path()
3299 .strip_prefix(&path)
3300 .map(|p| p.to_string_lossy().into_owned())
3301 .unwrap_or_else(|e| {
3302 debug_panic!(
3303 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3304 s,
3305 path.display(),
3306 e
3307 );
3308 watcher_path.as_path().to_string_lossy().into_owned()
3309 });
3310 (path, pattern)
3311 }
3312 lsp::GlobPattern::Relative(rp) => {
3313 let Ok(mut base_uri) = match &rp.base_uri {
3314 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3315 lsp::OneOf::Right(base_uri) => base_uri,
3316 }
3317 .to_file_path() else {
3318 continue;
3319 };
3320
3321 let path = glob_literal_prefix(Path::new(&rp.pattern));
3322 let pattern = Path::new(&rp.pattern)
3323 .strip_prefix(&path)
3324 .map(|p| p.to_string_lossy().into_owned())
3325 .unwrap_or_else(|e| {
3326 debug_panic!(
3327 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3328 rp.pattern,
3329 path.display(),
3330 e
3331 );
3332 rp.pattern.clone()
3333 });
3334 base_uri.push(path);
3335 (base_uri, pattern)
3336 }
3337 };
3338
3339 if let Some(glob) = Glob::new(&pattern).log_err() {
3340 if !path
3341 .components()
3342 .any(|c| matches!(c, path::Component::Normal(_)))
3343 {
3344 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3345 // rather than adding a new watcher for `/`.
3346 for worktree in &worktrees {
3347 worktree_globs
3348 .entry(worktree.read(cx).id())
3349 .or_insert_with(GlobSetBuilder::new)
3350 .add(glob.clone());
3351 }
3352 } else {
3353 abs_globs
3354 .entry(path.into())
3355 .or_insert_with(GlobSetBuilder::new)
3356 .add(glob);
3357 }
3358 }
3359 }
3360 }
3361
3362 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3363 for (worktree_id, builder) in worktree_globs {
3364 if let Ok(globset) = builder.build() {
3365 watch_builder.watch_worktree(worktree_id, globset);
3366 }
3367 }
3368 for (abs_path, builder) in abs_globs {
3369 if let Ok(globset) = builder.build() {
3370 watch_builder.watch_abs_path(abs_path, globset);
3371 }
3372 }
3373 watch_builder
3374 }
3375
3376 fn worktree_and_path_for_file_watcher(
3377 worktrees: &[Entity<Worktree>],
3378 watcher: &FileSystemWatcher,
3379 cx: &App,
3380 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3381 worktrees.iter().find_map(|worktree| {
3382 let tree = worktree.read(cx);
3383 let worktree_root_path = tree.abs_path();
3384 let path_style = tree.path_style();
3385 match &watcher.glob_pattern {
3386 lsp::GlobPattern::String(s) => {
3387 let watcher_path = SanitizedPath::new(s);
3388 let relative = watcher_path
3389 .as_path()
3390 .strip_prefix(&worktree_root_path)
3391 .ok()?;
3392 let literal_prefix = glob_literal_prefix(relative);
3393 Some((
3394 worktree.clone(),
3395 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3396 relative.to_string_lossy().into_owned(),
3397 ))
3398 }
3399 lsp::GlobPattern::Relative(rp) => {
3400 let base_uri = match &rp.base_uri {
3401 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3402 lsp::OneOf::Right(base_uri) => base_uri,
3403 }
3404 .to_file_path()
3405 .ok()?;
3406 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3407 let mut literal_prefix = relative.to_owned();
3408 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3409 Some((
3410 worktree.clone(),
3411 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3412 rp.pattern.clone(),
3413 ))
3414 }
3415 }
3416 })
3417 }
3418
3419 fn rebuild_watched_paths(
3420 &mut self,
3421 language_server_id: LanguageServerId,
3422 cx: &mut Context<LspStore>,
3423 ) {
3424 let Some(registrations) = self
3425 .language_server_dynamic_registrations
3426 .get(&language_server_id)
3427 else {
3428 return;
3429 };
3430
3431 let watch_builder = self.rebuild_watched_paths_inner(
3432 language_server_id,
3433 registrations.did_change_watched_files.values().flatten(),
3434 cx,
3435 );
3436 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3437 self.language_server_watched_paths
3438 .insert(language_server_id, watcher);
3439
3440 cx.notify();
3441 }
3442
3443 fn on_lsp_did_change_watched_files(
3444 &mut self,
3445 language_server_id: LanguageServerId,
3446 registration_id: &str,
3447 params: DidChangeWatchedFilesRegistrationOptions,
3448 cx: &mut Context<LspStore>,
3449 ) {
3450 let registrations = self
3451 .language_server_dynamic_registrations
3452 .entry(language_server_id)
3453 .or_default();
3454
3455 registrations
3456 .did_change_watched_files
3457 .insert(registration_id.to_string(), params.watchers);
3458
3459 self.rebuild_watched_paths(language_server_id, cx);
3460 }
3461
3462 fn on_lsp_unregister_did_change_watched_files(
3463 &mut self,
3464 language_server_id: LanguageServerId,
3465 registration_id: &str,
3466 cx: &mut Context<LspStore>,
3467 ) {
3468 let registrations = self
3469 .language_server_dynamic_registrations
3470 .entry(language_server_id)
3471 .or_default();
3472
3473 if registrations
3474 .did_change_watched_files
3475 .remove(registration_id)
3476 .is_some()
3477 {
3478 log::info!(
3479 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3480 language_server_id,
3481 registration_id
3482 );
3483 } else {
3484 log::warn!(
3485 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3486 language_server_id,
3487 registration_id
3488 );
3489 }
3490
3491 self.rebuild_watched_paths(language_server_id, cx);
3492 }
3493
3494 async fn initialization_options_for_adapter(
3495 adapter: Arc<dyn LspAdapter>,
3496 delegate: &Arc<dyn LspAdapterDelegate>,
3497 ) -> Result<Option<serde_json::Value>> {
3498 let Some(mut initialization_config) =
3499 adapter.clone().initialization_options(delegate).await?
3500 else {
3501 return Ok(None);
3502 };
3503
3504 for other_adapter in delegate.registered_lsp_adapters() {
3505 if other_adapter.name() == adapter.name() {
3506 continue;
3507 }
3508 if let Ok(Some(target_config)) = other_adapter
3509 .clone()
3510 .additional_initialization_options(adapter.name(), delegate)
3511 .await
3512 {
3513 merge_json_value_into(target_config.clone(), &mut initialization_config);
3514 }
3515 }
3516
3517 Ok(Some(initialization_config))
3518 }
3519
3520 async fn workspace_configuration_for_adapter(
3521 adapter: Arc<dyn LspAdapter>,
3522 delegate: &Arc<dyn LspAdapterDelegate>,
3523 toolchain: Option<Toolchain>,
3524 cx: &mut AsyncApp,
3525 ) -> Result<serde_json::Value> {
3526 let mut workspace_config = adapter
3527 .clone()
3528 .workspace_configuration(delegate, toolchain, cx)
3529 .await?;
3530
3531 for other_adapter in delegate.registered_lsp_adapters() {
3532 if other_adapter.name() == adapter.name() {
3533 continue;
3534 }
3535 if let Ok(Some(target_config)) = other_adapter
3536 .clone()
3537 .additional_workspace_configuration(adapter.name(), delegate, cx)
3538 .await
3539 {
3540 merge_json_value_into(target_config.clone(), &mut workspace_config);
3541 }
3542 }
3543
3544 Ok(workspace_config)
3545 }
3546
3547 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3548 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3549 Some(server.clone())
3550 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3551 Some(Arc::clone(server))
3552 } else {
3553 None
3554 }
3555 }
3556}
3557
3558fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3559 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3560 cx.emit(LspStoreEvent::LanguageServerUpdate {
3561 language_server_id: server.server_id(),
3562 name: Some(server.name()),
3563 message: proto::update_language_server::Variant::MetadataUpdated(
3564 proto::ServerMetadataUpdated {
3565 capabilities: Some(capabilities),
3566 binary: Some(proto::LanguageServerBinaryInfo {
3567 path: server.binary().path.to_string_lossy().into_owned(),
3568 arguments: server
3569 .binary()
3570 .arguments
3571 .iter()
3572 .map(|arg| arg.to_string_lossy().into_owned())
3573 .collect(),
3574 }),
3575 configuration: serde_json::to_string(server.configuration()).ok(),
3576 workspace_folders: server
3577 .workspace_folders()
3578 .iter()
3579 .map(|uri| uri.to_string())
3580 .collect(),
3581 },
3582 ),
3583 });
3584 }
3585}
3586
3587#[derive(Debug)]
3588pub struct FormattableBuffer {
3589 handle: Entity<Buffer>,
3590 abs_path: Option<PathBuf>,
3591 env: Option<HashMap<String, String>>,
3592 ranges: Option<Vec<Range<Anchor>>>,
3593}
3594
3595pub struct RemoteLspStore {
3596 upstream_client: Option<AnyProtoClient>,
3597 upstream_project_id: u64,
3598}
3599
3600pub(crate) enum LspStoreMode {
3601 Local(LocalLspStore), // ssh host and collab host
3602 Remote(RemoteLspStore), // collab guest
3603}
3604
3605impl LspStoreMode {
3606 fn is_local(&self) -> bool {
3607 matches!(self, LspStoreMode::Local(_))
3608 }
3609}
3610
3611pub struct LspStore {
3612 mode: LspStoreMode,
3613 last_formatting_failure: Option<String>,
3614 downstream_client: Option<(AnyProtoClient, u64)>,
3615 nonce: u128,
3616 buffer_store: Entity<BufferStore>,
3617 worktree_store: Entity<WorktreeStore>,
3618 pub languages: Arc<LanguageRegistry>,
3619 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3620 active_entry: Option<ProjectEntryId>,
3621 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3622 _maintain_buffer_languages: Task<()>,
3623 diagnostic_summaries:
3624 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3625 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3626 lsp_data: HashMap<BufferId, BufferLspData>,
3627 next_hint_id: Arc<AtomicUsize>,
3628}
3629
3630#[derive(Debug)]
3631pub struct BufferLspData {
3632 buffer_version: Global,
3633 document_colors: Option<DocumentColorData>,
3634 code_lens: Option<CodeLensData>,
3635 inlay_hints: BufferInlayHints,
3636 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3637 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3638}
3639
3640#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3641struct LspKey {
3642 request_type: TypeId,
3643 server_queried: Option<LanguageServerId>,
3644}
3645
3646impl BufferLspData {
3647 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3648 Self {
3649 buffer_version: buffer.read(cx).version(),
3650 document_colors: None,
3651 code_lens: None,
3652 inlay_hints: BufferInlayHints::new(buffer, cx),
3653 lsp_requests: HashMap::default(),
3654 chunk_lsp_requests: HashMap::default(),
3655 }
3656 }
3657
3658 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3659 if let Some(document_colors) = &mut self.document_colors {
3660 document_colors.colors.remove(&for_server);
3661 document_colors.cache_version += 1;
3662 }
3663
3664 if let Some(code_lens) = &mut self.code_lens {
3665 code_lens.lens.remove(&for_server);
3666 }
3667
3668 self.inlay_hints.remove_server_data(for_server);
3669 }
3670
3671 #[cfg(any(test, feature = "test-support"))]
3672 pub fn inlay_hints(&self) -> &BufferInlayHints {
3673 &self.inlay_hints
3674 }
3675}
3676
3677#[derive(Debug, Default, Clone)]
3678pub struct DocumentColors {
3679 pub colors: HashSet<DocumentColor>,
3680 pub cache_version: Option<usize>,
3681}
3682
3683type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3684type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3685
3686#[derive(Debug, Default)]
3687struct DocumentColorData {
3688 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3689 cache_version: usize,
3690 colors_update: Option<(Global, DocumentColorTask)>,
3691}
3692
3693#[derive(Debug, Default)]
3694struct CodeLensData {
3695 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3696 update: Option<(Global, CodeLensTask)>,
3697}
3698
3699#[derive(Debug)]
3700pub enum LspStoreEvent {
3701 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3702 LanguageServerRemoved(LanguageServerId),
3703 LanguageServerUpdate {
3704 language_server_id: LanguageServerId,
3705 name: Option<LanguageServerName>,
3706 message: proto::update_language_server::Variant,
3707 },
3708 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3709 LanguageServerPrompt(LanguageServerPromptRequest),
3710 LanguageDetected {
3711 buffer: Entity<Buffer>,
3712 new_language: Option<Arc<Language>>,
3713 },
3714 Notification(String),
3715 RefreshInlayHints {
3716 server_id: LanguageServerId,
3717 request_id: Option<usize>,
3718 },
3719 RefreshCodeLens,
3720 DiagnosticsUpdated {
3721 server_id: LanguageServerId,
3722 paths: Vec<ProjectPath>,
3723 },
3724 DiskBasedDiagnosticsStarted {
3725 language_server_id: LanguageServerId,
3726 },
3727 DiskBasedDiagnosticsFinished {
3728 language_server_id: LanguageServerId,
3729 },
3730 SnippetEdit {
3731 buffer_id: BufferId,
3732 edits: Vec<(lsp::Range, Snippet)>,
3733 most_recent_edit: clock::Lamport,
3734 },
3735}
3736
3737#[derive(Clone, Debug, Serialize)]
3738pub struct LanguageServerStatus {
3739 pub name: LanguageServerName,
3740 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3741 pub has_pending_diagnostic_updates: bool,
3742 pub progress_tokens: HashSet<ProgressToken>,
3743 pub worktree: Option<WorktreeId>,
3744 pub binary: Option<LanguageServerBinary>,
3745 pub configuration: Option<Value>,
3746 pub workspace_folders: BTreeSet<Uri>,
3747}
3748
3749#[derive(Clone, Debug)]
3750struct CoreSymbol {
3751 pub language_server_name: LanguageServerName,
3752 pub source_worktree_id: WorktreeId,
3753 pub source_language_server_id: LanguageServerId,
3754 pub path: SymbolLocation,
3755 pub name: String,
3756 pub kind: lsp::SymbolKind,
3757 pub range: Range<Unclipped<PointUtf16>>,
3758}
3759
3760#[derive(Clone, Debug, PartialEq, Eq)]
3761pub enum SymbolLocation {
3762 InProject(ProjectPath),
3763 OutsideProject {
3764 abs_path: Arc<Path>,
3765 signature: [u8; 32],
3766 },
3767}
3768
3769impl SymbolLocation {
3770 fn file_name(&self) -> Option<&str> {
3771 match self {
3772 Self::InProject(path) => path.path.file_name(),
3773 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3774 }
3775 }
3776}
3777
3778impl LspStore {
3779 pub fn init(client: &AnyProtoClient) {
3780 client.add_entity_request_handler(Self::handle_lsp_query);
3781 client.add_entity_message_handler(Self::handle_lsp_query_response);
3782 client.add_entity_request_handler(Self::handle_restart_language_servers);
3783 client.add_entity_request_handler(Self::handle_stop_language_servers);
3784 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3785 client.add_entity_message_handler(Self::handle_start_language_server);
3786 client.add_entity_message_handler(Self::handle_update_language_server);
3787 client.add_entity_message_handler(Self::handle_language_server_log);
3788 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3789 client.add_entity_request_handler(Self::handle_format_buffers);
3790 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3791 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3792 client.add_entity_request_handler(Self::handle_apply_code_action);
3793 client.add_entity_request_handler(Self::handle_get_project_symbols);
3794 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3795 client.add_entity_request_handler(Self::handle_get_color_presentation);
3796 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3797 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3798 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3799 client.add_entity_request_handler(Self::handle_on_type_formatting);
3800 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3801 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3802 client.add_entity_request_handler(Self::handle_rename_project_entry);
3803 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3804 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3805 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3806 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3807 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3808 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3809 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3810
3811 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3812 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3813 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3814 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3815 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3816 client.add_entity_request_handler(
3817 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3818 );
3819 client.add_entity_request_handler(
3820 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3821 );
3822 client.add_entity_request_handler(
3823 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3824 );
3825 }
3826
3827 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3828 match &self.mode {
3829 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3830 _ => None,
3831 }
3832 }
3833
3834 pub fn as_local(&self) -> Option<&LocalLspStore> {
3835 match &self.mode {
3836 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3837 _ => None,
3838 }
3839 }
3840
3841 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3842 match &mut self.mode {
3843 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3844 _ => None,
3845 }
3846 }
3847
3848 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3849 match &self.mode {
3850 LspStoreMode::Remote(RemoteLspStore {
3851 upstream_client: Some(upstream_client),
3852 upstream_project_id,
3853 ..
3854 }) => Some((upstream_client.clone(), *upstream_project_id)),
3855
3856 LspStoreMode::Remote(RemoteLspStore {
3857 upstream_client: None,
3858 ..
3859 }) => None,
3860 LspStoreMode::Local(_) => None,
3861 }
3862 }
3863
3864 pub fn new_local(
3865 buffer_store: Entity<BufferStore>,
3866 worktree_store: Entity<WorktreeStore>,
3867 prettier_store: Entity<PrettierStore>,
3868 toolchain_store: Entity<LocalToolchainStore>,
3869 environment: Entity<ProjectEnvironment>,
3870 manifest_tree: Entity<ManifestTree>,
3871 languages: Arc<LanguageRegistry>,
3872 http_client: Arc<dyn HttpClient>,
3873 fs: Arc<dyn Fs>,
3874 cx: &mut Context<Self>,
3875 ) -> Self {
3876 let yarn = YarnPathStore::new(fs.clone(), cx);
3877 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3878 .detach();
3879 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3880 .detach();
3881 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3882 .detach();
3883 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3884 .detach();
3885 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3886 .detach();
3887 subscribe_to_binary_statuses(&languages, cx).detach();
3888
3889 let _maintain_workspace_config = {
3890 let (sender, receiver) = watch::channel();
3891 (Self::maintain_workspace_config(receiver, cx), sender)
3892 };
3893
3894 Self {
3895 mode: LspStoreMode::Local(LocalLspStore {
3896 weak: cx.weak_entity(),
3897 worktree_store: worktree_store.clone(),
3898
3899 supplementary_language_servers: Default::default(),
3900 languages: languages.clone(),
3901 language_server_ids: Default::default(),
3902 language_servers: Default::default(),
3903 last_workspace_edits_by_language_server: Default::default(),
3904 language_server_watched_paths: Default::default(),
3905 language_server_paths_watched_for_rename: Default::default(),
3906 language_server_dynamic_registrations: Default::default(),
3907 buffers_being_formatted: Default::default(),
3908 buffer_snapshots: Default::default(),
3909 prettier_store,
3910 environment,
3911 http_client,
3912 fs,
3913 yarn,
3914 next_diagnostic_group_id: Default::default(),
3915 diagnostics: Default::default(),
3916 _subscription: cx.on_app_quit(|this, cx| {
3917 this.as_local_mut()
3918 .unwrap()
3919 .shutdown_language_servers_on_quit(cx)
3920 }),
3921 lsp_tree: LanguageServerTree::new(
3922 manifest_tree,
3923 languages.clone(),
3924 toolchain_store.clone(),
3925 ),
3926 toolchain_store,
3927 registered_buffers: HashMap::default(),
3928 buffers_opened_in_servers: HashMap::default(),
3929 buffer_pull_diagnostics_result_ids: HashMap::default(),
3930 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3931 .manifest_file_names(),
3932 }),
3933 last_formatting_failure: None,
3934 downstream_client: None,
3935 buffer_store,
3936 worktree_store,
3937 languages: languages.clone(),
3938 language_server_statuses: Default::default(),
3939 nonce: StdRng::from_os_rng().random(),
3940 diagnostic_summaries: HashMap::default(),
3941 lsp_server_capabilities: HashMap::default(),
3942 lsp_data: HashMap::default(),
3943 next_hint_id: Arc::default(),
3944 active_entry: None,
3945 _maintain_workspace_config,
3946 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3947 }
3948 }
3949
3950 fn send_lsp_proto_request<R: LspCommand>(
3951 &self,
3952 buffer: Entity<Buffer>,
3953 client: AnyProtoClient,
3954 upstream_project_id: u64,
3955 request: R,
3956 cx: &mut Context<LspStore>,
3957 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3958 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3959 return Task::ready(Ok(R::Response::default()));
3960 }
3961 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3962 cx.spawn(async move |this, cx| {
3963 let response = client.request(message).await?;
3964 let this = this.upgrade().context("project dropped")?;
3965 request
3966 .response_from_proto(response, this, buffer, cx.clone())
3967 .await
3968 })
3969 }
3970
3971 pub(super) fn new_remote(
3972 buffer_store: Entity<BufferStore>,
3973 worktree_store: Entity<WorktreeStore>,
3974 languages: Arc<LanguageRegistry>,
3975 upstream_client: AnyProtoClient,
3976 project_id: u64,
3977 cx: &mut Context<Self>,
3978 ) -> Self {
3979 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3980 .detach();
3981 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3982 .detach();
3983 subscribe_to_binary_statuses(&languages, cx).detach();
3984 let _maintain_workspace_config = {
3985 let (sender, receiver) = watch::channel();
3986 (Self::maintain_workspace_config(receiver, cx), sender)
3987 };
3988 Self {
3989 mode: LspStoreMode::Remote(RemoteLspStore {
3990 upstream_client: Some(upstream_client),
3991 upstream_project_id: project_id,
3992 }),
3993 downstream_client: None,
3994 last_formatting_failure: None,
3995 buffer_store,
3996 worktree_store,
3997 languages: languages.clone(),
3998 language_server_statuses: Default::default(),
3999 nonce: StdRng::from_os_rng().random(),
4000 diagnostic_summaries: HashMap::default(),
4001 lsp_server_capabilities: HashMap::default(),
4002 next_hint_id: Arc::default(),
4003 lsp_data: HashMap::default(),
4004 active_entry: None,
4005
4006 _maintain_workspace_config,
4007 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4008 }
4009 }
4010
4011 fn on_buffer_store_event(
4012 &mut self,
4013 _: Entity<BufferStore>,
4014 event: &BufferStoreEvent,
4015 cx: &mut Context<Self>,
4016 ) {
4017 match event {
4018 BufferStoreEvent::BufferAdded(buffer) => {
4019 self.on_buffer_added(buffer, cx).log_err();
4020 }
4021 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4022 let buffer_id = buffer.read(cx).remote_id();
4023 if let Some(local) = self.as_local_mut()
4024 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4025 {
4026 local.reset_buffer(buffer, old_file, cx);
4027
4028 if local.registered_buffers.contains_key(&buffer_id) {
4029 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4030 }
4031 }
4032
4033 self.detect_language_for_buffer(buffer, cx);
4034 if let Some(local) = self.as_local_mut() {
4035 local.initialize_buffer(buffer, cx);
4036 if local.registered_buffers.contains_key(&buffer_id) {
4037 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4038 }
4039 }
4040 }
4041 _ => {}
4042 }
4043 }
4044
4045 fn on_worktree_store_event(
4046 &mut self,
4047 _: Entity<WorktreeStore>,
4048 event: &WorktreeStoreEvent,
4049 cx: &mut Context<Self>,
4050 ) {
4051 match event {
4052 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4053 if !worktree.read(cx).is_local() {
4054 return;
4055 }
4056 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4057 worktree::Event::UpdatedEntries(changes) => {
4058 this.update_local_worktree_language_servers(&worktree, changes, cx);
4059 }
4060 worktree::Event::UpdatedGitRepositories(_)
4061 | worktree::Event::DeletedEntry(_) => {}
4062 })
4063 .detach()
4064 }
4065 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4066 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4067 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4068 }
4069 WorktreeStoreEvent::WorktreeReleased(..)
4070 | WorktreeStoreEvent::WorktreeOrderChanged
4071 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4072 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4073 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4074 }
4075 }
4076
4077 fn on_prettier_store_event(
4078 &mut self,
4079 _: Entity<PrettierStore>,
4080 event: &PrettierStoreEvent,
4081 cx: &mut Context<Self>,
4082 ) {
4083 match event {
4084 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4085 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4086 }
4087 PrettierStoreEvent::LanguageServerAdded {
4088 new_server_id,
4089 name,
4090 prettier_server,
4091 } => {
4092 self.register_supplementary_language_server(
4093 *new_server_id,
4094 name.clone(),
4095 prettier_server.clone(),
4096 cx,
4097 );
4098 }
4099 }
4100 }
4101
4102 fn on_toolchain_store_event(
4103 &mut self,
4104 _: Entity<LocalToolchainStore>,
4105 event: &ToolchainStoreEvent,
4106 _: &mut Context<Self>,
4107 ) {
4108 if let ToolchainStoreEvent::ToolchainActivated = event {
4109 self.request_workspace_config_refresh()
4110 }
4111 }
4112
4113 fn request_workspace_config_refresh(&mut self) {
4114 *self._maintain_workspace_config.1.borrow_mut() = ();
4115 }
4116
4117 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4118 self.as_local().map(|local| local.prettier_store.clone())
4119 }
4120
4121 fn on_buffer_event(
4122 &mut self,
4123 buffer: Entity<Buffer>,
4124 event: &language::BufferEvent,
4125 cx: &mut Context<Self>,
4126 ) {
4127 match event {
4128 language::BufferEvent::Edited => {
4129 self.on_buffer_edited(buffer, cx);
4130 }
4131
4132 language::BufferEvent::Saved => {
4133 self.on_buffer_saved(buffer, cx);
4134 }
4135
4136 _ => {}
4137 }
4138 }
4139
4140 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4141 buffer
4142 .read(cx)
4143 .set_language_registry(self.languages.clone());
4144
4145 cx.subscribe(buffer, |this, buffer, event, cx| {
4146 this.on_buffer_event(buffer, event, cx);
4147 })
4148 .detach();
4149
4150 self.detect_language_for_buffer(buffer, cx);
4151 if let Some(local) = self.as_local_mut() {
4152 local.initialize_buffer(buffer, cx);
4153 }
4154
4155 Ok(())
4156 }
4157
4158 pub(crate) fn register_buffer_with_language_servers(
4159 &mut self,
4160 buffer: &Entity<Buffer>,
4161 only_register_servers: HashSet<LanguageServerSelector>,
4162 ignore_refcounts: bool,
4163 cx: &mut Context<Self>,
4164 ) -> OpenLspBufferHandle {
4165 let buffer_id = buffer.read(cx).remote_id();
4166 let handle = cx.new(|_| buffer.clone());
4167 if let Some(local) = self.as_local_mut() {
4168 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4169 if !ignore_refcounts {
4170 *refcount += 1;
4171 }
4172
4173 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4174 // 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
4175 // 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
4176 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4177 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4178 return handle;
4179 };
4180 if !file.is_local() {
4181 return handle;
4182 }
4183
4184 if ignore_refcounts || *refcount == 1 {
4185 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4186 }
4187 if !ignore_refcounts {
4188 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4189 let refcount = {
4190 let local = lsp_store.as_local_mut().unwrap();
4191 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4192 debug_panic!("bad refcounting");
4193 return;
4194 };
4195
4196 *refcount -= 1;
4197 *refcount
4198 };
4199 if refcount == 0 {
4200 lsp_store.lsp_data.remove(&buffer_id);
4201 let local = lsp_store.as_local_mut().unwrap();
4202 local.registered_buffers.remove(&buffer_id);
4203 local.buffers_opened_in_servers.remove(&buffer_id);
4204 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4205 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4206 }
4207 }
4208 })
4209 .detach();
4210 }
4211 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4212 let buffer_id = buffer.read(cx).remote_id().to_proto();
4213 cx.background_spawn(async move {
4214 upstream_client
4215 .request(proto::RegisterBufferWithLanguageServers {
4216 project_id: upstream_project_id,
4217 buffer_id,
4218 only_servers: only_register_servers
4219 .into_iter()
4220 .map(|selector| {
4221 let selector = match selector {
4222 LanguageServerSelector::Id(language_server_id) => {
4223 proto::language_server_selector::Selector::ServerId(
4224 language_server_id.to_proto(),
4225 )
4226 }
4227 LanguageServerSelector::Name(language_server_name) => {
4228 proto::language_server_selector::Selector::Name(
4229 language_server_name.to_string(),
4230 )
4231 }
4232 };
4233 proto::LanguageServerSelector {
4234 selector: Some(selector),
4235 }
4236 })
4237 .collect(),
4238 })
4239 .await
4240 })
4241 .detach();
4242 } else {
4243 // Our remote connection got closed
4244 }
4245 handle
4246 }
4247
4248 fn maintain_buffer_languages(
4249 languages: Arc<LanguageRegistry>,
4250 cx: &mut Context<Self>,
4251 ) -> Task<()> {
4252 let mut subscription = languages.subscribe();
4253 let mut prev_reload_count = languages.reload_count();
4254 cx.spawn(async move |this, cx| {
4255 while let Some(()) = subscription.next().await {
4256 if let Some(this) = this.upgrade() {
4257 // If the language registry has been reloaded, then remove and
4258 // re-assign the languages on all open buffers.
4259 let reload_count = languages.reload_count();
4260 if reload_count > prev_reload_count {
4261 prev_reload_count = reload_count;
4262 this.update(cx, |this, cx| {
4263 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4264 for buffer in buffer_store.buffers() {
4265 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4266 {
4267 buffer
4268 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4269 if let Some(local) = this.as_local_mut() {
4270 local.reset_buffer(&buffer, &f, cx);
4271
4272 if local
4273 .registered_buffers
4274 .contains_key(&buffer.read(cx).remote_id())
4275 && let Some(file_url) =
4276 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4277 {
4278 local.unregister_buffer_from_language_servers(
4279 &buffer, &file_url, cx,
4280 );
4281 }
4282 }
4283 }
4284 }
4285 });
4286 })
4287 .ok();
4288 }
4289
4290 this.update(cx, |this, cx| {
4291 let mut plain_text_buffers = Vec::new();
4292 let mut buffers_with_unknown_injections = Vec::new();
4293 for handle in this.buffer_store.read(cx).buffers() {
4294 let buffer = handle.read(cx);
4295 if buffer.language().is_none()
4296 || buffer.language() == Some(&*language::PLAIN_TEXT)
4297 {
4298 plain_text_buffers.push(handle);
4299 } else if buffer.contains_unknown_injections() {
4300 buffers_with_unknown_injections.push(handle);
4301 }
4302 }
4303
4304 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4305 // and reused later in the invisible worktrees.
4306 plain_text_buffers.sort_by_key(|buffer| {
4307 Reverse(
4308 File::from_dyn(buffer.read(cx).file())
4309 .map(|file| file.worktree.read(cx).is_visible()),
4310 )
4311 });
4312
4313 for buffer in plain_text_buffers {
4314 this.detect_language_for_buffer(&buffer, cx);
4315 if let Some(local) = this.as_local_mut() {
4316 local.initialize_buffer(&buffer, cx);
4317 if local
4318 .registered_buffers
4319 .contains_key(&buffer.read(cx).remote_id())
4320 {
4321 local.register_buffer_with_language_servers(
4322 &buffer,
4323 HashSet::default(),
4324 cx,
4325 );
4326 }
4327 }
4328 }
4329
4330 for buffer in buffers_with_unknown_injections {
4331 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4332 }
4333 })
4334 .ok();
4335 }
4336 }
4337 })
4338 }
4339
4340 fn detect_language_for_buffer(
4341 &mut self,
4342 buffer_handle: &Entity<Buffer>,
4343 cx: &mut Context<Self>,
4344 ) -> Option<language::AvailableLanguage> {
4345 // If the buffer has a language, set it and start the language server if we haven't already.
4346 let buffer = buffer_handle.read(cx);
4347 let file = buffer.file()?;
4348
4349 let content = buffer.as_rope();
4350 let available_language = self.languages.language_for_file(file, Some(content), cx);
4351 if let Some(available_language) = &available_language {
4352 if let Some(Ok(Ok(new_language))) = self
4353 .languages
4354 .load_language(available_language)
4355 .now_or_never()
4356 {
4357 self.set_language_for_buffer(buffer_handle, new_language, cx);
4358 }
4359 } else {
4360 cx.emit(LspStoreEvent::LanguageDetected {
4361 buffer: buffer_handle.clone(),
4362 new_language: None,
4363 });
4364 }
4365
4366 available_language
4367 }
4368
4369 pub(crate) fn set_language_for_buffer(
4370 &mut self,
4371 buffer_entity: &Entity<Buffer>,
4372 new_language: Arc<Language>,
4373 cx: &mut Context<Self>,
4374 ) {
4375 let buffer = buffer_entity.read(cx);
4376 let buffer_file = buffer.file().cloned();
4377 let buffer_id = buffer.remote_id();
4378 if let Some(local_store) = self.as_local_mut()
4379 && local_store.registered_buffers.contains_key(&buffer_id)
4380 && let Some(abs_path) =
4381 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4382 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4383 {
4384 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4385 }
4386 buffer_entity.update(cx, |buffer, cx| {
4387 if buffer
4388 .language()
4389 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4390 {
4391 buffer.set_language(Some(new_language.clone()), cx);
4392 }
4393 });
4394
4395 let settings =
4396 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4397 let buffer_file = File::from_dyn(buffer_file.as_ref());
4398
4399 let worktree_id = if let Some(file) = buffer_file {
4400 let worktree = file.worktree.clone();
4401
4402 if let Some(local) = self.as_local_mut()
4403 && local.registered_buffers.contains_key(&buffer_id)
4404 {
4405 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4406 }
4407 Some(worktree.read(cx).id())
4408 } else {
4409 None
4410 };
4411
4412 if settings.prettier.allowed
4413 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4414 {
4415 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4416 if let Some(prettier_store) = prettier_store {
4417 prettier_store.update(cx, |prettier_store, cx| {
4418 prettier_store.install_default_prettier(
4419 worktree_id,
4420 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4421 cx,
4422 )
4423 })
4424 }
4425 }
4426
4427 cx.emit(LspStoreEvent::LanguageDetected {
4428 buffer: buffer_entity.clone(),
4429 new_language: Some(new_language),
4430 })
4431 }
4432
4433 pub fn buffer_store(&self) -> Entity<BufferStore> {
4434 self.buffer_store.clone()
4435 }
4436
4437 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4438 self.active_entry = active_entry;
4439 }
4440
4441 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4442 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4443 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4444 {
4445 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4446 summaries
4447 .iter()
4448 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4449 });
4450 if let Some(summary) = summaries.next() {
4451 client
4452 .send(proto::UpdateDiagnosticSummary {
4453 project_id: downstream_project_id,
4454 worktree_id: worktree.id().to_proto(),
4455 summary: Some(summary),
4456 more_summaries: summaries.collect(),
4457 })
4458 .log_err();
4459 }
4460 }
4461 }
4462
4463 fn is_capable_for_proto_request<R>(
4464 &self,
4465 buffer: &Entity<Buffer>,
4466 request: &R,
4467 cx: &App,
4468 ) -> bool
4469 where
4470 R: LspCommand,
4471 {
4472 self.check_if_capable_for_proto_request(
4473 buffer,
4474 |capabilities| {
4475 request.check_capabilities(AdapterServerCapabilities {
4476 server_capabilities: capabilities.clone(),
4477 code_action_kinds: None,
4478 })
4479 },
4480 cx,
4481 )
4482 }
4483
4484 fn check_if_capable_for_proto_request<F>(
4485 &self,
4486 buffer: &Entity<Buffer>,
4487 check: F,
4488 cx: &App,
4489 ) -> bool
4490 where
4491 F: FnMut(&lsp::ServerCapabilities) -> bool,
4492 {
4493 let Some(language) = buffer.read(cx).language().cloned() else {
4494 return false;
4495 };
4496 let relevant_language_servers = self
4497 .languages
4498 .lsp_adapters(&language.name())
4499 .into_iter()
4500 .map(|lsp_adapter| lsp_adapter.name())
4501 .collect::<HashSet<_>>();
4502 self.language_server_statuses
4503 .iter()
4504 .filter_map(|(server_id, server_status)| {
4505 relevant_language_servers
4506 .contains(&server_status.name)
4507 .then_some(server_id)
4508 })
4509 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4510 .any(check)
4511 }
4512
4513 fn all_capable_for_proto_request<F>(
4514 &self,
4515 buffer: &Entity<Buffer>,
4516 mut check: F,
4517 cx: &App,
4518 ) -> Vec<lsp::LanguageServerId>
4519 where
4520 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4521 {
4522 let Some(language) = buffer.read(cx).language().cloned() else {
4523 return Vec::default();
4524 };
4525 let relevant_language_servers = self
4526 .languages
4527 .lsp_adapters(&language.name())
4528 .into_iter()
4529 .map(|lsp_adapter| lsp_adapter.name())
4530 .collect::<HashSet<_>>();
4531 self.language_server_statuses
4532 .iter()
4533 .filter_map(|(server_id, server_status)| {
4534 relevant_language_servers
4535 .contains(&server_status.name)
4536 .then_some((server_id, &server_status.name))
4537 })
4538 .filter_map(|(server_id, server_name)| {
4539 self.lsp_server_capabilities
4540 .get(server_id)
4541 .map(|c| (server_id, server_name, c))
4542 })
4543 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4544 .map(|(server_id, _, _)| *server_id)
4545 .collect()
4546 }
4547
4548 pub fn request_lsp<R>(
4549 &mut self,
4550 buffer: Entity<Buffer>,
4551 server: LanguageServerToQuery,
4552 request: R,
4553 cx: &mut Context<Self>,
4554 ) -> Task<Result<R::Response>>
4555 where
4556 R: LspCommand,
4557 <R::LspRequest as lsp::request::Request>::Result: Send,
4558 <R::LspRequest as lsp::request::Request>::Params: Send,
4559 {
4560 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4561 return self.send_lsp_proto_request(
4562 buffer,
4563 upstream_client,
4564 upstream_project_id,
4565 request,
4566 cx,
4567 );
4568 }
4569
4570 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4571 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4572 local
4573 .language_servers_for_buffer(buffer, cx)
4574 .find(|(_, server)| {
4575 request.check_capabilities(server.adapter_server_capabilities())
4576 })
4577 .map(|(_, server)| server.clone())
4578 }),
4579 LanguageServerToQuery::Other(id) => self
4580 .language_server_for_local_buffer(buffer, id, cx)
4581 .and_then(|(_, server)| {
4582 request
4583 .check_capabilities(server.adapter_server_capabilities())
4584 .then(|| Arc::clone(server))
4585 }),
4586 }) else {
4587 return Task::ready(Ok(Default::default()));
4588 };
4589
4590 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4591
4592 let Some(file) = file else {
4593 return Task::ready(Ok(Default::default()));
4594 };
4595
4596 let lsp_params = match request.to_lsp_params_or_response(
4597 &file.abs_path(cx),
4598 buffer.read(cx),
4599 &language_server,
4600 cx,
4601 ) {
4602 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4603 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4604 Err(err) => {
4605 let message = format!(
4606 "{} via {} failed: {}",
4607 request.display_name(),
4608 language_server.name(),
4609 err
4610 );
4611 // rust-analyzer likes to error with this when its still loading up
4612 if !message.ends_with("content modified") {
4613 log::warn!("{message}");
4614 }
4615 return Task::ready(Err(anyhow!(message)));
4616 }
4617 };
4618
4619 let status = request.status();
4620 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4621 return Task::ready(Ok(Default::default()));
4622 }
4623 cx.spawn(async move |this, cx| {
4624 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4625
4626 let id = lsp_request.id();
4627 let _cleanup = if status.is_some() {
4628 cx.update(|cx| {
4629 this.update(cx, |this, cx| {
4630 this.on_lsp_work_start(
4631 language_server.server_id(),
4632 ProgressToken::Number(id),
4633 LanguageServerProgress {
4634 is_disk_based_diagnostics_progress: false,
4635 is_cancellable: false,
4636 title: None,
4637 message: status.clone(),
4638 percentage: None,
4639 last_update_at: cx.background_executor().now(),
4640 },
4641 cx,
4642 );
4643 })
4644 })
4645 .log_err();
4646
4647 Some(defer(|| {
4648 cx.update(|cx| {
4649 this.update(cx, |this, cx| {
4650 this.on_lsp_work_end(
4651 language_server.server_id(),
4652 ProgressToken::Number(id),
4653 cx,
4654 );
4655 })
4656 })
4657 .log_err();
4658 }))
4659 } else {
4660 None
4661 };
4662
4663 let result = lsp_request.await.into_response();
4664
4665 let response = result.map_err(|err| {
4666 let message = format!(
4667 "{} via {} failed: {}",
4668 request.display_name(),
4669 language_server.name(),
4670 err
4671 );
4672 // rust-analyzer likes to error with this when its still loading up
4673 if !message.ends_with("content modified") {
4674 log::warn!("{message}");
4675 }
4676 anyhow::anyhow!(message)
4677 })?;
4678
4679 request
4680 .response_from_lsp(
4681 response,
4682 this.upgrade().context("no app context")?,
4683 buffer,
4684 language_server.server_id(),
4685 cx.clone(),
4686 )
4687 .await
4688 })
4689 }
4690
4691 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4692 let mut language_formatters_to_check = Vec::new();
4693 for buffer in self.buffer_store.read(cx).buffers() {
4694 let buffer = buffer.read(cx);
4695 let buffer_file = File::from_dyn(buffer.file());
4696 let buffer_language = buffer.language();
4697 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4698 if buffer_language.is_some() {
4699 language_formatters_to_check.push((
4700 buffer_file.map(|f| f.worktree_id(cx)),
4701 settings.into_owned(),
4702 ));
4703 }
4704 }
4705
4706 self.request_workspace_config_refresh();
4707
4708 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4709 prettier_store.update(cx, |prettier_store, cx| {
4710 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4711 })
4712 }
4713
4714 cx.notify();
4715 }
4716
4717 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4718 let buffer_store = self.buffer_store.clone();
4719 let Some(local) = self.as_local_mut() else {
4720 return;
4721 };
4722 let mut adapters = BTreeMap::default();
4723 let get_adapter = {
4724 let languages = local.languages.clone();
4725 let environment = local.environment.clone();
4726 let weak = local.weak.clone();
4727 let worktree_store = local.worktree_store.clone();
4728 let http_client = local.http_client.clone();
4729 let fs = local.fs.clone();
4730 move |worktree_id, cx: &mut App| {
4731 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4732 Some(LocalLspAdapterDelegate::new(
4733 languages.clone(),
4734 &environment,
4735 weak.clone(),
4736 &worktree,
4737 http_client.clone(),
4738 fs.clone(),
4739 cx,
4740 ))
4741 }
4742 };
4743
4744 let mut messages_to_report = Vec::new();
4745 let (new_tree, to_stop) = {
4746 let mut rebase = local.lsp_tree.rebase();
4747 let buffers = buffer_store
4748 .read(cx)
4749 .buffers()
4750 .filter_map(|buffer| {
4751 let raw_buffer = buffer.read(cx);
4752 if !local
4753 .registered_buffers
4754 .contains_key(&raw_buffer.remote_id())
4755 {
4756 return None;
4757 }
4758 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4759 let language = raw_buffer.language().cloned()?;
4760 Some((file, language, raw_buffer.remote_id()))
4761 })
4762 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4763 for (file, language, buffer_id) in buffers {
4764 let worktree_id = file.worktree_id(cx);
4765 let Some(worktree) = local
4766 .worktree_store
4767 .read(cx)
4768 .worktree_for_id(worktree_id, cx)
4769 else {
4770 continue;
4771 };
4772
4773 if let Some((_, apply)) = local.reuse_existing_language_server(
4774 rebase.server_tree(),
4775 &worktree,
4776 &language.name(),
4777 cx,
4778 ) {
4779 (apply)(rebase.server_tree());
4780 } else if let Some(lsp_delegate) = adapters
4781 .entry(worktree_id)
4782 .or_insert_with(|| get_adapter(worktree_id, cx))
4783 .clone()
4784 {
4785 let delegate =
4786 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4787 let path = file
4788 .path()
4789 .parent()
4790 .map(Arc::from)
4791 .unwrap_or_else(|| file.path().clone());
4792 let worktree_path = ProjectPath { worktree_id, path };
4793 let abs_path = file.abs_path(cx);
4794 let nodes = rebase
4795 .walk(
4796 worktree_path,
4797 language.name(),
4798 language.manifest(),
4799 delegate.clone(),
4800 cx,
4801 )
4802 .collect::<Vec<_>>();
4803 for node in nodes {
4804 let server_id = node.server_id_or_init(|disposition| {
4805 let path = &disposition.path;
4806 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4807 let key = LanguageServerSeed {
4808 worktree_id,
4809 name: disposition.server_name.clone(),
4810 settings: disposition.settings.clone(),
4811 toolchain: local.toolchain_store.read(cx).active_toolchain(
4812 path.worktree_id,
4813 &path.path,
4814 language.name(),
4815 ),
4816 };
4817 local.language_server_ids.remove(&key);
4818
4819 let server_id = local.get_or_insert_language_server(
4820 &worktree,
4821 lsp_delegate.clone(),
4822 disposition,
4823 &language.name(),
4824 cx,
4825 );
4826 if let Some(state) = local.language_servers.get(&server_id)
4827 && let Ok(uri) = uri
4828 {
4829 state.add_workspace_folder(uri);
4830 };
4831 server_id
4832 });
4833
4834 if let Some(language_server_id) = server_id {
4835 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4836 language_server_id,
4837 name: node.name(),
4838 message:
4839 proto::update_language_server::Variant::RegisteredForBuffer(
4840 proto::RegisteredForBuffer {
4841 buffer_abs_path: abs_path
4842 .to_string_lossy()
4843 .into_owned(),
4844 buffer_id: buffer_id.to_proto(),
4845 },
4846 ),
4847 });
4848 }
4849 }
4850 } else {
4851 continue;
4852 }
4853 }
4854 rebase.finish()
4855 };
4856 for message in messages_to_report {
4857 cx.emit(message);
4858 }
4859 local.lsp_tree = new_tree;
4860 for (id, _) in to_stop {
4861 self.stop_local_language_server(id, cx).detach();
4862 }
4863 }
4864
4865 pub fn apply_code_action(
4866 &self,
4867 buffer_handle: Entity<Buffer>,
4868 mut action: CodeAction,
4869 push_to_history: bool,
4870 cx: &mut Context<Self>,
4871 ) -> Task<Result<ProjectTransaction>> {
4872 if let Some((upstream_client, project_id)) = self.upstream_client() {
4873 let request = proto::ApplyCodeAction {
4874 project_id,
4875 buffer_id: buffer_handle.read(cx).remote_id().into(),
4876 action: Some(Self::serialize_code_action(&action)),
4877 };
4878 let buffer_store = self.buffer_store();
4879 cx.spawn(async move |_, cx| {
4880 let response = upstream_client
4881 .request(request)
4882 .await?
4883 .transaction
4884 .context("missing transaction")?;
4885
4886 buffer_store
4887 .update(cx, |buffer_store, cx| {
4888 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4889 })?
4890 .await
4891 })
4892 } else if self.mode.is_local() {
4893 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4894 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4895 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4896 }) else {
4897 return Task::ready(Ok(ProjectTransaction::default()));
4898 };
4899 cx.spawn(async move |this, cx| {
4900 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4901 .await
4902 .context("resolving a code action")?;
4903 if let Some(edit) = action.lsp_action.edit()
4904 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4905 return LocalLspStore::deserialize_workspace_edit(
4906 this.upgrade().context("no app present")?,
4907 edit.clone(),
4908 push_to_history,
4909
4910 lang_server.clone(),
4911 cx,
4912 )
4913 .await;
4914 }
4915
4916 if let Some(command) = action.lsp_action.command() {
4917 let server_capabilities = lang_server.capabilities();
4918 let available_commands = server_capabilities
4919 .execute_command_provider
4920 .as_ref()
4921 .map(|options| options.commands.as_slice())
4922 .unwrap_or_default();
4923 if available_commands.contains(&command.command) {
4924 this.update(cx, |this, _| {
4925 this.as_local_mut()
4926 .unwrap()
4927 .last_workspace_edits_by_language_server
4928 .remove(&lang_server.server_id());
4929 })?;
4930
4931 let _result = lang_server
4932 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4933 command: command.command.clone(),
4934 arguments: command.arguments.clone().unwrap_or_default(),
4935 ..lsp::ExecuteCommandParams::default()
4936 })
4937 .await.into_response()
4938 .context("execute command")?;
4939
4940 return this.update(cx, |this, _| {
4941 this.as_local_mut()
4942 .unwrap()
4943 .last_workspace_edits_by_language_server
4944 .remove(&lang_server.server_id())
4945 .unwrap_or_default()
4946 });
4947 } else {
4948 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4949 }
4950 }
4951
4952 Ok(ProjectTransaction::default())
4953 })
4954 } else {
4955 Task::ready(Err(anyhow!("no upstream client and not local")))
4956 }
4957 }
4958
4959 pub fn apply_code_action_kind(
4960 &mut self,
4961 buffers: HashSet<Entity<Buffer>>,
4962 kind: CodeActionKind,
4963 push_to_history: bool,
4964 cx: &mut Context<Self>,
4965 ) -> Task<anyhow::Result<ProjectTransaction>> {
4966 if self.as_local().is_some() {
4967 cx.spawn(async move |lsp_store, cx| {
4968 let buffers = buffers.into_iter().collect::<Vec<_>>();
4969 let result = LocalLspStore::execute_code_action_kind_locally(
4970 lsp_store.clone(),
4971 buffers,
4972 kind,
4973 push_to_history,
4974 cx,
4975 )
4976 .await;
4977 lsp_store.update(cx, |lsp_store, _| {
4978 lsp_store.update_last_formatting_failure(&result);
4979 })?;
4980 result
4981 })
4982 } else if let Some((client, project_id)) = self.upstream_client() {
4983 let buffer_store = self.buffer_store();
4984 cx.spawn(async move |lsp_store, cx| {
4985 let result = client
4986 .request(proto::ApplyCodeActionKind {
4987 project_id,
4988 kind: kind.as_str().to_owned(),
4989 buffer_ids: buffers
4990 .iter()
4991 .map(|buffer| {
4992 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4993 })
4994 .collect::<Result<_>>()?,
4995 })
4996 .await
4997 .and_then(|result| result.transaction.context("missing transaction"));
4998 lsp_store.update(cx, |lsp_store, _| {
4999 lsp_store.update_last_formatting_failure(&result);
5000 })?;
5001
5002 let transaction_response = result?;
5003 buffer_store
5004 .update(cx, |buffer_store, cx| {
5005 buffer_store.deserialize_project_transaction(
5006 transaction_response,
5007 push_to_history,
5008 cx,
5009 )
5010 })?
5011 .await
5012 })
5013 } else {
5014 Task::ready(Ok(ProjectTransaction::default()))
5015 }
5016 }
5017
5018 pub fn resolved_hint(
5019 &mut self,
5020 buffer_id: BufferId,
5021 id: InlayId,
5022 cx: &mut Context<Self>,
5023 ) -> Option<ResolvedHint> {
5024 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5025
5026 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5027 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5028 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5029 let (server_id, resolve_data) = match &hint.resolve_state {
5030 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5031 ResolveState::Resolving => {
5032 return Some(ResolvedHint::Resolving(
5033 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5034 ));
5035 }
5036 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5037 };
5038
5039 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5040 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5041 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5042 id,
5043 cx.spawn(async move |lsp_store, cx| {
5044 let resolved_hint = resolve_task.await;
5045 lsp_store
5046 .update(cx, |lsp_store, _| {
5047 if let Some(old_inlay_hint) = lsp_store
5048 .lsp_data
5049 .get_mut(&buffer_id)
5050 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5051 {
5052 match resolved_hint {
5053 Ok(resolved_hint) => {
5054 *old_inlay_hint = resolved_hint;
5055 }
5056 Err(e) => {
5057 old_inlay_hint.resolve_state =
5058 ResolveState::CanResolve(server_id, resolve_data);
5059 log::error!("Inlay hint resolve failed: {e:#}");
5060 }
5061 }
5062 }
5063 })
5064 .ok();
5065 })
5066 .shared(),
5067 );
5068 debug_assert!(
5069 previous_task.is_none(),
5070 "Did not change hint's resolve state after spawning its resolve"
5071 );
5072 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5073 None
5074 }
5075
5076 fn resolve_inlay_hint(
5077 &self,
5078 mut hint: InlayHint,
5079 buffer: Entity<Buffer>,
5080 server_id: LanguageServerId,
5081 cx: &mut Context<Self>,
5082 ) -> Task<anyhow::Result<InlayHint>> {
5083 if let Some((upstream_client, project_id)) = self.upstream_client() {
5084 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5085 {
5086 hint.resolve_state = ResolveState::Resolved;
5087 return Task::ready(Ok(hint));
5088 }
5089 let request = proto::ResolveInlayHint {
5090 project_id,
5091 buffer_id: buffer.read(cx).remote_id().into(),
5092 language_server_id: server_id.0 as u64,
5093 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5094 };
5095 cx.background_spawn(async move {
5096 let response = upstream_client
5097 .request(request)
5098 .await
5099 .context("inlay hints proto request")?;
5100 match response.hint {
5101 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5102 .context("inlay hints proto resolve response conversion"),
5103 None => Ok(hint),
5104 }
5105 })
5106 } else {
5107 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5108 self.language_server_for_local_buffer(buffer, server_id, cx)
5109 .map(|(_, server)| server.clone())
5110 }) else {
5111 return Task::ready(Ok(hint));
5112 };
5113 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5114 return Task::ready(Ok(hint));
5115 }
5116 let buffer_snapshot = buffer.read(cx).snapshot();
5117 cx.spawn(async move |_, cx| {
5118 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5119 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5120 );
5121 let resolved_hint = resolve_task
5122 .await
5123 .into_response()
5124 .context("inlay hint resolve LSP request")?;
5125 let resolved_hint = InlayHints::lsp_to_project_hint(
5126 resolved_hint,
5127 &buffer,
5128 server_id,
5129 ResolveState::Resolved,
5130 false,
5131 cx,
5132 )
5133 .await?;
5134 Ok(resolved_hint)
5135 })
5136 }
5137 }
5138
5139 pub fn resolve_color_presentation(
5140 &mut self,
5141 mut color: DocumentColor,
5142 buffer: Entity<Buffer>,
5143 server_id: LanguageServerId,
5144 cx: &mut Context<Self>,
5145 ) -> Task<Result<DocumentColor>> {
5146 if color.resolved {
5147 return Task::ready(Ok(color));
5148 }
5149
5150 if let Some((upstream_client, project_id)) = self.upstream_client() {
5151 let start = color.lsp_range.start;
5152 let end = color.lsp_range.end;
5153 let request = proto::GetColorPresentation {
5154 project_id,
5155 server_id: server_id.to_proto(),
5156 buffer_id: buffer.read(cx).remote_id().into(),
5157 color: Some(proto::ColorInformation {
5158 red: color.color.red,
5159 green: color.color.green,
5160 blue: color.color.blue,
5161 alpha: color.color.alpha,
5162 lsp_range_start: Some(proto::PointUtf16 {
5163 row: start.line,
5164 column: start.character,
5165 }),
5166 lsp_range_end: Some(proto::PointUtf16 {
5167 row: end.line,
5168 column: end.character,
5169 }),
5170 }),
5171 };
5172 cx.background_spawn(async move {
5173 let response = upstream_client
5174 .request(request)
5175 .await
5176 .context("color presentation proto request")?;
5177 color.resolved = true;
5178 color.color_presentations = response
5179 .presentations
5180 .into_iter()
5181 .map(|presentation| ColorPresentation {
5182 label: SharedString::from(presentation.label),
5183 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5184 additional_text_edits: presentation
5185 .additional_text_edits
5186 .into_iter()
5187 .filter_map(deserialize_lsp_edit)
5188 .collect(),
5189 })
5190 .collect();
5191 Ok(color)
5192 })
5193 } else {
5194 let path = match buffer
5195 .update(cx, |buffer, cx| {
5196 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5197 })
5198 .context("buffer with the missing path")
5199 {
5200 Ok(path) => path,
5201 Err(e) => return Task::ready(Err(e)),
5202 };
5203 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5204 self.language_server_for_local_buffer(buffer, server_id, cx)
5205 .map(|(_, server)| server.clone())
5206 }) else {
5207 return Task::ready(Ok(color));
5208 };
5209 cx.background_spawn(async move {
5210 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5211 lsp::ColorPresentationParams {
5212 text_document: make_text_document_identifier(&path)?,
5213 color: color.color,
5214 range: color.lsp_range,
5215 work_done_progress_params: Default::default(),
5216 partial_result_params: Default::default(),
5217 },
5218 );
5219 color.color_presentations = resolve_task
5220 .await
5221 .into_response()
5222 .context("color presentation resolve LSP request")?
5223 .into_iter()
5224 .map(|presentation| ColorPresentation {
5225 label: SharedString::from(presentation.label),
5226 text_edit: presentation.text_edit,
5227 additional_text_edits: presentation
5228 .additional_text_edits
5229 .unwrap_or_default(),
5230 })
5231 .collect();
5232 color.resolved = true;
5233 Ok(color)
5234 })
5235 }
5236 }
5237
5238 pub(crate) fn linked_edits(
5239 &mut self,
5240 buffer: &Entity<Buffer>,
5241 position: Anchor,
5242 cx: &mut Context<Self>,
5243 ) -> Task<Result<Vec<Range<Anchor>>>> {
5244 let snapshot = buffer.read(cx).snapshot();
5245 let scope = snapshot.language_scope_at(position);
5246 let Some(server_id) = self
5247 .as_local()
5248 .and_then(|local| {
5249 buffer.update(cx, |buffer, cx| {
5250 local
5251 .language_servers_for_buffer(buffer, cx)
5252 .filter(|(_, server)| {
5253 LinkedEditingRange::check_server_capabilities(server.capabilities())
5254 })
5255 .filter(|(adapter, _)| {
5256 scope
5257 .as_ref()
5258 .map(|scope| scope.language_allowed(&adapter.name))
5259 .unwrap_or(true)
5260 })
5261 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5262 .next()
5263 })
5264 })
5265 .or_else(|| {
5266 self.upstream_client()
5267 .is_some()
5268 .then_some(LanguageServerToQuery::FirstCapable)
5269 })
5270 .filter(|_| {
5271 maybe!({
5272 let language = buffer.read(cx).language_at(position)?;
5273 Some(
5274 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5275 .linked_edits,
5276 )
5277 }) == Some(true)
5278 })
5279 else {
5280 return Task::ready(Ok(Vec::new()));
5281 };
5282
5283 self.request_lsp(
5284 buffer.clone(),
5285 server_id,
5286 LinkedEditingRange { position },
5287 cx,
5288 )
5289 }
5290
5291 fn apply_on_type_formatting(
5292 &mut self,
5293 buffer: Entity<Buffer>,
5294 position: Anchor,
5295 trigger: String,
5296 cx: &mut Context<Self>,
5297 ) -> Task<Result<Option<Transaction>>> {
5298 if let Some((client, project_id)) = self.upstream_client() {
5299 if !self.check_if_capable_for_proto_request(
5300 &buffer,
5301 |capabilities| {
5302 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5303 },
5304 cx,
5305 ) {
5306 return Task::ready(Ok(None));
5307 }
5308 let request = proto::OnTypeFormatting {
5309 project_id,
5310 buffer_id: buffer.read(cx).remote_id().into(),
5311 position: Some(serialize_anchor(&position)),
5312 trigger,
5313 version: serialize_version(&buffer.read(cx).version()),
5314 };
5315 cx.background_spawn(async move {
5316 client
5317 .request(request)
5318 .await?
5319 .transaction
5320 .map(language::proto::deserialize_transaction)
5321 .transpose()
5322 })
5323 } else if let Some(local) = self.as_local_mut() {
5324 let buffer_id = buffer.read(cx).remote_id();
5325 local.buffers_being_formatted.insert(buffer_id);
5326 cx.spawn(async move |this, cx| {
5327 let _cleanup = defer({
5328 let this = this.clone();
5329 let mut cx = cx.clone();
5330 move || {
5331 this.update(&mut cx, |this, _| {
5332 if let Some(local) = this.as_local_mut() {
5333 local.buffers_being_formatted.remove(&buffer_id);
5334 }
5335 })
5336 .ok();
5337 }
5338 });
5339
5340 buffer
5341 .update(cx, |buffer, _| {
5342 buffer.wait_for_edits(Some(position.timestamp))
5343 })?
5344 .await?;
5345 this.update(cx, |this, cx| {
5346 let position = position.to_point_utf16(buffer.read(cx));
5347 this.on_type_format(buffer, position, trigger, false, cx)
5348 })?
5349 .await
5350 })
5351 } else {
5352 Task::ready(Err(anyhow!("No upstream client or local language server")))
5353 }
5354 }
5355
5356 pub fn on_type_format<T: ToPointUtf16>(
5357 &mut self,
5358 buffer: Entity<Buffer>,
5359 position: T,
5360 trigger: String,
5361 push_to_history: bool,
5362 cx: &mut Context<Self>,
5363 ) -> Task<Result<Option<Transaction>>> {
5364 let position = position.to_point_utf16(buffer.read(cx));
5365 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5366 }
5367
5368 fn on_type_format_impl(
5369 &mut self,
5370 buffer: Entity<Buffer>,
5371 position: PointUtf16,
5372 trigger: String,
5373 push_to_history: bool,
5374 cx: &mut Context<Self>,
5375 ) -> Task<Result<Option<Transaction>>> {
5376 let options = buffer.update(cx, |buffer, cx| {
5377 lsp_command::lsp_formatting_options(
5378 language_settings(
5379 buffer.language_at(position).map(|l| l.name()),
5380 buffer.file(),
5381 cx,
5382 )
5383 .as_ref(),
5384 )
5385 });
5386
5387 cx.spawn(async move |this, cx| {
5388 if let Some(waiter) =
5389 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5390 {
5391 waiter.await?;
5392 }
5393 cx.update(|cx| {
5394 this.update(cx, |this, cx| {
5395 this.request_lsp(
5396 buffer.clone(),
5397 LanguageServerToQuery::FirstCapable,
5398 OnTypeFormatting {
5399 position,
5400 trigger,
5401 options,
5402 push_to_history,
5403 },
5404 cx,
5405 )
5406 })
5407 })??
5408 .await
5409 })
5410 }
5411
5412 pub fn definitions(
5413 &mut self,
5414 buffer: &Entity<Buffer>,
5415 position: PointUtf16,
5416 cx: &mut Context<Self>,
5417 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5418 if let Some((upstream_client, project_id)) = self.upstream_client() {
5419 let request = GetDefinitions { position };
5420 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5421 return Task::ready(Ok(None));
5422 }
5423 let request_task = upstream_client.request_lsp(
5424 project_id,
5425 None,
5426 LSP_REQUEST_TIMEOUT,
5427 cx.background_executor().clone(),
5428 request.to_proto(project_id, buffer.read(cx)),
5429 );
5430 let buffer = buffer.clone();
5431 cx.spawn(async move |weak_lsp_store, cx| {
5432 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5433 return Ok(None);
5434 };
5435 let Some(responses) = request_task.await? else {
5436 return Ok(None);
5437 };
5438 let actions = join_all(responses.payload.into_iter().map(|response| {
5439 GetDefinitions { position }.response_from_proto(
5440 response.response,
5441 lsp_store.clone(),
5442 buffer.clone(),
5443 cx.clone(),
5444 )
5445 }))
5446 .await;
5447
5448 Ok(Some(
5449 actions
5450 .into_iter()
5451 .collect::<Result<Vec<Vec<_>>>>()?
5452 .into_iter()
5453 .flatten()
5454 .dedup()
5455 .collect(),
5456 ))
5457 })
5458 } else {
5459 let definitions_task = self.request_multiple_lsp_locally(
5460 buffer,
5461 Some(position),
5462 GetDefinitions { position },
5463 cx,
5464 );
5465 cx.background_spawn(async move {
5466 Ok(Some(
5467 definitions_task
5468 .await
5469 .into_iter()
5470 .flat_map(|(_, definitions)| definitions)
5471 .dedup()
5472 .collect(),
5473 ))
5474 })
5475 }
5476 }
5477
5478 pub fn declarations(
5479 &mut self,
5480 buffer: &Entity<Buffer>,
5481 position: PointUtf16,
5482 cx: &mut Context<Self>,
5483 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5484 if let Some((upstream_client, project_id)) = self.upstream_client() {
5485 let request = GetDeclarations { position };
5486 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5487 return Task::ready(Ok(None));
5488 }
5489 let request_task = upstream_client.request_lsp(
5490 project_id,
5491 None,
5492 LSP_REQUEST_TIMEOUT,
5493 cx.background_executor().clone(),
5494 request.to_proto(project_id, buffer.read(cx)),
5495 );
5496 let buffer = buffer.clone();
5497 cx.spawn(async move |weak_lsp_store, cx| {
5498 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5499 return Ok(None);
5500 };
5501 let Some(responses) = request_task.await? else {
5502 return Ok(None);
5503 };
5504 let actions = join_all(responses.payload.into_iter().map(|response| {
5505 GetDeclarations { position }.response_from_proto(
5506 response.response,
5507 lsp_store.clone(),
5508 buffer.clone(),
5509 cx.clone(),
5510 )
5511 }))
5512 .await;
5513
5514 Ok(Some(
5515 actions
5516 .into_iter()
5517 .collect::<Result<Vec<Vec<_>>>>()?
5518 .into_iter()
5519 .flatten()
5520 .dedup()
5521 .collect(),
5522 ))
5523 })
5524 } else {
5525 let declarations_task = self.request_multiple_lsp_locally(
5526 buffer,
5527 Some(position),
5528 GetDeclarations { position },
5529 cx,
5530 );
5531 cx.background_spawn(async move {
5532 Ok(Some(
5533 declarations_task
5534 .await
5535 .into_iter()
5536 .flat_map(|(_, declarations)| declarations)
5537 .dedup()
5538 .collect(),
5539 ))
5540 })
5541 }
5542 }
5543
5544 pub fn type_definitions(
5545 &mut self,
5546 buffer: &Entity<Buffer>,
5547 position: PointUtf16,
5548 cx: &mut Context<Self>,
5549 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5550 if let Some((upstream_client, project_id)) = self.upstream_client() {
5551 let request = GetTypeDefinitions { position };
5552 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5553 return Task::ready(Ok(None));
5554 }
5555 let request_task = upstream_client.request_lsp(
5556 project_id,
5557 None,
5558 LSP_REQUEST_TIMEOUT,
5559 cx.background_executor().clone(),
5560 request.to_proto(project_id, buffer.read(cx)),
5561 );
5562 let buffer = buffer.clone();
5563 cx.spawn(async move |weak_lsp_store, cx| {
5564 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5565 return Ok(None);
5566 };
5567 let Some(responses) = request_task.await? else {
5568 return Ok(None);
5569 };
5570 let actions = join_all(responses.payload.into_iter().map(|response| {
5571 GetTypeDefinitions { position }.response_from_proto(
5572 response.response,
5573 lsp_store.clone(),
5574 buffer.clone(),
5575 cx.clone(),
5576 )
5577 }))
5578 .await;
5579
5580 Ok(Some(
5581 actions
5582 .into_iter()
5583 .collect::<Result<Vec<Vec<_>>>>()?
5584 .into_iter()
5585 .flatten()
5586 .dedup()
5587 .collect(),
5588 ))
5589 })
5590 } else {
5591 let type_definitions_task = self.request_multiple_lsp_locally(
5592 buffer,
5593 Some(position),
5594 GetTypeDefinitions { position },
5595 cx,
5596 );
5597 cx.background_spawn(async move {
5598 Ok(Some(
5599 type_definitions_task
5600 .await
5601 .into_iter()
5602 .flat_map(|(_, type_definitions)| type_definitions)
5603 .dedup()
5604 .collect(),
5605 ))
5606 })
5607 }
5608 }
5609
5610 pub fn implementations(
5611 &mut self,
5612 buffer: &Entity<Buffer>,
5613 position: PointUtf16,
5614 cx: &mut Context<Self>,
5615 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5616 if let Some((upstream_client, project_id)) = self.upstream_client() {
5617 let request = GetImplementations { position };
5618 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5619 return Task::ready(Ok(None));
5620 }
5621 let request_task = upstream_client.request_lsp(
5622 project_id,
5623 None,
5624 LSP_REQUEST_TIMEOUT,
5625 cx.background_executor().clone(),
5626 request.to_proto(project_id, buffer.read(cx)),
5627 );
5628 let buffer = buffer.clone();
5629 cx.spawn(async move |weak_lsp_store, cx| {
5630 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5631 return Ok(None);
5632 };
5633 let Some(responses) = request_task.await? else {
5634 return Ok(None);
5635 };
5636 let actions = join_all(responses.payload.into_iter().map(|response| {
5637 GetImplementations { position }.response_from_proto(
5638 response.response,
5639 lsp_store.clone(),
5640 buffer.clone(),
5641 cx.clone(),
5642 )
5643 }))
5644 .await;
5645
5646 Ok(Some(
5647 actions
5648 .into_iter()
5649 .collect::<Result<Vec<Vec<_>>>>()?
5650 .into_iter()
5651 .flatten()
5652 .dedup()
5653 .collect(),
5654 ))
5655 })
5656 } else {
5657 let implementations_task = self.request_multiple_lsp_locally(
5658 buffer,
5659 Some(position),
5660 GetImplementations { position },
5661 cx,
5662 );
5663 cx.background_spawn(async move {
5664 Ok(Some(
5665 implementations_task
5666 .await
5667 .into_iter()
5668 .flat_map(|(_, implementations)| implementations)
5669 .dedup()
5670 .collect(),
5671 ))
5672 })
5673 }
5674 }
5675
5676 pub fn references(
5677 &mut self,
5678 buffer: &Entity<Buffer>,
5679 position: PointUtf16,
5680 cx: &mut Context<Self>,
5681 ) -> Task<Result<Option<Vec<Location>>>> {
5682 if let Some((upstream_client, project_id)) = self.upstream_client() {
5683 let request = GetReferences { position };
5684 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5685 return Task::ready(Ok(None));
5686 }
5687
5688 let request_task = upstream_client.request_lsp(
5689 project_id,
5690 None,
5691 LSP_REQUEST_TIMEOUT,
5692 cx.background_executor().clone(),
5693 request.to_proto(project_id, buffer.read(cx)),
5694 );
5695 let buffer = buffer.clone();
5696 cx.spawn(async move |weak_lsp_store, cx| {
5697 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5698 return Ok(None);
5699 };
5700 let Some(responses) = request_task.await? else {
5701 return Ok(None);
5702 };
5703
5704 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5705 GetReferences { position }.response_from_proto(
5706 lsp_response.response,
5707 lsp_store.clone(),
5708 buffer.clone(),
5709 cx.clone(),
5710 )
5711 }))
5712 .await
5713 .into_iter()
5714 .collect::<Result<Vec<Vec<_>>>>()?
5715 .into_iter()
5716 .flatten()
5717 .dedup()
5718 .collect();
5719 Ok(Some(locations))
5720 })
5721 } else {
5722 let references_task = self.request_multiple_lsp_locally(
5723 buffer,
5724 Some(position),
5725 GetReferences { position },
5726 cx,
5727 );
5728 cx.background_spawn(async move {
5729 Ok(Some(
5730 references_task
5731 .await
5732 .into_iter()
5733 .flat_map(|(_, references)| references)
5734 .dedup()
5735 .collect(),
5736 ))
5737 })
5738 }
5739 }
5740
5741 pub fn code_actions(
5742 &mut self,
5743 buffer: &Entity<Buffer>,
5744 range: Range<Anchor>,
5745 kinds: Option<Vec<CodeActionKind>>,
5746 cx: &mut Context<Self>,
5747 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5748 if let Some((upstream_client, project_id)) = self.upstream_client() {
5749 let request = GetCodeActions {
5750 range: range.clone(),
5751 kinds: kinds.clone(),
5752 };
5753 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5754 return Task::ready(Ok(None));
5755 }
5756 let request_task = upstream_client.request_lsp(
5757 project_id,
5758 None,
5759 LSP_REQUEST_TIMEOUT,
5760 cx.background_executor().clone(),
5761 request.to_proto(project_id, buffer.read(cx)),
5762 );
5763 let buffer = buffer.clone();
5764 cx.spawn(async move |weak_lsp_store, cx| {
5765 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5766 return Ok(None);
5767 };
5768 let Some(responses) = request_task.await? else {
5769 return Ok(None);
5770 };
5771 let actions = join_all(responses.payload.into_iter().map(|response| {
5772 GetCodeActions {
5773 range: range.clone(),
5774 kinds: kinds.clone(),
5775 }
5776 .response_from_proto(
5777 response.response,
5778 lsp_store.clone(),
5779 buffer.clone(),
5780 cx.clone(),
5781 )
5782 }))
5783 .await;
5784
5785 Ok(Some(
5786 actions
5787 .into_iter()
5788 .collect::<Result<Vec<Vec<_>>>>()?
5789 .into_iter()
5790 .flatten()
5791 .collect(),
5792 ))
5793 })
5794 } else {
5795 let all_actions_task = self.request_multiple_lsp_locally(
5796 buffer,
5797 Some(range.start),
5798 GetCodeActions { range, kinds },
5799 cx,
5800 );
5801 cx.background_spawn(async move {
5802 Ok(Some(
5803 all_actions_task
5804 .await
5805 .into_iter()
5806 .flat_map(|(_, actions)| actions)
5807 .collect(),
5808 ))
5809 })
5810 }
5811 }
5812
5813 pub fn code_lens_actions(
5814 &mut self,
5815 buffer: &Entity<Buffer>,
5816 cx: &mut Context<Self>,
5817 ) -> CodeLensTask {
5818 let version_queried_for = buffer.read(cx).version();
5819 let buffer_id = buffer.read(cx).remote_id();
5820 let existing_servers = self.as_local().map(|local| {
5821 local
5822 .buffers_opened_in_servers
5823 .get(&buffer_id)
5824 .cloned()
5825 .unwrap_or_default()
5826 });
5827
5828 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5829 if let Some(cached_lens) = &lsp_data.code_lens {
5830 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5831 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5832 existing_servers != cached_lens.lens.keys().copied().collect()
5833 });
5834 if !has_different_servers {
5835 return Task::ready(Ok(Some(
5836 cached_lens.lens.values().flatten().cloned().collect(),
5837 )))
5838 .shared();
5839 }
5840 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5841 if !version_queried_for.changed_since(updating_for) {
5842 return running_update.clone();
5843 }
5844 }
5845 }
5846 }
5847
5848 let lens_lsp_data = self
5849 .latest_lsp_data(buffer, cx)
5850 .code_lens
5851 .get_or_insert_default();
5852 let buffer = buffer.clone();
5853 let query_version_queried_for = version_queried_for.clone();
5854 let new_task = cx
5855 .spawn(async move |lsp_store, cx| {
5856 cx.background_executor()
5857 .timer(Duration::from_millis(30))
5858 .await;
5859 let fetched_lens = lsp_store
5860 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5861 .map_err(Arc::new)?
5862 .await
5863 .context("fetching code lens")
5864 .map_err(Arc::new);
5865 let fetched_lens = match fetched_lens {
5866 Ok(fetched_lens) => fetched_lens,
5867 Err(e) => {
5868 lsp_store
5869 .update(cx, |lsp_store, _| {
5870 if let Some(lens_lsp_data) = lsp_store
5871 .lsp_data
5872 .get_mut(&buffer_id)
5873 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5874 {
5875 lens_lsp_data.update = None;
5876 }
5877 })
5878 .ok();
5879 return Err(e);
5880 }
5881 };
5882
5883 lsp_store
5884 .update(cx, |lsp_store, _| {
5885 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5886 let code_lens = lsp_data.code_lens.as_mut()?;
5887 if let Some(fetched_lens) = fetched_lens {
5888 if lsp_data.buffer_version == query_version_queried_for {
5889 code_lens.lens.extend(fetched_lens);
5890 } else if !lsp_data
5891 .buffer_version
5892 .changed_since(&query_version_queried_for)
5893 {
5894 lsp_data.buffer_version = query_version_queried_for;
5895 code_lens.lens = fetched_lens;
5896 }
5897 }
5898 code_lens.update = None;
5899 Some(code_lens.lens.values().flatten().cloned().collect())
5900 })
5901 .map_err(Arc::new)
5902 })
5903 .shared();
5904 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5905 new_task
5906 }
5907
5908 fn fetch_code_lens(
5909 &mut self,
5910 buffer: &Entity<Buffer>,
5911 cx: &mut Context<Self>,
5912 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5913 if let Some((upstream_client, project_id)) = self.upstream_client() {
5914 let request = GetCodeLens;
5915 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5916 return Task::ready(Ok(None));
5917 }
5918 let request_task = upstream_client.request_lsp(
5919 project_id,
5920 None,
5921 LSP_REQUEST_TIMEOUT,
5922 cx.background_executor().clone(),
5923 request.to_proto(project_id, buffer.read(cx)),
5924 );
5925 let buffer = buffer.clone();
5926 cx.spawn(async move |weak_lsp_store, cx| {
5927 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5928 return Ok(None);
5929 };
5930 let Some(responses) = request_task.await? else {
5931 return Ok(None);
5932 };
5933
5934 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5935 let lsp_store = lsp_store.clone();
5936 let buffer = buffer.clone();
5937 let cx = cx.clone();
5938 async move {
5939 (
5940 LanguageServerId::from_proto(response.server_id),
5941 GetCodeLens
5942 .response_from_proto(response.response, lsp_store, buffer, cx)
5943 .await,
5944 )
5945 }
5946 }))
5947 .await;
5948
5949 let mut has_errors = false;
5950 let code_lens_actions = code_lens_actions
5951 .into_iter()
5952 .filter_map(|(server_id, code_lens)| match code_lens {
5953 Ok(code_lens) => Some((server_id, code_lens)),
5954 Err(e) => {
5955 has_errors = true;
5956 log::error!("{e:#}");
5957 None
5958 }
5959 })
5960 .collect::<HashMap<_, _>>();
5961 anyhow::ensure!(
5962 !has_errors || !code_lens_actions.is_empty(),
5963 "Failed to fetch code lens"
5964 );
5965 Ok(Some(code_lens_actions))
5966 })
5967 } else {
5968 let code_lens_actions_task =
5969 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5970 cx.background_spawn(async move {
5971 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5972 })
5973 }
5974 }
5975
5976 #[inline(never)]
5977 pub fn completions(
5978 &self,
5979 buffer: &Entity<Buffer>,
5980 position: PointUtf16,
5981 context: CompletionContext,
5982 cx: &mut Context<Self>,
5983 ) -> Task<Result<Vec<CompletionResponse>>> {
5984 let language_registry = self.languages.clone();
5985
5986 if let Some((upstream_client, project_id)) = self.upstream_client() {
5987 let snapshot = buffer.read(cx).snapshot();
5988 let offset = position.to_offset(&snapshot);
5989 let scope = snapshot.language_scope_at(offset);
5990 let capable_lsps = self.all_capable_for_proto_request(
5991 buffer,
5992 |server_name, capabilities| {
5993 capabilities.completion_provider.is_some()
5994 && scope
5995 .as_ref()
5996 .map(|scope| scope.language_allowed(server_name))
5997 .unwrap_or(true)
5998 },
5999 cx,
6000 );
6001 if capable_lsps.is_empty() {
6002 return Task::ready(Ok(Vec::new()));
6003 }
6004
6005 let language = buffer.read(cx).language().cloned();
6006
6007 // In the future, we should provide project guests with the names of LSP adapters,
6008 // so that they can use the correct LSP adapter when computing labels. For now,
6009 // guests just use the first LSP adapter associated with the buffer's language.
6010 let lsp_adapter = language.as_ref().and_then(|language| {
6011 language_registry
6012 .lsp_adapters(&language.name())
6013 .first()
6014 .cloned()
6015 });
6016
6017 let buffer = buffer.clone();
6018
6019 cx.spawn(async move |this, cx| {
6020 let requests = join_all(
6021 capable_lsps
6022 .into_iter()
6023 .map(|id| {
6024 let request = GetCompletions {
6025 position,
6026 context: context.clone(),
6027 server_id: Some(id),
6028 };
6029 let buffer = buffer.clone();
6030 let language = language.clone();
6031 let lsp_adapter = lsp_adapter.clone();
6032 let upstream_client = upstream_client.clone();
6033 let response = this
6034 .update(cx, |this, cx| {
6035 this.send_lsp_proto_request(
6036 buffer,
6037 upstream_client,
6038 project_id,
6039 request,
6040 cx,
6041 )
6042 })
6043 .log_err();
6044 async move {
6045 let response = response?.await.log_err()?;
6046
6047 let completions = populate_labels_for_completions(
6048 response.completions,
6049 language,
6050 lsp_adapter,
6051 )
6052 .await;
6053
6054 Some(CompletionResponse {
6055 completions,
6056 display_options: CompletionDisplayOptions::default(),
6057 is_incomplete: response.is_incomplete,
6058 })
6059 }
6060 })
6061 .collect::<Vec<_>>(),
6062 );
6063 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6064 })
6065 } else if let Some(local) = self.as_local() {
6066 let snapshot = buffer.read(cx).snapshot();
6067 let offset = position.to_offset(&snapshot);
6068 let scope = snapshot.language_scope_at(offset);
6069 let language = snapshot.language().cloned();
6070 let completion_settings = language_settings(
6071 language.as_ref().map(|language| language.name()),
6072 buffer.read(cx).file(),
6073 cx,
6074 )
6075 .completions
6076 .clone();
6077 if !completion_settings.lsp {
6078 return Task::ready(Ok(Vec::new()));
6079 }
6080
6081 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6082 local
6083 .language_servers_for_buffer(buffer, cx)
6084 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6085 .filter(|(adapter, _)| {
6086 scope
6087 .as_ref()
6088 .map(|scope| scope.language_allowed(&adapter.name))
6089 .unwrap_or(true)
6090 })
6091 .map(|(_, server)| server.server_id())
6092 .collect()
6093 });
6094
6095 let buffer = buffer.clone();
6096 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6097 let lsp_timeout = if lsp_timeout > 0 {
6098 Some(Duration::from_millis(lsp_timeout))
6099 } else {
6100 None
6101 };
6102 cx.spawn(async move |this, cx| {
6103 let mut tasks = Vec::with_capacity(server_ids.len());
6104 this.update(cx, |lsp_store, cx| {
6105 for server_id in server_ids {
6106 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6107 let lsp_timeout = lsp_timeout
6108 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6109 let mut timeout = cx.background_spawn(async move {
6110 match lsp_timeout {
6111 Some(lsp_timeout) => {
6112 lsp_timeout.await;
6113 true
6114 },
6115 None => false,
6116 }
6117 }).fuse();
6118 let mut lsp_request = lsp_store.request_lsp(
6119 buffer.clone(),
6120 LanguageServerToQuery::Other(server_id),
6121 GetCompletions {
6122 position,
6123 context: context.clone(),
6124 server_id: Some(server_id),
6125 },
6126 cx,
6127 ).fuse();
6128 let new_task = cx.background_spawn(async move {
6129 select_biased! {
6130 response = lsp_request => anyhow::Ok(Some(response?)),
6131 timeout_happened = timeout => {
6132 if timeout_happened {
6133 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6134 Ok(None)
6135 } else {
6136 let completions = lsp_request.await?;
6137 Ok(Some(completions))
6138 }
6139 },
6140 }
6141 });
6142 tasks.push((lsp_adapter, new_task));
6143 }
6144 })?;
6145
6146 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6147 let completion_response = task.await.ok()??;
6148 let completions = populate_labels_for_completions(
6149 completion_response.completions,
6150 language.clone(),
6151 lsp_adapter,
6152 )
6153 .await;
6154 Some(CompletionResponse {
6155 completions,
6156 display_options: CompletionDisplayOptions::default(),
6157 is_incomplete: completion_response.is_incomplete,
6158 })
6159 });
6160
6161 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6162
6163 Ok(responses.into_iter().flatten().collect())
6164 })
6165 } else {
6166 Task::ready(Err(anyhow!("No upstream client or local language server")))
6167 }
6168 }
6169
6170 pub fn resolve_completions(
6171 &self,
6172 buffer: Entity<Buffer>,
6173 completion_indices: Vec<usize>,
6174 completions: Rc<RefCell<Box<[Completion]>>>,
6175 cx: &mut Context<Self>,
6176 ) -> Task<Result<bool>> {
6177 let client = self.upstream_client();
6178 let buffer_id = buffer.read(cx).remote_id();
6179 let buffer_snapshot = buffer.read(cx).snapshot();
6180
6181 if !self.check_if_capable_for_proto_request(
6182 &buffer,
6183 GetCompletions::can_resolve_completions,
6184 cx,
6185 ) {
6186 return Task::ready(Ok(false));
6187 }
6188 cx.spawn(async move |lsp_store, cx| {
6189 let mut did_resolve = false;
6190 if let Some((client, project_id)) = client {
6191 for completion_index in completion_indices {
6192 let server_id = {
6193 let completion = &completions.borrow()[completion_index];
6194 completion.source.server_id()
6195 };
6196 if let Some(server_id) = server_id {
6197 if Self::resolve_completion_remote(
6198 project_id,
6199 server_id,
6200 buffer_id,
6201 completions.clone(),
6202 completion_index,
6203 client.clone(),
6204 )
6205 .await
6206 .log_err()
6207 .is_some()
6208 {
6209 did_resolve = true;
6210 }
6211 } else {
6212 resolve_word_completion(
6213 &buffer_snapshot,
6214 &mut completions.borrow_mut()[completion_index],
6215 );
6216 }
6217 }
6218 } else {
6219 for completion_index in completion_indices {
6220 let server_id = {
6221 let completion = &completions.borrow()[completion_index];
6222 completion.source.server_id()
6223 };
6224 if let Some(server_id) = server_id {
6225 let server_and_adapter = lsp_store
6226 .read_with(cx, |lsp_store, _| {
6227 let server = lsp_store.language_server_for_id(server_id)?;
6228 let adapter =
6229 lsp_store.language_server_adapter_for_id(server.server_id())?;
6230 Some((server, adapter))
6231 })
6232 .ok()
6233 .flatten();
6234 let Some((server, adapter)) = server_and_adapter else {
6235 continue;
6236 };
6237
6238 let resolved = Self::resolve_completion_local(
6239 server,
6240 completions.clone(),
6241 completion_index,
6242 )
6243 .await
6244 .log_err()
6245 .is_some();
6246 if resolved {
6247 Self::regenerate_completion_labels(
6248 adapter,
6249 &buffer_snapshot,
6250 completions.clone(),
6251 completion_index,
6252 )
6253 .await
6254 .log_err();
6255 did_resolve = true;
6256 }
6257 } else {
6258 resolve_word_completion(
6259 &buffer_snapshot,
6260 &mut completions.borrow_mut()[completion_index],
6261 );
6262 }
6263 }
6264 }
6265
6266 Ok(did_resolve)
6267 })
6268 }
6269
6270 async fn resolve_completion_local(
6271 server: Arc<lsp::LanguageServer>,
6272 completions: Rc<RefCell<Box<[Completion]>>>,
6273 completion_index: usize,
6274 ) -> Result<()> {
6275 let server_id = server.server_id();
6276 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6277 return Ok(());
6278 }
6279
6280 let request = {
6281 let completion = &completions.borrow()[completion_index];
6282 match &completion.source {
6283 CompletionSource::Lsp {
6284 lsp_completion,
6285 resolved,
6286 server_id: completion_server_id,
6287 ..
6288 } => {
6289 if *resolved {
6290 return Ok(());
6291 }
6292 anyhow::ensure!(
6293 server_id == *completion_server_id,
6294 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6295 );
6296 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6297 }
6298 CompletionSource::BufferWord { .. }
6299 | CompletionSource::Dap { .. }
6300 | CompletionSource::Custom => {
6301 return Ok(());
6302 }
6303 }
6304 };
6305 let resolved_completion = request
6306 .await
6307 .into_response()
6308 .context("resolve completion")?;
6309
6310 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6311 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6312
6313 let mut completions = completions.borrow_mut();
6314 let completion = &mut completions[completion_index];
6315 if let CompletionSource::Lsp {
6316 lsp_completion,
6317 resolved,
6318 server_id: completion_server_id,
6319 ..
6320 } = &mut completion.source
6321 {
6322 if *resolved {
6323 return Ok(());
6324 }
6325 anyhow::ensure!(
6326 server_id == *completion_server_id,
6327 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6328 );
6329 *lsp_completion = Box::new(resolved_completion);
6330 *resolved = true;
6331 }
6332 Ok(())
6333 }
6334
6335 async fn regenerate_completion_labels(
6336 adapter: Arc<CachedLspAdapter>,
6337 snapshot: &BufferSnapshot,
6338 completions: Rc<RefCell<Box<[Completion]>>>,
6339 completion_index: usize,
6340 ) -> Result<()> {
6341 let completion_item = completions.borrow()[completion_index]
6342 .source
6343 .lsp_completion(true)
6344 .map(Cow::into_owned);
6345 if let Some(lsp_documentation) = completion_item
6346 .as_ref()
6347 .and_then(|completion_item| completion_item.documentation.clone())
6348 {
6349 let mut completions = completions.borrow_mut();
6350 let completion = &mut completions[completion_index];
6351 completion.documentation = Some(lsp_documentation.into());
6352 } else {
6353 let mut completions = completions.borrow_mut();
6354 let completion = &mut completions[completion_index];
6355 completion.documentation = Some(CompletionDocumentation::Undocumented);
6356 }
6357
6358 let mut new_label = match completion_item {
6359 Some(completion_item) => {
6360 // 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
6361 // So we have to update the label here anyway...
6362 let language = snapshot.language();
6363 match language {
6364 Some(language) => {
6365 adapter
6366 .labels_for_completions(
6367 std::slice::from_ref(&completion_item),
6368 language,
6369 )
6370 .await?
6371 }
6372 None => Vec::new(),
6373 }
6374 .pop()
6375 .flatten()
6376 .unwrap_or_else(|| {
6377 CodeLabel::fallback_for_completion(
6378 &completion_item,
6379 language.map(|language| language.as_ref()),
6380 )
6381 })
6382 }
6383 None => CodeLabel::plain(
6384 completions.borrow()[completion_index].new_text.clone(),
6385 None,
6386 ),
6387 };
6388 ensure_uniform_list_compatible_label(&mut new_label);
6389
6390 let mut completions = completions.borrow_mut();
6391 let completion = &mut completions[completion_index];
6392 if completion.label.filter_text() == new_label.filter_text() {
6393 completion.label = new_label;
6394 } else {
6395 log::error!(
6396 "Resolved completion changed display label from {} to {}. \
6397 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6398 completion.label.text(),
6399 new_label.text(),
6400 completion.label.filter_text(),
6401 new_label.filter_text()
6402 );
6403 }
6404
6405 Ok(())
6406 }
6407
6408 async fn resolve_completion_remote(
6409 project_id: u64,
6410 server_id: LanguageServerId,
6411 buffer_id: BufferId,
6412 completions: Rc<RefCell<Box<[Completion]>>>,
6413 completion_index: usize,
6414 client: AnyProtoClient,
6415 ) -> Result<()> {
6416 let lsp_completion = {
6417 let completion = &completions.borrow()[completion_index];
6418 match &completion.source {
6419 CompletionSource::Lsp {
6420 lsp_completion,
6421 resolved,
6422 server_id: completion_server_id,
6423 ..
6424 } => {
6425 anyhow::ensure!(
6426 server_id == *completion_server_id,
6427 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6428 );
6429 if *resolved {
6430 return Ok(());
6431 }
6432 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6433 }
6434 CompletionSource::Custom
6435 | CompletionSource::Dap { .. }
6436 | CompletionSource::BufferWord { .. } => {
6437 return Ok(());
6438 }
6439 }
6440 };
6441 let request = proto::ResolveCompletionDocumentation {
6442 project_id,
6443 language_server_id: server_id.0 as u64,
6444 lsp_completion,
6445 buffer_id: buffer_id.into(),
6446 };
6447
6448 let response = client
6449 .request(request)
6450 .await
6451 .context("completion documentation resolve proto request")?;
6452 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6453
6454 let documentation = if response.documentation.is_empty() {
6455 CompletionDocumentation::Undocumented
6456 } else if response.documentation_is_markdown {
6457 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6458 } else if response.documentation.lines().count() <= 1 {
6459 CompletionDocumentation::SingleLine(response.documentation.into())
6460 } else {
6461 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6462 };
6463
6464 let mut completions = completions.borrow_mut();
6465 let completion = &mut completions[completion_index];
6466 completion.documentation = Some(documentation);
6467 if let CompletionSource::Lsp {
6468 insert_range,
6469 lsp_completion,
6470 resolved,
6471 server_id: completion_server_id,
6472 lsp_defaults: _,
6473 } = &mut completion.source
6474 {
6475 let completion_insert_range = response
6476 .old_insert_start
6477 .and_then(deserialize_anchor)
6478 .zip(response.old_insert_end.and_then(deserialize_anchor));
6479 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6480
6481 if *resolved {
6482 return Ok(());
6483 }
6484 anyhow::ensure!(
6485 server_id == *completion_server_id,
6486 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6487 );
6488 *lsp_completion = Box::new(resolved_lsp_completion);
6489 *resolved = true;
6490 }
6491
6492 let replace_range = response
6493 .old_replace_start
6494 .and_then(deserialize_anchor)
6495 .zip(response.old_replace_end.and_then(deserialize_anchor));
6496 if let Some((old_replace_start, old_replace_end)) = replace_range
6497 && !response.new_text.is_empty()
6498 {
6499 completion.new_text = response.new_text;
6500 completion.replace_range = old_replace_start..old_replace_end;
6501 }
6502
6503 Ok(())
6504 }
6505
6506 pub fn apply_additional_edits_for_completion(
6507 &self,
6508 buffer_handle: Entity<Buffer>,
6509 completions: Rc<RefCell<Box<[Completion]>>>,
6510 completion_index: usize,
6511 push_to_history: bool,
6512 cx: &mut Context<Self>,
6513 ) -> Task<Result<Option<Transaction>>> {
6514 if let Some((client, project_id)) = self.upstream_client() {
6515 let buffer = buffer_handle.read(cx);
6516 let buffer_id = buffer.remote_id();
6517 cx.spawn(async move |_, cx| {
6518 let request = {
6519 let completion = completions.borrow()[completion_index].clone();
6520 proto::ApplyCompletionAdditionalEdits {
6521 project_id,
6522 buffer_id: buffer_id.into(),
6523 completion: Some(Self::serialize_completion(&CoreCompletion {
6524 replace_range: completion.replace_range,
6525 new_text: completion.new_text,
6526 source: completion.source,
6527 })),
6528 }
6529 };
6530
6531 if let Some(transaction) = client.request(request).await?.transaction {
6532 let transaction = language::proto::deserialize_transaction(transaction)?;
6533 buffer_handle
6534 .update(cx, |buffer, _| {
6535 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6536 })?
6537 .await?;
6538 if push_to_history {
6539 buffer_handle.update(cx, |buffer, _| {
6540 buffer.push_transaction(transaction.clone(), Instant::now());
6541 buffer.finalize_last_transaction();
6542 })?;
6543 }
6544 Ok(Some(transaction))
6545 } else {
6546 Ok(None)
6547 }
6548 })
6549 } else {
6550 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6551 let completion = &completions.borrow()[completion_index];
6552 let server_id = completion.source.server_id()?;
6553 Some(
6554 self.language_server_for_local_buffer(buffer, server_id, cx)?
6555 .1
6556 .clone(),
6557 )
6558 }) else {
6559 return Task::ready(Ok(None));
6560 };
6561
6562 cx.spawn(async move |this, cx| {
6563 Self::resolve_completion_local(
6564 server.clone(),
6565 completions.clone(),
6566 completion_index,
6567 )
6568 .await
6569 .context("resolving completion")?;
6570 let completion = completions.borrow()[completion_index].clone();
6571 let additional_text_edits = completion
6572 .source
6573 .lsp_completion(true)
6574 .as_ref()
6575 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6576 if let Some(edits) = additional_text_edits {
6577 let edits = this
6578 .update(cx, |this, cx| {
6579 this.as_local_mut().unwrap().edits_from_lsp(
6580 &buffer_handle,
6581 edits,
6582 server.server_id(),
6583 None,
6584 cx,
6585 )
6586 })?
6587 .await?;
6588
6589 buffer_handle.update(cx, |buffer, cx| {
6590 buffer.finalize_last_transaction();
6591 buffer.start_transaction();
6592
6593 for (range, text) in edits {
6594 let primary = &completion.replace_range;
6595
6596 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6597 // and the primary completion is just an insertion (empty range), then this is likely
6598 // an auto-import scenario and should not be considered overlapping
6599 // https://github.com/zed-industries/zed/issues/26136
6600 let is_file_start_auto_import = {
6601 let snapshot = buffer.snapshot();
6602 let primary_start_point = primary.start.to_point(&snapshot);
6603 let range_start_point = range.start.to_point(&snapshot);
6604
6605 let result = primary_start_point.row == 0
6606 && primary_start_point.column == 0
6607 && range_start_point.row == 0
6608 && range_start_point.column == 0;
6609
6610 result
6611 };
6612
6613 let has_overlap = if is_file_start_auto_import {
6614 false
6615 } else {
6616 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6617 && primary.end.cmp(&range.start, buffer).is_ge();
6618 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6619 && range.end.cmp(&primary.end, buffer).is_ge();
6620 let result = start_within || end_within;
6621 result
6622 };
6623
6624 //Skip additional edits which overlap with the primary completion edit
6625 //https://github.com/zed-industries/zed/pull/1871
6626 if !has_overlap {
6627 buffer.edit([(range, text)], None, cx);
6628 }
6629 }
6630
6631 let transaction = if buffer.end_transaction(cx).is_some() {
6632 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6633 if !push_to_history {
6634 buffer.forget_transaction(transaction.id);
6635 }
6636 Some(transaction)
6637 } else {
6638 None
6639 };
6640 Ok(transaction)
6641 })?
6642 } else {
6643 Ok(None)
6644 }
6645 })
6646 }
6647 }
6648
6649 pub fn pull_diagnostics(
6650 &mut self,
6651 buffer: Entity<Buffer>,
6652 cx: &mut Context<Self>,
6653 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6654 let buffer_id = buffer.read(cx).remote_id();
6655
6656 if let Some((client, upstream_project_id)) = self.upstream_client() {
6657 let mut suitable_capabilities = None;
6658 // Are we capable for proto request?
6659 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6660 &buffer,
6661 |capabilities| {
6662 if let Some(caps) = &capabilities.diagnostic_provider {
6663 suitable_capabilities = Some(caps.clone());
6664 true
6665 } else {
6666 false
6667 }
6668 },
6669 cx,
6670 );
6671 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6672 let Some(dynamic_caps) = suitable_capabilities else {
6673 return Task::ready(Ok(None));
6674 };
6675 assert!(any_server_has_diagnostics_provider);
6676
6677 let request = GetDocumentDiagnostics {
6678 previous_result_id: None,
6679 dynamic_caps,
6680 };
6681 let request_task = client.request_lsp(
6682 upstream_project_id,
6683 None,
6684 LSP_REQUEST_TIMEOUT,
6685 cx.background_executor().clone(),
6686 request.to_proto(upstream_project_id, buffer.read(cx)),
6687 );
6688 cx.background_spawn(async move {
6689 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6690 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6691 // Do not attempt to further process the dummy responses here.
6692 let _response = request_task.await?;
6693 Ok(None)
6694 })
6695 } else {
6696 let servers = buffer.update(cx, |buffer, cx| {
6697 self.language_servers_for_local_buffer(buffer, cx)
6698 .map(|(_, server)| server.clone())
6699 .collect::<Vec<_>>()
6700 });
6701
6702 let pull_diagnostics = servers
6703 .into_iter()
6704 .flat_map(|server| {
6705 let result = maybe!({
6706 let local = self.as_local()?;
6707 let server_id = server.server_id();
6708 let providers_with_identifiers = local
6709 .language_server_dynamic_registrations
6710 .get(&server_id)
6711 .into_iter()
6712 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6713 .collect::<Vec<_>>();
6714 Some(
6715 providers_with_identifiers
6716 .into_iter()
6717 .map(|dynamic_caps| {
6718 let result_id = self.result_id(server_id, buffer_id, cx);
6719 self.request_lsp(
6720 buffer.clone(),
6721 LanguageServerToQuery::Other(server_id),
6722 GetDocumentDiagnostics {
6723 previous_result_id: result_id,
6724 dynamic_caps,
6725 },
6726 cx,
6727 )
6728 })
6729 .collect::<Vec<_>>(),
6730 )
6731 });
6732
6733 result.unwrap_or_default()
6734 })
6735 .collect::<Vec<_>>();
6736
6737 cx.background_spawn(async move {
6738 let mut responses = Vec::new();
6739 for diagnostics in join_all(pull_diagnostics).await {
6740 responses.extend(diagnostics?);
6741 }
6742 Ok(Some(responses))
6743 })
6744 }
6745 }
6746
6747 pub fn applicable_inlay_chunks(
6748 &mut self,
6749 buffer: &Entity<Buffer>,
6750 ranges: &[Range<text::Anchor>],
6751 cx: &mut Context<Self>,
6752 ) -> Vec<Range<BufferRow>> {
6753 self.latest_lsp_data(buffer, cx)
6754 .inlay_hints
6755 .applicable_chunks(ranges)
6756 .map(|chunk| chunk.row_range())
6757 .collect()
6758 }
6759
6760 pub fn invalidate_inlay_hints<'a>(
6761 &'a mut self,
6762 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6763 ) {
6764 for buffer_id in for_buffers {
6765 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6766 lsp_data.inlay_hints.clear();
6767 }
6768 }
6769 }
6770
6771 pub fn inlay_hints(
6772 &mut self,
6773 invalidate: InvalidationStrategy,
6774 buffer: Entity<Buffer>,
6775 ranges: Vec<Range<text::Anchor>>,
6776 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6777 cx: &mut Context<Self>,
6778 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6779 let next_hint_id = self.next_hint_id.clone();
6780 let lsp_data = self.latest_lsp_data(&buffer, cx);
6781 let query_version = lsp_data.buffer_version.clone();
6782 let mut lsp_refresh_requested = false;
6783 let for_server = if let InvalidationStrategy::RefreshRequested {
6784 server_id,
6785 request_id,
6786 } = invalidate
6787 {
6788 let invalidated = lsp_data
6789 .inlay_hints
6790 .invalidate_for_server_refresh(server_id, request_id);
6791 lsp_refresh_requested = invalidated;
6792 Some(server_id)
6793 } else {
6794 None
6795 };
6796 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6797 let known_chunks = known_chunks
6798 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6799 .map(|(_, known_chunks)| known_chunks)
6800 .unwrap_or_default();
6801
6802 let mut hint_fetch_tasks = Vec::new();
6803 let mut cached_inlay_hints = None;
6804 let mut ranges_to_query = None;
6805 let applicable_chunks = existing_inlay_hints
6806 .applicable_chunks(ranges.as_slice())
6807 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6808 .collect::<Vec<_>>();
6809 if applicable_chunks.is_empty() {
6810 return HashMap::default();
6811 }
6812
6813 for row_chunk in applicable_chunks {
6814 match (
6815 existing_inlay_hints
6816 .cached_hints(&row_chunk)
6817 .filter(|_| !lsp_refresh_requested)
6818 .cloned(),
6819 existing_inlay_hints
6820 .fetched_hints(&row_chunk)
6821 .as_ref()
6822 .filter(|_| !lsp_refresh_requested)
6823 .cloned(),
6824 ) {
6825 (None, None) => {
6826 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6827 continue;
6828 };
6829 ranges_to_query
6830 .get_or_insert_with(Vec::new)
6831 .push((row_chunk, chunk_range));
6832 }
6833 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6834 (Some(cached_hints), None) => {
6835 for (server_id, cached_hints) in cached_hints {
6836 if for_server.is_none_or(|for_server| for_server == server_id) {
6837 cached_inlay_hints
6838 .get_or_insert_with(HashMap::default)
6839 .entry(row_chunk.row_range())
6840 .or_insert_with(HashMap::default)
6841 .entry(server_id)
6842 .or_insert_with(Vec::new)
6843 .extend(cached_hints);
6844 }
6845 }
6846 }
6847 (Some(cached_hints), Some(fetched_hints)) => {
6848 hint_fetch_tasks.push((row_chunk, fetched_hints));
6849 for (server_id, cached_hints) in cached_hints {
6850 if for_server.is_none_or(|for_server| for_server == server_id) {
6851 cached_inlay_hints
6852 .get_or_insert_with(HashMap::default)
6853 .entry(row_chunk.row_range())
6854 .or_insert_with(HashMap::default)
6855 .entry(server_id)
6856 .or_insert_with(Vec::new)
6857 .extend(cached_hints);
6858 }
6859 }
6860 }
6861 }
6862 }
6863
6864 if hint_fetch_tasks.is_empty()
6865 && ranges_to_query
6866 .as_ref()
6867 .is_none_or(|ranges| ranges.is_empty())
6868 && let Some(cached_inlay_hints) = cached_inlay_hints
6869 {
6870 cached_inlay_hints
6871 .into_iter()
6872 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6873 .collect()
6874 } else {
6875 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6876 let next_hint_id = next_hint_id.clone();
6877 let buffer = buffer.clone();
6878 let query_version = query_version.clone();
6879 let new_inlay_hints = cx
6880 .spawn(async move |lsp_store, cx| {
6881 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6882 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6883 })?;
6884 new_fetch_task
6885 .await
6886 .and_then(|new_hints_by_server| {
6887 lsp_store.update(cx, |lsp_store, cx| {
6888 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6889 let update_cache = lsp_data.buffer_version == query_version;
6890 if new_hints_by_server.is_empty() {
6891 if update_cache {
6892 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6893 }
6894 HashMap::default()
6895 } else {
6896 new_hints_by_server
6897 .into_iter()
6898 .map(|(server_id, new_hints)| {
6899 let new_hints = new_hints
6900 .into_iter()
6901 .map(|new_hint| {
6902 (
6903 InlayId::Hint(next_hint_id.fetch_add(
6904 1,
6905 atomic::Ordering::AcqRel,
6906 )),
6907 new_hint,
6908 )
6909 })
6910 .collect::<Vec<_>>();
6911 if update_cache {
6912 lsp_data.inlay_hints.insert_new_hints(
6913 chunk,
6914 server_id,
6915 new_hints.clone(),
6916 );
6917 }
6918 (server_id, new_hints)
6919 })
6920 .collect()
6921 }
6922 })
6923 })
6924 .map_err(Arc::new)
6925 })
6926 .shared();
6927
6928 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6929 *fetch_task = Some(new_inlay_hints.clone());
6930 hint_fetch_tasks.push((chunk, new_inlay_hints));
6931 }
6932
6933 cached_inlay_hints
6934 .unwrap_or_default()
6935 .into_iter()
6936 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6937 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6938 (
6939 chunk.row_range(),
6940 cx.spawn(async move |_, _| {
6941 hints_fetch.await.map_err(|e| {
6942 if e.error_code() != ErrorCode::Internal {
6943 anyhow!(e.error_code())
6944 } else {
6945 anyhow!("{e:#}")
6946 }
6947 })
6948 }),
6949 )
6950 }))
6951 .collect()
6952 }
6953 }
6954
6955 fn fetch_inlay_hints(
6956 &mut self,
6957 for_server: Option<LanguageServerId>,
6958 buffer: &Entity<Buffer>,
6959 range: Range<Anchor>,
6960 cx: &mut Context<Self>,
6961 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6962 let request = InlayHints {
6963 range: range.clone(),
6964 };
6965 if let Some((upstream_client, project_id)) = self.upstream_client() {
6966 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6967 return Task::ready(Ok(HashMap::default()));
6968 }
6969 let request_task = upstream_client.request_lsp(
6970 project_id,
6971 for_server.map(|id| id.to_proto()),
6972 LSP_REQUEST_TIMEOUT,
6973 cx.background_executor().clone(),
6974 request.to_proto(project_id, buffer.read(cx)),
6975 );
6976 let buffer = buffer.clone();
6977 cx.spawn(async move |weak_lsp_store, cx| {
6978 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6979 return Ok(HashMap::default());
6980 };
6981 let Some(responses) = request_task.await? else {
6982 return Ok(HashMap::default());
6983 };
6984
6985 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6986 let lsp_store = lsp_store.clone();
6987 let buffer = buffer.clone();
6988 let cx = cx.clone();
6989 let request = request.clone();
6990 async move {
6991 (
6992 LanguageServerId::from_proto(response.server_id),
6993 request
6994 .response_from_proto(response.response, lsp_store, buffer, cx)
6995 .await,
6996 )
6997 }
6998 }))
6999 .await;
7000
7001 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7002 let mut has_errors = false;
7003 let inlay_hints = inlay_hints
7004 .into_iter()
7005 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7006 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7007 Err(e) => {
7008 has_errors = true;
7009 log::error!("{e:#}");
7010 None
7011 }
7012 })
7013 .map(|(server_id, mut new_hints)| {
7014 new_hints.retain(|hint| {
7015 hint.position.is_valid(&buffer_snapshot)
7016 && range.start.is_valid(&buffer_snapshot)
7017 && range.end.is_valid(&buffer_snapshot)
7018 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7019 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7020 });
7021 (server_id, new_hints)
7022 })
7023 .collect::<HashMap<_, _>>();
7024 anyhow::ensure!(
7025 !has_errors || !inlay_hints.is_empty(),
7026 "Failed to fetch inlay hints"
7027 );
7028 Ok(inlay_hints)
7029 })
7030 } else {
7031 let inlay_hints_task = match for_server {
7032 Some(server_id) => {
7033 let server_task = self.request_lsp(
7034 buffer.clone(),
7035 LanguageServerToQuery::Other(server_id),
7036 request,
7037 cx,
7038 );
7039 cx.background_spawn(async move {
7040 let mut responses = Vec::new();
7041 match server_task.await {
7042 Ok(response) => responses.push((server_id, response)),
7043 // rust-analyzer likes to error with this when its still loading up
7044 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7045 Err(e) => log::error!(
7046 "Error handling response for inlay hints request: {e:#}"
7047 ),
7048 }
7049 responses
7050 })
7051 }
7052 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7053 };
7054 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7055 cx.background_spawn(async move {
7056 Ok(inlay_hints_task
7057 .await
7058 .into_iter()
7059 .map(|(server_id, mut new_hints)| {
7060 new_hints.retain(|hint| {
7061 hint.position.is_valid(&buffer_snapshot)
7062 && range.start.is_valid(&buffer_snapshot)
7063 && range.end.is_valid(&buffer_snapshot)
7064 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7065 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7066 });
7067 (server_id, new_hints)
7068 })
7069 .collect())
7070 })
7071 }
7072 }
7073
7074 pub fn pull_diagnostics_for_buffer(
7075 &mut self,
7076 buffer: Entity<Buffer>,
7077 cx: &mut Context<Self>,
7078 ) -> Task<anyhow::Result<()>> {
7079 let diagnostics = self.pull_diagnostics(buffer, cx);
7080 cx.spawn(async move |lsp_store, cx| {
7081 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7082 return Ok(());
7083 };
7084 lsp_store.update(cx, |lsp_store, cx| {
7085 if lsp_store.as_local().is_none() {
7086 return;
7087 }
7088
7089 let mut unchanged_buffers = HashSet::default();
7090 let mut changed_buffers = HashSet::default();
7091 let server_diagnostics_updates = diagnostics
7092 .into_iter()
7093 .filter_map(|diagnostics_set| match diagnostics_set {
7094 LspPullDiagnostics::Response {
7095 server_id,
7096 uri,
7097 diagnostics,
7098 } => Some((server_id, uri, diagnostics)),
7099 LspPullDiagnostics::Default => None,
7100 })
7101 .fold(
7102 HashMap::default(),
7103 |mut acc, (server_id, uri, diagnostics)| {
7104 let (result_id, diagnostics) = match diagnostics {
7105 PulledDiagnostics::Unchanged { result_id } => {
7106 unchanged_buffers.insert(uri.clone());
7107 (Some(result_id), Vec::new())
7108 }
7109 PulledDiagnostics::Changed {
7110 result_id,
7111 diagnostics,
7112 } => {
7113 changed_buffers.insert(uri.clone());
7114 (result_id, diagnostics)
7115 }
7116 };
7117 let disk_based_sources = Cow::Owned(
7118 lsp_store
7119 .language_server_adapter_for_id(server_id)
7120 .as_ref()
7121 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7122 .unwrap_or(&[])
7123 .to_vec(),
7124 );
7125 acc.entry(server_id).or_insert_with(Vec::new).push(
7126 DocumentDiagnosticsUpdate {
7127 server_id,
7128 diagnostics: lsp::PublishDiagnosticsParams {
7129 uri,
7130 diagnostics,
7131 version: None,
7132 },
7133 result_id,
7134 disk_based_sources,
7135 },
7136 );
7137 acc
7138 },
7139 );
7140
7141 for diagnostic_updates in server_diagnostics_updates.into_values() {
7142 lsp_store
7143 .merge_lsp_diagnostics(
7144 DiagnosticSourceKind::Pulled,
7145 diagnostic_updates,
7146 |buffer, old_diagnostic, cx| {
7147 File::from_dyn(buffer.file())
7148 .and_then(|file| {
7149 let abs_path = file.as_local()?.abs_path(cx);
7150 lsp::Uri::from_file_path(abs_path).ok()
7151 })
7152 .is_none_or(|buffer_uri| {
7153 unchanged_buffers.contains(&buffer_uri)
7154 || match old_diagnostic.source_kind {
7155 DiagnosticSourceKind::Pulled => {
7156 !changed_buffers.contains(&buffer_uri)
7157 }
7158 DiagnosticSourceKind::Other
7159 | DiagnosticSourceKind::Pushed => true,
7160 }
7161 })
7162 },
7163 cx,
7164 )
7165 .log_err();
7166 }
7167 })
7168 })
7169 }
7170
7171 pub fn document_colors(
7172 &mut self,
7173 known_cache_version: Option<usize>,
7174 buffer: Entity<Buffer>,
7175 cx: &mut Context<Self>,
7176 ) -> Option<DocumentColorTask> {
7177 let version_queried_for = buffer.read(cx).version();
7178 let buffer_id = buffer.read(cx).remote_id();
7179
7180 let current_language_servers = self.as_local().map(|local| {
7181 local
7182 .buffers_opened_in_servers
7183 .get(&buffer_id)
7184 .cloned()
7185 .unwrap_or_default()
7186 });
7187
7188 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7189 if let Some(cached_colors) = &lsp_data.document_colors {
7190 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7191 let has_different_servers =
7192 current_language_servers.is_some_and(|current_language_servers| {
7193 current_language_servers
7194 != cached_colors.colors.keys().copied().collect()
7195 });
7196 if !has_different_servers {
7197 let cache_version = cached_colors.cache_version;
7198 if Some(cache_version) == known_cache_version {
7199 return None;
7200 } else {
7201 return Some(
7202 Task::ready(Ok(DocumentColors {
7203 colors: cached_colors
7204 .colors
7205 .values()
7206 .flatten()
7207 .cloned()
7208 .collect(),
7209 cache_version: Some(cache_version),
7210 }))
7211 .shared(),
7212 );
7213 }
7214 }
7215 }
7216 }
7217 }
7218
7219 let color_lsp_data = self
7220 .latest_lsp_data(&buffer, cx)
7221 .document_colors
7222 .get_or_insert_default();
7223 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7224 && !version_queried_for.changed_since(updating_for)
7225 {
7226 return Some(running_update.clone());
7227 }
7228 let buffer_version_queried_for = version_queried_for.clone();
7229 let new_task = cx
7230 .spawn(async move |lsp_store, cx| {
7231 cx.background_executor()
7232 .timer(Duration::from_millis(30))
7233 .await;
7234 let fetched_colors = lsp_store
7235 .update(cx, |lsp_store, cx| {
7236 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7237 })?
7238 .await
7239 .context("fetching document colors")
7240 .map_err(Arc::new);
7241 let fetched_colors = match fetched_colors {
7242 Ok(fetched_colors) => {
7243 if Some(true)
7244 == buffer
7245 .update(cx, |buffer, _| {
7246 buffer.version() != buffer_version_queried_for
7247 })
7248 .ok()
7249 {
7250 return Ok(DocumentColors::default());
7251 }
7252 fetched_colors
7253 }
7254 Err(e) => {
7255 lsp_store
7256 .update(cx, |lsp_store, _| {
7257 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7258 if let Some(document_colors) = &mut lsp_data.document_colors {
7259 document_colors.colors_update = None;
7260 }
7261 }
7262 })
7263 .ok();
7264 return Err(e);
7265 }
7266 };
7267
7268 lsp_store
7269 .update(cx, |lsp_store, cx| {
7270 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7271 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7272
7273 if let Some(fetched_colors) = fetched_colors {
7274 if lsp_data.buffer_version == buffer_version_queried_for {
7275 lsp_colors.colors.extend(fetched_colors);
7276 lsp_colors.cache_version += 1;
7277 } else if !lsp_data
7278 .buffer_version
7279 .changed_since(&buffer_version_queried_for)
7280 {
7281 lsp_data.buffer_version = buffer_version_queried_for;
7282 lsp_colors.colors = fetched_colors;
7283 lsp_colors.cache_version += 1;
7284 }
7285 }
7286 lsp_colors.colors_update = None;
7287 let colors = lsp_colors
7288 .colors
7289 .values()
7290 .flatten()
7291 .cloned()
7292 .collect::<HashSet<_>>();
7293 DocumentColors {
7294 colors,
7295 cache_version: Some(lsp_colors.cache_version),
7296 }
7297 })
7298 .map_err(Arc::new)
7299 })
7300 .shared();
7301 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7302 Some(new_task)
7303 }
7304
7305 fn fetch_document_colors_for_buffer(
7306 &mut self,
7307 buffer: &Entity<Buffer>,
7308 cx: &mut Context<Self>,
7309 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7310 if let Some((client, project_id)) = self.upstream_client() {
7311 let request = GetDocumentColor {};
7312 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7313 return Task::ready(Ok(None));
7314 }
7315
7316 let request_task = client.request_lsp(
7317 project_id,
7318 None,
7319 LSP_REQUEST_TIMEOUT,
7320 cx.background_executor().clone(),
7321 request.to_proto(project_id, buffer.read(cx)),
7322 );
7323 let buffer = buffer.clone();
7324 cx.spawn(async move |lsp_store, cx| {
7325 let Some(lsp_store) = lsp_store.upgrade() else {
7326 return Ok(None);
7327 };
7328 let colors = join_all(
7329 request_task
7330 .await
7331 .log_err()
7332 .flatten()
7333 .map(|response| response.payload)
7334 .unwrap_or_default()
7335 .into_iter()
7336 .map(|color_response| {
7337 let response = request.response_from_proto(
7338 color_response.response,
7339 lsp_store.clone(),
7340 buffer.clone(),
7341 cx.clone(),
7342 );
7343 async move {
7344 (
7345 LanguageServerId::from_proto(color_response.server_id),
7346 response.await.log_err().unwrap_or_default(),
7347 )
7348 }
7349 }),
7350 )
7351 .await
7352 .into_iter()
7353 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7354 acc.entry(server_id)
7355 .or_insert_with(HashSet::default)
7356 .extend(colors);
7357 acc
7358 });
7359 Ok(Some(colors))
7360 })
7361 } else {
7362 let document_colors_task =
7363 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7364 cx.background_spawn(async move {
7365 Ok(Some(
7366 document_colors_task
7367 .await
7368 .into_iter()
7369 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7370 acc.entry(server_id)
7371 .or_insert_with(HashSet::default)
7372 .extend(colors);
7373 acc
7374 })
7375 .into_iter()
7376 .collect(),
7377 ))
7378 })
7379 }
7380 }
7381
7382 pub fn signature_help<T: ToPointUtf16>(
7383 &mut self,
7384 buffer: &Entity<Buffer>,
7385 position: T,
7386 cx: &mut Context<Self>,
7387 ) -> Task<Option<Vec<SignatureHelp>>> {
7388 let position = position.to_point_utf16(buffer.read(cx));
7389
7390 if let Some((client, upstream_project_id)) = self.upstream_client() {
7391 let request = GetSignatureHelp { position };
7392 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7393 return Task::ready(None);
7394 }
7395 let request_task = client.request_lsp(
7396 upstream_project_id,
7397 None,
7398 LSP_REQUEST_TIMEOUT,
7399 cx.background_executor().clone(),
7400 request.to_proto(upstream_project_id, buffer.read(cx)),
7401 );
7402 let buffer = buffer.clone();
7403 cx.spawn(async move |weak_lsp_store, cx| {
7404 let lsp_store = weak_lsp_store.upgrade()?;
7405 let signatures = join_all(
7406 request_task
7407 .await
7408 .log_err()
7409 .flatten()
7410 .map(|response| response.payload)
7411 .unwrap_or_default()
7412 .into_iter()
7413 .map(|response| {
7414 let response = GetSignatureHelp { position }.response_from_proto(
7415 response.response,
7416 lsp_store.clone(),
7417 buffer.clone(),
7418 cx.clone(),
7419 );
7420 async move { response.await.log_err().flatten() }
7421 }),
7422 )
7423 .await
7424 .into_iter()
7425 .flatten()
7426 .collect();
7427 Some(signatures)
7428 })
7429 } else {
7430 let all_actions_task = self.request_multiple_lsp_locally(
7431 buffer,
7432 Some(position),
7433 GetSignatureHelp { position },
7434 cx,
7435 );
7436 cx.background_spawn(async move {
7437 Some(
7438 all_actions_task
7439 .await
7440 .into_iter()
7441 .flat_map(|(_, actions)| actions)
7442 .collect::<Vec<_>>(),
7443 )
7444 })
7445 }
7446 }
7447
7448 pub fn hover(
7449 &mut self,
7450 buffer: &Entity<Buffer>,
7451 position: PointUtf16,
7452 cx: &mut Context<Self>,
7453 ) -> Task<Option<Vec<Hover>>> {
7454 if let Some((client, upstream_project_id)) = self.upstream_client() {
7455 let request = GetHover { position };
7456 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7457 return Task::ready(None);
7458 }
7459 let request_task = client.request_lsp(
7460 upstream_project_id,
7461 None,
7462 LSP_REQUEST_TIMEOUT,
7463 cx.background_executor().clone(),
7464 request.to_proto(upstream_project_id, buffer.read(cx)),
7465 );
7466 let buffer = buffer.clone();
7467 cx.spawn(async move |weak_lsp_store, cx| {
7468 let lsp_store = weak_lsp_store.upgrade()?;
7469 let hovers = join_all(
7470 request_task
7471 .await
7472 .log_err()
7473 .flatten()
7474 .map(|response| response.payload)
7475 .unwrap_or_default()
7476 .into_iter()
7477 .map(|response| {
7478 let response = GetHover { position }.response_from_proto(
7479 response.response,
7480 lsp_store.clone(),
7481 buffer.clone(),
7482 cx.clone(),
7483 );
7484 async move {
7485 response
7486 .await
7487 .log_err()
7488 .flatten()
7489 .and_then(remove_empty_hover_blocks)
7490 }
7491 }),
7492 )
7493 .await
7494 .into_iter()
7495 .flatten()
7496 .collect();
7497 Some(hovers)
7498 })
7499 } else {
7500 let all_actions_task = self.request_multiple_lsp_locally(
7501 buffer,
7502 Some(position),
7503 GetHover { position },
7504 cx,
7505 );
7506 cx.background_spawn(async move {
7507 Some(
7508 all_actions_task
7509 .await
7510 .into_iter()
7511 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7512 .collect::<Vec<Hover>>(),
7513 )
7514 })
7515 }
7516 }
7517
7518 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7519 let language_registry = self.languages.clone();
7520
7521 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7522 let request = upstream_client.request(proto::GetProjectSymbols {
7523 project_id: *project_id,
7524 query: query.to_string(),
7525 });
7526 cx.foreground_executor().spawn(async move {
7527 let response = request.await?;
7528 let mut symbols = Vec::new();
7529 let core_symbols = response
7530 .symbols
7531 .into_iter()
7532 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7533 .collect::<Vec<_>>();
7534 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7535 .await;
7536 Ok(symbols)
7537 })
7538 } else if let Some(local) = self.as_local() {
7539 struct WorkspaceSymbolsResult {
7540 server_id: LanguageServerId,
7541 lsp_adapter: Arc<CachedLspAdapter>,
7542 worktree: WeakEntity<Worktree>,
7543 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7544 }
7545
7546 let mut requests = Vec::new();
7547 let mut requested_servers = BTreeSet::new();
7548 for (seed, state) in local.language_server_ids.iter() {
7549 let Some(worktree_handle) = self
7550 .worktree_store
7551 .read(cx)
7552 .worktree_for_id(seed.worktree_id, cx)
7553 else {
7554 continue;
7555 };
7556 let worktree = worktree_handle.read(cx);
7557 if !worktree.is_visible() {
7558 continue;
7559 }
7560
7561 if !requested_servers.insert(state.id) {
7562 continue;
7563 }
7564
7565 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7566 Some(LanguageServerState::Running {
7567 adapter, server, ..
7568 }) => (adapter.clone(), server),
7569
7570 _ => continue,
7571 };
7572 let supports_workspace_symbol_request =
7573 match server.capabilities().workspace_symbol_provider {
7574 Some(OneOf::Left(supported)) => supported,
7575 Some(OneOf::Right(_)) => true,
7576 None => false,
7577 };
7578 if !supports_workspace_symbol_request {
7579 continue;
7580 }
7581 let worktree_handle = worktree_handle.clone();
7582 let server_id = server.server_id();
7583 requests.push(
7584 server
7585 .request::<lsp::request::WorkspaceSymbolRequest>(
7586 lsp::WorkspaceSymbolParams {
7587 query: query.to_string(),
7588 ..Default::default()
7589 },
7590 )
7591 .map(move |response| {
7592 let lsp_symbols = response.into_response()
7593 .context("workspace symbols request")
7594 .log_err()
7595 .flatten()
7596 .map(|symbol_response| match symbol_response {
7597 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7598 flat_responses.into_iter().map(|lsp_symbol| {
7599 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7600 }).collect::<Vec<_>>()
7601 }
7602 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7603 nested_responses.into_iter().filter_map(|lsp_symbol| {
7604 let location = match lsp_symbol.location {
7605 OneOf::Left(location) => location,
7606 OneOf::Right(_) => {
7607 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7608 return None
7609 }
7610 };
7611 Some((lsp_symbol.name, lsp_symbol.kind, location))
7612 }).collect::<Vec<_>>()
7613 }
7614 }).unwrap_or_default();
7615
7616 WorkspaceSymbolsResult {
7617 server_id,
7618 lsp_adapter,
7619 worktree: worktree_handle.downgrade(),
7620 lsp_symbols,
7621 }
7622 }),
7623 );
7624 }
7625
7626 cx.spawn(async move |this, cx| {
7627 let responses = futures::future::join_all(requests).await;
7628 let this = match this.upgrade() {
7629 Some(this) => this,
7630 None => return Ok(Vec::new()),
7631 };
7632
7633 let mut symbols = Vec::new();
7634 for result in responses {
7635 let core_symbols = this.update(cx, |this, cx| {
7636 result
7637 .lsp_symbols
7638 .into_iter()
7639 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7640 let abs_path = symbol_location.uri.to_file_path().ok()?;
7641 let source_worktree = result.worktree.upgrade()?;
7642 let source_worktree_id = source_worktree.read(cx).id();
7643
7644 let path = if let Some((tree, rel_path)) =
7645 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7646 {
7647 let worktree_id = tree.read(cx).id();
7648 SymbolLocation::InProject(ProjectPath {
7649 worktree_id,
7650 path: rel_path,
7651 })
7652 } else {
7653 SymbolLocation::OutsideProject {
7654 signature: this.symbol_signature(&abs_path),
7655 abs_path: abs_path.into(),
7656 }
7657 };
7658
7659 Some(CoreSymbol {
7660 source_language_server_id: result.server_id,
7661 language_server_name: result.lsp_adapter.name.clone(),
7662 source_worktree_id,
7663 path,
7664 kind: symbol_kind,
7665 name: symbol_name,
7666 range: range_from_lsp(symbol_location.range),
7667 })
7668 })
7669 .collect()
7670 })?;
7671
7672 populate_labels_for_symbols(
7673 core_symbols,
7674 &language_registry,
7675 Some(result.lsp_adapter),
7676 &mut symbols,
7677 )
7678 .await;
7679 }
7680
7681 Ok(symbols)
7682 })
7683 } else {
7684 Task::ready(Err(anyhow!("No upstream client or local language server")))
7685 }
7686 }
7687
7688 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7689 let mut summary = DiagnosticSummary::default();
7690 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7691 summary.error_count += path_summary.error_count;
7692 summary.warning_count += path_summary.warning_count;
7693 }
7694 summary
7695 }
7696
7697 /// Returns the diagnostic summary for a specific project path.
7698 pub fn diagnostic_summary_for_path(
7699 &self,
7700 project_path: &ProjectPath,
7701 _: &App,
7702 ) -> DiagnosticSummary {
7703 if let Some(summaries) = self
7704 .diagnostic_summaries
7705 .get(&project_path.worktree_id)
7706 .and_then(|map| map.get(&project_path.path))
7707 {
7708 let (error_count, warning_count) = summaries.iter().fold(
7709 (0, 0),
7710 |(error_count, warning_count), (_language_server_id, summary)| {
7711 (
7712 error_count + summary.error_count,
7713 warning_count + summary.warning_count,
7714 )
7715 },
7716 );
7717
7718 DiagnosticSummary {
7719 error_count,
7720 warning_count,
7721 }
7722 } else {
7723 DiagnosticSummary::default()
7724 }
7725 }
7726
7727 pub fn diagnostic_summaries<'a>(
7728 &'a self,
7729 include_ignored: bool,
7730 cx: &'a App,
7731 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7732 self.worktree_store
7733 .read(cx)
7734 .visible_worktrees(cx)
7735 .filter_map(|worktree| {
7736 let worktree = worktree.read(cx);
7737 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7738 })
7739 .flat_map(move |(worktree, summaries)| {
7740 let worktree_id = worktree.id();
7741 summaries
7742 .iter()
7743 .filter(move |(path, _)| {
7744 include_ignored
7745 || worktree
7746 .entry_for_path(path.as_ref())
7747 .is_some_and(|entry| !entry.is_ignored)
7748 })
7749 .flat_map(move |(path, summaries)| {
7750 summaries.iter().map(move |(server_id, summary)| {
7751 (
7752 ProjectPath {
7753 worktree_id,
7754 path: path.clone(),
7755 },
7756 *server_id,
7757 *summary,
7758 )
7759 })
7760 })
7761 })
7762 }
7763
7764 pub fn on_buffer_edited(
7765 &mut self,
7766 buffer: Entity<Buffer>,
7767 cx: &mut Context<Self>,
7768 ) -> Option<()> {
7769 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7770 Some(
7771 self.as_local()?
7772 .language_servers_for_buffer(buffer, cx)
7773 .map(|i| i.1.clone())
7774 .collect(),
7775 )
7776 })?;
7777
7778 let buffer = buffer.read(cx);
7779 let file = File::from_dyn(buffer.file())?;
7780 let abs_path = file.as_local()?.abs_path(cx);
7781 let uri = lsp::Uri::from_file_path(&abs_path)
7782 .ok()
7783 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7784 .log_err()?;
7785 let next_snapshot = buffer.text_snapshot();
7786 for language_server in language_servers {
7787 let language_server = language_server.clone();
7788
7789 let buffer_snapshots = self
7790 .as_local_mut()?
7791 .buffer_snapshots
7792 .get_mut(&buffer.remote_id())
7793 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7794 let previous_snapshot = buffer_snapshots.last()?;
7795
7796 let build_incremental_change = || {
7797 buffer
7798 .edits_since::<Dimensions<PointUtf16, usize>>(
7799 previous_snapshot.snapshot.version(),
7800 )
7801 .map(|edit| {
7802 let edit_start = edit.new.start.0;
7803 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7804 let new_text = next_snapshot
7805 .text_for_range(edit.new.start.1..edit.new.end.1)
7806 .collect();
7807 lsp::TextDocumentContentChangeEvent {
7808 range: Some(lsp::Range::new(
7809 point_to_lsp(edit_start),
7810 point_to_lsp(edit_end),
7811 )),
7812 range_length: None,
7813 text: new_text,
7814 }
7815 })
7816 .collect()
7817 };
7818
7819 let document_sync_kind = language_server
7820 .capabilities()
7821 .text_document_sync
7822 .as_ref()
7823 .and_then(|sync| match sync {
7824 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7825 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7826 });
7827
7828 let content_changes: Vec<_> = match document_sync_kind {
7829 Some(lsp::TextDocumentSyncKind::FULL) => {
7830 vec![lsp::TextDocumentContentChangeEvent {
7831 range: None,
7832 range_length: None,
7833 text: next_snapshot.text(),
7834 }]
7835 }
7836 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7837 _ => {
7838 #[cfg(any(test, feature = "test-support"))]
7839 {
7840 build_incremental_change()
7841 }
7842
7843 #[cfg(not(any(test, feature = "test-support")))]
7844 {
7845 continue;
7846 }
7847 }
7848 };
7849
7850 let next_version = previous_snapshot.version + 1;
7851 buffer_snapshots.push(LspBufferSnapshot {
7852 version: next_version,
7853 snapshot: next_snapshot.clone(),
7854 });
7855
7856 language_server
7857 .notify::<lsp::notification::DidChangeTextDocument>(
7858 lsp::DidChangeTextDocumentParams {
7859 text_document: lsp::VersionedTextDocumentIdentifier::new(
7860 uri.clone(),
7861 next_version,
7862 ),
7863 content_changes,
7864 },
7865 )
7866 .ok();
7867 self.pull_workspace_diagnostics(language_server.server_id());
7868 }
7869
7870 None
7871 }
7872
7873 pub fn on_buffer_saved(
7874 &mut self,
7875 buffer: Entity<Buffer>,
7876 cx: &mut Context<Self>,
7877 ) -> Option<()> {
7878 let file = File::from_dyn(buffer.read(cx).file())?;
7879 let worktree_id = file.worktree_id(cx);
7880 let abs_path = file.as_local()?.abs_path(cx);
7881 let text_document = lsp::TextDocumentIdentifier {
7882 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7883 };
7884 let local = self.as_local()?;
7885
7886 for server in local.language_servers_for_worktree(worktree_id) {
7887 if let Some(include_text) = include_text(server.as_ref()) {
7888 let text = if include_text {
7889 Some(buffer.read(cx).text())
7890 } else {
7891 None
7892 };
7893 server
7894 .notify::<lsp::notification::DidSaveTextDocument>(
7895 lsp::DidSaveTextDocumentParams {
7896 text_document: text_document.clone(),
7897 text,
7898 },
7899 )
7900 .ok();
7901 }
7902 }
7903
7904 let language_servers = buffer.update(cx, |buffer, cx| {
7905 local.language_server_ids_for_buffer(buffer, cx)
7906 });
7907 for language_server_id in language_servers {
7908 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7909 }
7910
7911 None
7912 }
7913
7914 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7915 maybe!(async move {
7916 let mut refreshed_servers = HashSet::default();
7917 let servers = lsp_store
7918 .update(cx, |lsp_store, cx| {
7919 let local = lsp_store.as_local()?;
7920
7921 let servers = local
7922 .language_server_ids
7923 .iter()
7924 .filter_map(|(seed, state)| {
7925 let worktree = lsp_store
7926 .worktree_store
7927 .read(cx)
7928 .worktree_for_id(seed.worktree_id, cx);
7929 let delegate: Arc<dyn LspAdapterDelegate> =
7930 worktree.map(|worktree| {
7931 LocalLspAdapterDelegate::new(
7932 local.languages.clone(),
7933 &local.environment,
7934 cx.weak_entity(),
7935 &worktree,
7936 local.http_client.clone(),
7937 local.fs.clone(),
7938 cx,
7939 )
7940 })?;
7941 let server_id = state.id;
7942
7943 let states = local.language_servers.get(&server_id)?;
7944
7945 match states {
7946 LanguageServerState::Starting { .. } => None,
7947 LanguageServerState::Running {
7948 adapter, server, ..
7949 } => {
7950 let adapter = adapter.clone();
7951 let server = server.clone();
7952 refreshed_servers.insert(server.name());
7953 let toolchain = seed.toolchain.clone();
7954 Some(cx.spawn(async move |_, cx| {
7955 let settings =
7956 LocalLspStore::workspace_configuration_for_adapter(
7957 adapter.adapter.clone(),
7958 &delegate,
7959 toolchain,
7960 cx,
7961 )
7962 .await
7963 .ok()?;
7964 server
7965 .notify::<lsp::notification::DidChangeConfiguration>(
7966 lsp::DidChangeConfigurationParams { settings },
7967 )
7968 .ok()?;
7969 Some(())
7970 }))
7971 }
7972 }
7973 })
7974 .collect::<Vec<_>>();
7975
7976 Some(servers)
7977 })
7978 .ok()
7979 .flatten()?;
7980
7981 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7982 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7983 // to stop and unregister its language server wrapper.
7984 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7985 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7986 let _: Vec<Option<()>> = join_all(servers).await;
7987
7988 Some(())
7989 })
7990 .await;
7991 }
7992
7993 fn maintain_workspace_config(
7994 external_refresh_requests: watch::Receiver<()>,
7995 cx: &mut Context<Self>,
7996 ) -> Task<Result<()>> {
7997 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7998 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7999
8000 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8001 *settings_changed_tx.borrow_mut() = ();
8002 });
8003
8004 let mut joint_future =
8005 futures::stream::select(settings_changed_rx, external_refresh_requests);
8006 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8007 // - 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).
8008 // - 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.
8009 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8010 // - 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,
8011 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8012 cx.spawn(async move |this, cx| {
8013 while let Some(()) = joint_future.next().await {
8014 this.update(cx, |this, cx| {
8015 this.refresh_server_tree(cx);
8016 })
8017 .ok();
8018
8019 Self::refresh_workspace_configurations(&this, cx).await;
8020 }
8021
8022 drop(settings_observation);
8023 anyhow::Ok(())
8024 })
8025 }
8026
8027 pub fn language_servers_for_local_buffer<'a>(
8028 &'a self,
8029 buffer: &Buffer,
8030 cx: &mut App,
8031 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8032 let local = self.as_local();
8033 let language_server_ids = local
8034 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8035 .unwrap_or_default();
8036
8037 language_server_ids
8038 .into_iter()
8039 .filter_map(
8040 move |server_id| match local?.language_servers.get(&server_id)? {
8041 LanguageServerState::Running {
8042 adapter, server, ..
8043 } => Some((adapter, server)),
8044 _ => None,
8045 },
8046 )
8047 }
8048
8049 pub fn language_server_for_local_buffer<'a>(
8050 &'a self,
8051 buffer: &'a Buffer,
8052 server_id: LanguageServerId,
8053 cx: &'a mut App,
8054 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8055 self.as_local()?
8056 .language_servers_for_buffer(buffer, cx)
8057 .find(|(_, s)| s.server_id() == server_id)
8058 }
8059
8060 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8061 self.diagnostic_summaries.remove(&id_to_remove);
8062 if let Some(local) = self.as_local_mut() {
8063 let to_remove = local.remove_worktree(id_to_remove, cx);
8064 for server in to_remove {
8065 self.language_server_statuses.remove(&server);
8066 }
8067 }
8068 }
8069
8070 pub fn shared(
8071 &mut self,
8072 project_id: u64,
8073 downstream_client: AnyProtoClient,
8074 _: &mut Context<Self>,
8075 ) {
8076 self.downstream_client = Some((downstream_client.clone(), project_id));
8077
8078 for (server_id, status) in &self.language_server_statuses {
8079 if let Some(server) = self.language_server_for_id(*server_id) {
8080 downstream_client
8081 .send(proto::StartLanguageServer {
8082 project_id,
8083 server: Some(proto::LanguageServer {
8084 id: server_id.to_proto(),
8085 name: status.name.to_string(),
8086 worktree_id: status.worktree.map(|id| id.to_proto()),
8087 }),
8088 capabilities: serde_json::to_string(&server.capabilities())
8089 .expect("serializing server LSP capabilities"),
8090 })
8091 .log_err();
8092 }
8093 }
8094 }
8095
8096 pub fn disconnected_from_host(&mut self) {
8097 self.downstream_client.take();
8098 }
8099
8100 pub fn disconnected_from_ssh_remote(&mut self) {
8101 if let LspStoreMode::Remote(RemoteLspStore {
8102 upstream_client, ..
8103 }) = &mut self.mode
8104 {
8105 upstream_client.take();
8106 }
8107 }
8108
8109 pub(crate) fn set_language_server_statuses_from_proto(
8110 &mut self,
8111 project: WeakEntity<Project>,
8112 language_servers: Vec<proto::LanguageServer>,
8113 server_capabilities: Vec<String>,
8114 cx: &mut Context<Self>,
8115 ) {
8116 let lsp_logs = cx
8117 .try_global::<GlobalLogStore>()
8118 .map(|lsp_store| lsp_store.0.clone());
8119
8120 self.language_server_statuses = language_servers
8121 .into_iter()
8122 .zip(server_capabilities)
8123 .map(|(server, server_capabilities)| {
8124 let server_id = LanguageServerId(server.id as usize);
8125 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8126 self.lsp_server_capabilities
8127 .insert(server_id, server_capabilities);
8128 }
8129
8130 let name = LanguageServerName::from_proto(server.name);
8131 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8132
8133 if let Some(lsp_logs) = &lsp_logs {
8134 lsp_logs.update(cx, |lsp_logs, cx| {
8135 lsp_logs.add_language_server(
8136 // Only remote clients get their language servers set from proto
8137 LanguageServerKind::Remote {
8138 project: project.clone(),
8139 },
8140 server_id,
8141 Some(name.clone()),
8142 worktree,
8143 None,
8144 cx,
8145 );
8146 });
8147 }
8148
8149 (
8150 server_id,
8151 LanguageServerStatus {
8152 name,
8153 pending_work: Default::default(),
8154 has_pending_diagnostic_updates: false,
8155 progress_tokens: Default::default(),
8156 worktree,
8157 binary: None,
8158 configuration: None,
8159 workspace_folders: BTreeSet::new(),
8160 },
8161 )
8162 })
8163 .collect();
8164 }
8165
8166 #[cfg(test)]
8167 pub fn update_diagnostic_entries(
8168 &mut self,
8169 server_id: LanguageServerId,
8170 abs_path: PathBuf,
8171 result_id: Option<String>,
8172 version: Option<i32>,
8173 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8174 cx: &mut Context<Self>,
8175 ) -> anyhow::Result<()> {
8176 self.merge_diagnostic_entries(
8177 vec![DocumentDiagnosticsUpdate {
8178 diagnostics: DocumentDiagnostics {
8179 diagnostics,
8180 document_abs_path: abs_path,
8181 version,
8182 },
8183 result_id,
8184 server_id,
8185 disk_based_sources: Cow::Borrowed(&[]),
8186 }],
8187 |_, _, _| false,
8188 cx,
8189 )?;
8190 Ok(())
8191 }
8192
8193 pub fn merge_diagnostic_entries<'a>(
8194 &mut self,
8195 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8196 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8197 cx: &mut Context<Self>,
8198 ) -> anyhow::Result<()> {
8199 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8200 let mut updated_diagnostics_paths = HashMap::default();
8201 for mut update in diagnostic_updates {
8202 let abs_path = &update.diagnostics.document_abs_path;
8203 let server_id = update.server_id;
8204 let Some((worktree, relative_path)) =
8205 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8206 else {
8207 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8208 return Ok(());
8209 };
8210
8211 let worktree_id = worktree.read(cx).id();
8212 let project_path = ProjectPath {
8213 worktree_id,
8214 path: relative_path,
8215 };
8216
8217 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8218 let snapshot = buffer_handle.read(cx).snapshot();
8219 let buffer = buffer_handle.read(cx);
8220 let reused_diagnostics = buffer
8221 .buffer_diagnostics(Some(server_id))
8222 .iter()
8223 .filter(|v| merge(buffer, &v.diagnostic, cx))
8224 .map(|v| {
8225 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8226 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8227 DiagnosticEntry {
8228 range: start..end,
8229 diagnostic: v.diagnostic.clone(),
8230 }
8231 })
8232 .collect::<Vec<_>>();
8233
8234 self.as_local_mut()
8235 .context("cannot merge diagnostics on a remote LspStore")?
8236 .update_buffer_diagnostics(
8237 &buffer_handle,
8238 server_id,
8239 update.result_id,
8240 update.diagnostics.version,
8241 update.diagnostics.diagnostics.clone(),
8242 reused_diagnostics.clone(),
8243 cx,
8244 )?;
8245
8246 update.diagnostics.diagnostics.extend(reused_diagnostics);
8247 }
8248
8249 let updated = worktree.update(cx, |worktree, cx| {
8250 self.update_worktree_diagnostics(
8251 worktree.id(),
8252 server_id,
8253 project_path.path.clone(),
8254 update.diagnostics.diagnostics,
8255 cx,
8256 )
8257 })?;
8258 match updated {
8259 ControlFlow::Continue(new_summary) => {
8260 if let Some((project_id, new_summary)) = new_summary {
8261 match &mut diagnostics_summary {
8262 Some(diagnostics_summary) => {
8263 diagnostics_summary
8264 .more_summaries
8265 .push(proto::DiagnosticSummary {
8266 path: project_path.path.as_ref().to_proto(),
8267 language_server_id: server_id.0 as u64,
8268 error_count: new_summary.error_count,
8269 warning_count: new_summary.warning_count,
8270 })
8271 }
8272 None => {
8273 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8274 project_id,
8275 worktree_id: worktree_id.to_proto(),
8276 summary: Some(proto::DiagnosticSummary {
8277 path: project_path.path.as_ref().to_proto(),
8278 language_server_id: server_id.0 as u64,
8279 error_count: new_summary.error_count,
8280 warning_count: new_summary.warning_count,
8281 }),
8282 more_summaries: Vec::new(),
8283 })
8284 }
8285 }
8286 }
8287 updated_diagnostics_paths
8288 .entry(server_id)
8289 .or_insert_with(Vec::new)
8290 .push(project_path);
8291 }
8292 ControlFlow::Break(()) => {}
8293 }
8294 }
8295
8296 if let Some((diagnostics_summary, (downstream_client, _))) =
8297 diagnostics_summary.zip(self.downstream_client.as_ref())
8298 {
8299 downstream_client.send(diagnostics_summary).log_err();
8300 }
8301 for (server_id, paths) in updated_diagnostics_paths {
8302 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8303 }
8304 Ok(())
8305 }
8306
8307 fn update_worktree_diagnostics(
8308 &mut self,
8309 worktree_id: WorktreeId,
8310 server_id: LanguageServerId,
8311 path_in_worktree: Arc<RelPath>,
8312 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8313 _: &mut Context<Worktree>,
8314 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8315 let local = match &mut self.mode {
8316 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8317 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8318 };
8319
8320 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8321 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8322 let summaries_by_server_id = summaries_for_tree
8323 .entry(path_in_worktree.clone())
8324 .or_default();
8325
8326 let old_summary = summaries_by_server_id
8327 .remove(&server_id)
8328 .unwrap_or_default();
8329
8330 let new_summary = DiagnosticSummary::new(&diagnostics);
8331 if new_summary.is_empty() {
8332 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8333 {
8334 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8335 diagnostics_by_server_id.remove(ix);
8336 }
8337 if diagnostics_by_server_id.is_empty() {
8338 diagnostics_for_tree.remove(&path_in_worktree);
8339 }
8340 }
8341 } else {
8342 summaries_by_server_id.insert(server_id, new_summary);
8343 let diagnostics_by_server_id = diagnostics_for_tree
8344 .entry(path_in_worktree.clone())
8345 .or_default();
8346 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8347 Ok(ix) => {
8348 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8349 }
8350 Err(ix) => {
8351 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8352 }
8353 }
8354 }
8355
8356 if !old_summary.is_empty() || !new_summary.is_empty() {
8357 if let Some((_, project_id)) = &self.downstream_client {
8358 Ok(ControlFlow::Continue(Some((
8359 *project_id,
8360 proto::DiagnosticSummary {
8361 path: path_in_worktree.to_proto(),
8362 language_server_id: server_id.0 as u64,
8363 error_count: new_summary.error_count as u32,
8364 warning_count: new_summary.warning_count as u32,
8365 },
8366 ))))
8367 } else {
8368 Ok(ControlFlow::Continue(None))
8369 }
8370 } else {
8371 Ok(ControlFlow::Break(()))
8372 }
8373 }
8374
8375 pub fn open_buffer_for_symbol(
8376 &mut self,
8377 symbol: &Symbol,
8378 cx: &mut Context<Self>,
8379 ) -> Task<Result<Entity<Buffer>>> {
8380 if let Some((client, project_id)) = self.upstream_client() {
8381 let request = client.request(proto::OpenBufferForSymbol {
8382 project_id,
8383 symbol: Some(Self::serialize_symbol(symbol)),
8384 });
8385 cx.spawn(async move |this, cx| {
8386 let response = request.await?;
8387 let buffer_id = BufferId::new(response.buffer_id)?;
8388 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8389 .await
8390 })
8391 } else if let Some(local) = self.as_local() {
8392 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8393 seed.worktree_id == symbol.source_worktree_id
8394 && state.id == symbol.source_language_server_id
8395 && symbol.language_server_name == seed.name
8396 });
8397 if !is_valid {
8398 return Task::ready(Err(anyhow!(
8399 "language server for worktree and language not found"
8400 )));
8401 };
8402
8403 let symbol_abs_path = match &symbol.path {
8404 SymbolLocation::InProject(project_path) => self
8405 .worktree_store
8406 .read(cx)
8407 .absolutize(&project_path, cx)
8408 .context("no such worktree"),
8409 SymbolLocation::OutsideProject {
8410 abs_path,
8411 signature: _,
8412 } => Ok(abs_path.to_path_buf()),
8413 };
8414 let symbol_abs_path = match symbol_abs_path {
8415 Ok(abs_path) => abs_path,
8416 Err(err) => return Task::ready(Err(err)),
8417 };
8418 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8419 uri
8420 } else {
8421 return Task::ready(Err(anyhow!("invalid symbol path")));
8422 };
8423
8424 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8425 } else {
8426 Task::ready(Err(anyhow!("no upstream client or local store")))
8427 }
8428 }
8429
8430 pub(crate) fn open_local_buffer_via_lsp(
8431 &mut self,
8432 abs_path: lsp::Uri,
8433 language_server_id: LanguageServerId,
8434 cx: &mut Context<Self>,
8435 ) -> Task<Result<Entity<Buffer>>> {
8436 cx.spawn(async move |lsp_store, cx| {
8437 // Escape percent-encoded string.
8438 let current_scheme = abs_path.scheme().to_owned();
8439 // Uri is immutable, so we can't modify the scheme
8440
8441 let abs_path = abs_path
8442 .to_file_path()
8443 .map_err(|()| anyhow!("can't convert URI to path"))?;
8444 let p = abs_path.clone();
8445 let yarn_worktree = lsp_store
8446 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8447 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8448 cx.spawn(async move |this, cx| {
8449 let t = this
8450 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8451 .ok()?;
8452 t.await
8453 })
8454 }),
8455 None => Task::ready(None),
8456 })?
8457 .await;
8458 let (worktree_root_target, known_relative_path) =
8459 if let Some((zip_root, relative_path)) = yarn_worktree {
8460 (zip_root, Some(relative_path))
8461 } else {
8462 (Arc::<Path>::from(abs_path.as_path()), None)
8463 };
8464 let (worktree, relative_path) = if let Some(result) =
8465 lsp_store.update(cx, |lsp_store, cx| {
8466 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8467 worktree_store.find_worktree(&worktree_root_target, cx)
8468 })
8469 })? {
8470 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8471 (result.0, relative_path)
8472 } else {
8473 let worktree = lsp_store
8474 .update(cx, |lsp_store, cx| {
8475 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8476 worktree_store.create_worktree(&worktree_root_target, false, cx)
8477 })
8478 })?
8479 .await?;
8480 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8481 lsp_store
8482 .update(cx, |lsp_store, cx| {
8483 if let Some(local) = lsp_store.as_local_mut() {
8484 local.register_language_server_for_invisible_worktree(
8485 &worktree,
8486 language_server_id,
8487 cx,
8488 )
8489 }
8490 })
8491 .ok();
8492 }
8493 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8494 let relative_path = if let Some(known_path) = known_relative_path {
8495 known_path
8496 } else {
8497 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8498 .into_arc()
8499 };
8500 (worktree, relative_path)
8501 };
8502 let project_path = ProjectPath {
8503 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8504 path: relative_path,
8505 };
8506 lsp_store
8507 .update(cx, |lsp_store, cx| {
8508 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8509 buffer_store.open_buffer(project_path, cx)
8510 })
8511 })?
8512 .await
8513 })
8514 }
8515
8516 fn request_multiple_lsp_locally<P, R>(
8517 &mut self,
8518 buffer: &Entity<Buffer>,
8519 position: Option<P>,
8520 request: R,
8521 cx: &mut Context<Self>,
8522 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8523 where
8524 P: ToOffset,
8525 R: LspCommand + Clone,
8526 <R::LspRequest as lsp::request::Request>::Result: Send,
8527 <R::LspRequest as lsp::request::Request>::Params: Send,
8528 {
8529 let Some(local) = self.as_local() else {
8530 return Task::ready(Vec::new());
8531 };
8532
8533 let snapshot = buffer.read(cx).snapshot();
8534 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8535
8536 let server_ids = buffer.update(cx, |buffer, cx| {
8537 local
8538 .language_servers_for_buffer(buffer, cx)
8539 .filter(|(adapter, _)| {
8540 scope
8541 .as_ref()
8542 .map(|scope| scope.language_allowed(&adapter.name))
8543 .unwrap_or(true)
8544 })
8545 .map(|(_, server)| server.server_id())
8546 .filter(|server_id| {
8547 self.as_local().is_none_or(|local| {
8548 local
8549 .buffers_opened_in_servers
8550 .get(&snapshot.remote_id())
8551 .is_some_and(|servers| servers.contains(server_id))
8552 })
8553 })
8554 .collect::<Vec<_>>()
8555 });
8556
8557 let mut response_results = server_ids
8558 .into_iter()
8559 .map(|server_id| {
8560 let task = self.request_lsp(
8561 buffer.clone(),
8562 LanguageServerToQuery::Other(server_id),
8563 request.clone(),
8564 cx,
8565 );
8566 async move { (server_id, task.await) }
8567 })
8568 .collect::<FuturesUnordered<_>>();
8569
8570 cx.background_spawn(async move {
8571 let mut responses = Vec::with_capacity(response_results.len());
8572 while let Some((server_id, response_result)) = response_results.next().await {
8573 match response_result {
8574 Ok(response) => responses.push((server_id, response)),
8575 // rust-analyzer likes to error with this when its still loading up
8576 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8577 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8578 }
8579 }
8580 responses
8581 })
8582 }
8583
8584 async fn handle_lsp_get_completions(
8585 this: Entity<Self>,
8586 envelope: TypedEnvelope<proto::GetCompletions>,
8587 mut cx: AsyncApp,
8588 ) -> Result<proto::GetCompletionsResponse> {
8589 let sender_id = envelope.original_sender_id().unwrap_or_default();
8590
8591 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8592 let buffer_handle = this.update(&mut cx, |this, cx| {
8593 this.buffer_store.read(cx).get_existing(buffer_id)
8594 })??;
8595 let request = GetCompletions::from_proto(
8596 envelope.payload,
8597 this.clone(),
8598 buffer_handle.clone(),
8599 cx.clone(),
8600 )
8601 .await?;
8602
8603 let server_to_query = match request.server_id {
8604 Some(server_id) => LanguageServerToQuery::Other(server_id),
8605 None => LanguageServerToQuery::FirstCapable,
8606 };
8607
8608 let response = this
8609 .update(&mut cx, |this, cx| {
8610 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8611 })?
8612 .await?;
8613 this.update(&mut cx, |this, cx| {
8614 Ok(GetCompletions::response_to_proto(
8615 response,
8616 this,
8617 sender_id,
8618 &buffer_handle.read(cx).version(),
8619 cx,
8620 ))
8621 })?
8622 }
8623
8624 async fn handle_lsp_command<T: LspCommand>(
8625 this: Entity<Self>,
8626 envelope: TypedEnvelope<T::ProtoRequest>,
8627 mut cx: AsyncApp,
8628 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8629 where
8630 <T::LspRequest as lsp::request::Request>::Params: Send,
8631 <T::LspRequest as lsp::request::Request>::Result: Send,
8632 {
8633 let sender_id = envelope.original_sender_id().unwrap_or_default();
8634 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8635 let buffer_handle = this.update(&mut cx, |this, cx| {
8636 this.buffer_store.read(cx).get_existing(buffer_id)
8637 })??;
8638 let request = T::from_proto(
8639 envelope.payload,
8640 this.clone(),
8641 buffer_handle.clone(),
8642 cx.clone(),
8643 )
8644 .await?;
8645 let response = this
8646 .update(&mut cx, |this, cx| {
8647 this.request_lsp(
8648 buffer_handle.clone(),
8649 LanguageServerToQuery::FirstCapable,
8650 request,
8651 cx,
8652 )
8653 })?
8654 .await?;
8655 this.update(&mut cx, |this, cx| {
8656 Ok(T::response_to_proto(
8657 response,
8658 this,
8659 sender_id,
8660 &buffer_handle.read(cx).version(),
8661 cx,
8662 ))
8663 })?
8664 }
8665
8666 async fn handle_lsp_query(
8667 lsp_store: Entity<Self>,
8668 envelope: TypedEnvelope<proto::LspQuery>,
8669 mut cx: AsyncApp,
8670 ) -> Result<proto::Ack> {
8671 use proto::lsp_query::Request;
8672 let sender_id = envelope.original_sender_id().unwrap_or_default();
8673 let lsp_query = envelope.payload;
8674 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8675 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8676 match lsp_query.request.context("invalid LSP query request")? {
8677 Request::GetReferences(get_references) => {
8678 let position = get_references.position.clone().and_then(deserialize_anchor);
8679 Self::query_lsp_locally::<GetReferences>(
8680 lsp_store,
8681 server_id,
8682 sender_id,
8683 lsp_request_id,
8684 get_references,
8685 position,
8686 &mut cx,
8687 )
8688 .await?;
8689 }
8690 Request::GetDocumentColor(get_document_color) => {
8691 Self::query_lsp_locally::<GetDocumentColor>(
8692 lsp_store,
8693 server_id,
8694 sender_id,
8695 lsp_request_id,
8696 get_document_color,
8697 None,
8698 &mut cx,
8699 )
8700 .await?;
8701 }
8702 Request::GetHover(get_hover) => {
8703 let position = get_hover.position.clone().and_then(deserialize_anchor);
8704 Self::query_lsp_locally::<GetHover>(
8705 lsp_store,
8706 server_id,
8707 sender_id,
8708 lsp_request_id,
8709 get_hover,
8710 position,
8711 &mut cx,
8712 )
8713 .await?;
8714 }
8715 Request::GetCodeActions(get_code_actions) => {
8716 Self::query_lsp_locally::<GetCodeActions>(
8717 lsp_store,
8718 server_id,
8719 sender_id,
8720 lsp_request_id,
8721 get_code_actions,
8722 None,
8723 &mut cx,
8724 )
8725 .await?;
8726 }
8727 Request::GetSignatureHelp(get_signature_help) => {
8728 let position = get_signature_help
8729 .position
8730 .clone()
8731 .and_then(deserialize_anchor);
8732 Self::query_lsp_locally::<GetSignatureHelp>(
8733 lsp_store,
8734 server_id,
8735 sender_id,
8736 lsp_request_id,
8737 get_signature_help,
8738 position,
8739 &mut cx,
8740 )
8741 .await?;
8742 }
8743 Request::GetCodeLens(get_code_lens) => {
8744 Self::query_lsp_locally::<GetCodeLens>(
8745 lsp_store,
8746 server_id,
8747 sender_id,
8748 lsp_request_id,
8749 get_code_lens,
8750 None,
8751 &mut cx,
8752 )
8753 .await?;
8754 }
8755 Request::GetDefinition(get_definition) => {
8756 let position = get_definition.position.clone().and_then(deserialize_anchor);
8757 Self::query_lsp_locally::<GetDefinitions>(
8758 lsp_store,
8759 server_id,
8760 sender_id,
8761 lsp_request_id,
8762 get_definition,
8763 position,
8764 &mut cx,
8765 )
8766 .await?;
8767 }
8768 Request::GetDeclaration(get_declaration) => {
8769 let position = get_declaration
8770 .position
8771 .clone()
8772 .and_then(deserialize_anchor);
8773 Self::query_lsp_locally::<GetDeclarations>(
8774 lsp_store,
8775 server_id,
8776 sender_id,
8777 lsp_request_id,
8778 get_declaration,
8779 position,
8780 &mut cx,
8781 )
8782 .await?;
8783 }
8784 Request::GetTypeDefinition(get_type_definition) => {
8785 let position = get_type_definition
8786 .position
8787 .clone()
8788 .and_then(deserialize_anchor);
8789 Self::query_lsp_locally::<GetTypeDefinitions>(
8790 lsp_store,
8791 server_id,
8792 sender_id,
8793 lsp_request_id,
8794 get_type_definition,
8795 position,
8796 &mut cx,
8797 )
8798 .await?;
8799 }
8800 Request::GetImplementation(get_implementation) => {
8801 let position = get_implementation
8802 .position
8803 .clone()
8804 .and_then(deserialize_anchor);
8805 Self::query_lsp_locally::<GetImplementations>(
8806 lsp_store,
8807 server_id,
8808 sender_id,
8809 lsp_request_id,
8810 get_implementation,
8811 position,
8812 &mut cx,
8813 )
8814 .await?;
8815 }
8816 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8817 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8818 let version = deserialize_version(get_document_diagnostics.buffer_version());
8819 let buffer = lsp_store.update(&mut cx, |this, cx| {
8820 this.buffer_store.read(cx).get_existing(buffer_id)
8821 })??;
8822 buffer
8823 .update(&mut cx, |buffer, _| {
8824 buffer.wait_for_version(version.clone())
8825 })?
8826 .await?;
8827 lsp_store.update(&mut cx, |lsp_store, cx| {
8828 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8829 let key = LspKey {
8830 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8831 server_queried: server_id,
8832 };
8833 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8834 ) {
8835 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8836 lsp_requests.clear();
8837 };
8838 }
8839
8840 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8841 existing_queries.insert(
8842 lsp_request_id,
8843 cx.spawn(async move |lsp_store, cx| {
8844 let diagnostics_pull = lsp_store
8845 .update(cx, |lsp_store, cx| {
8846 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8847 })
8848 .ok();
8849 if let Some(diagnostics_pull) = diagnostics_pull {
8850 match diagnostics_pull.await {
8851 Ok(()) => {}
8852 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8853 };
8854 }
8855 }),
8856 );
8857 })?;
8858 }
8859 Request::InlayHints(inlay_hints) => {
8860 let query_start = inlay_hints
8861 .start
8862 .clone()
8863 .and_then(deserialize_anchor)
8864 .context("invalid inlay hints range start")?;
8865 let query_end = inlay_hints
8866 .end
8867 .clone()
8868 .and_then(deserialize_anchor)
8869 .context("invalid inlay hints range end")?;
8870 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8871 &lsp_store,
8872 server_id,
8873 lsp_request_id,
8874 &inlay_hints,
8875 query_start..query_end,
8876 &mut cx,
8877 )
8878 .await
8879 .context("preparing inlay hints request")?;
8880 Self::query_lsp_locally::<InlayHints>(
8881 lsp_store,
8882 server_id,
8883 sender_id,
8884 lsp_request_id,
8885 inlay_hints,
8886 None,
8887 &mut cx,
8888 )
8889 .await
8890 .context("querying for inlay hints")?
8891 }
8892 }
8893 Ok(proto::Ack {})
8894 }
8895
8896 async fn handle_lsp_query_response(
8897 lsp_store: Entity<Self>,
8898 envelope: TypedEnvelope<proto::LspQueryResponse>,
8899 cx: AsyncApp,
8900 ) -> Result<()> {
8901 lsp_store.read_with(&cx, |lsp_store, _| {
8902 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8903 upstream_client.handle_lsp_response(envelope.clone());
8904 }
8905 })?;
8906 Ok(())
8907 }
8908
8909 async fn handle_apply_code_action(
8910 this: Entity<Self>,
8911 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8912 mut cx: AsyncApp,
8913 ) -> Result<proto::ApplyCodeActionResponse> {
8914 let sender_id = envelope.original_sender_id().unwrap_or_default();
8915 let action =
8916 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8917 let apply_code_action = this.update(&mut cx, |this, cx| {
8918 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8919 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8920 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8921 })??;
8922
8923 let project_transaction = apply_code_action.await?;
8924 let project_transaction = this.update(&mut cx, |this, cx| {
8925 this.buffer_store.update(cx, |buffer_store, cx| {
8926 buffer_store.serialize_project_transaction_for_peer(
8927 project_transaction,
8928 sender_id,
8929 cx,
8930 )
8931 })
8932 })?;
8933 Ok(proto::ApplyCodeActionResponse {
8934 transaction: Some(project_transaction),
8935 })
8936 }
8937
8938 async fn handle_register_buffer_with_language_servers(
8939 this: Entity<Self>,
8940 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8941 mut cx: AsyncApp,
8942 ) -> Result<proto::Ack> {
8943 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8944 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8945 this.update(&mut cx, |this, cx| {
8946 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8947 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8948 project_id: upstream_project_id,
8949 buffer_id: buffer_id.to_proto(),
8950 only_servers: envelope.payload.only_servers,
8951 });
8952 }
8953
8954 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8955 anyhow::bail!("buffer is not open");
8956 };
8957
8958 let handle = this.register_buffer_with_language_servers(
8959 &buffer,
8960 envelope
8961 .payload
8962 .only_servers
8963 .into_iter()
8964 .filter_map(|selector| {
8965 Some(match selector.selector? {
8966 proto::language_server_selector::Selector::ServerId(server_id) => {
8967 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8968 }
8969 proto::language_server_selector::Selector::Name(name) => {
8970 LanguageServerSelector::Name(LanguageServerName(
8971 SharedString::from(name),
8972 ))
8973 }
8974 })
8975 })
8976 .collect(),
8977 false,
8978 cx,
8979 );
8980 this.buffer_store().update(cx, |buffer_store, _| {
8981 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8982 });
8983
8984 Ok(())
8985 })??;
8986 Ok(proto::Ack {})
8987 }
8988
8989 async fn handle_rename_project_entry(
8990 this: Entity<Self>,
8991 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8992 mut cx: AsyncApp,
8993 ) -> Result<proto::ProjectEntryResponse> {
8994 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8995 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8996 let new_path =
8997 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8998
8999 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9000 .update(&mut cx, |this, cx| {
9001 let (worktree, entry) = this
9002 .worktree_store
9003 .read(cx)
9004 .worktree_and_entry_for_id(entry_id, cx)?;
9005 let new_worktree = this
9006 .worktree_store
9007 .read(cx)
9008 .worktree_for_id(new_worktree_id, cx)?;
9009 Some((
9010 this.worktree_store.clone(),
9011 worktree,
9012 new_worktree,
9013 entry.clone(),
9014 ))
9015 })?
9016 .context("worktree not found")?;
9017 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9018 (worktree.absolutize(&old_entry.path), worktree.id())
9019 })?;
9020 let new_abs_path =
9021 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9022
9023 let _transaction = Self::will_rename_entry(
9024 this.downgrade(),
9025 old_worktree_id,
9026 &old_abs_path,
9027 &new_abs_path,
9028 old_entry.is_dir(),
9029 cx.clone(),
9030 )
9031 .await;
9032 let response = WorktreeStore::handle_rename_project_entry(
9033 worktree_store,
9034 envelope.payload,
9035 cx.clone(),
9036 )
9037 .await;
9038 this.read_with(&cx, |this, _| {
9039 this.did_rename_entry(
9040 old_worktree_id,
9041 &old_abs_path,
9042 &new_abs_path,
9043 old_entry.is_dir(),
9044 );
9045 })
9046 .ok();
9047 response
9048 }
9049
9050 async fn handle_update_diagnostic_summary(
9051 this: Entity<Self>,
9052 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9053 mut cx: AsyncApp,
9054 ) -> Result<()> {
9055 this.update(&mut cx, |lsp_store, cx| {
9056 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9057 let mut updated_diagnostics_paths = HashMap::default();
9058 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9059 for message_summary in envelope
9060 .payload
9061 .summary
9062 .into_iter()
9063 .chain(envelope.payload.more_summaries)
9064 {
9065 let project_path = ProjectPath {
9066 worktree_id,
9067 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9068 };
9069 let path = project_path.path.clone();
9070 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9071 let summary = DiagnosticSummary {
9072 error_count: message_summary.error_count as usize,
9073 warning_count: message_summary.warning_count as usize,
9074 };
9075
9076 if summary.is_empty() {
9077 if let Some(worktree_summaries) =
9078 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9079 && let Some(summaries) = worktree_summaries.get_mut(&path)
9080 {
9081 summaries.remove(&server_id);
9082 if summaries.is_empty() {
9083 worktree_summaries.remove(&path);
9084 }
9085 }
9086 } else {
9087 lsp_store
9088 .diagnostic_summaries
9089 .entry(worktree_id)
9090 .or_default()
9091 .entry(path)
9092 .or_default()
9093 .insert(server_id, summary);
9094 }
9095
9096 if let Some((_, project_id)) = &lsp_store.downstream_client {
9097 match &mut diagnostics_summary {
9098 Some(diagnostics_summary) => {
9099 diagnostics_summary
9100 .more_summaries
9101 .push(proto::DiagnosticSummary {
9102 path: project_path.path.as_ref().to_proto(),
9103 language_server_id: server_id.0 as u64,
9104 error_count: summary.error_count as u32,
9105 warning_count: summary.warning_count as u32,
9106 })
9107 }
9108 None => {
9109 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9110 project_id: *project_id,
9111 worktree_id: worktree_id.to_proto(),
9112 summary: Some(proto::DiagnosticSummary {
9113 path: project_path.path.as_ref().to_proto(),
9114 language_server_id: server_id.0 as u64,
9115 error_count: summary.error_count as u32,
9116 warning_count: summary.warning_count as u32,
9117 }),
9118 more_summaries: Vec::new(),
9119 })
9120 }
9121 }
9122 }
9123 updated_diagnostics_paths
9124 .entry(server_id)
9125 .or_insert_with(Vec::new)
9126 .push(project_path);
9127 }
9128
9129 if let Some((diagnostics_summary, (downstream_client, _))) =
9130 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9131 {
9132 downstream_client.send(diagnostics_summary).log_err();
9133 }
9134 for (server_id, paths) in updated_diagnostics_paths {
9135 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9136 }
9137 Ok(())
9138 })?
9139 }
9140
9141 async fn handle_start_language_server(
9142 lsp_store: Entity<Self>,
9143 envelope: TypedEnvelope<proto::StartLanguageServer>,
9144 mut cx: AsyncApp,
9145 ) -> Result<()> {
9146 let server = envelope.payload.server.context("invalid server")?;
9147 let server_capabilities =
9148 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9149 .with_context(|| {
9150 format!(
9151 "incorrect server capabilities {}",
9152 envelope.payload.capabilities
9153 )
9154 })?;
9155 lsp_store.update(&mut cx, |lsp_store, cx| {
9156 let server_id = LanguageServerId(server.id as usize);
9157 let server_name = LanguageServerName::from_proto(server.name.clone());
9158 lsp_store
9159 .lsp_server_capabilities
9160 .insert(server_id, server_capabilities);
9161 lsp_store.language_server_statuses.insert(
9162 server_id,
9163 LanguageServerStatus {
9164 name: server_name.clone(),
9165 pending_work: Default::default(),
9166 has_pending_diagnostic_updates: false,
9167 progress_tokens: Default::default(),
9168 worktree: server.worktree_id.map(WorktreeId::from_proto),
9169 binary: None,
9170 configuration: None,
9171 workspace_folders: BTreeSet::new(),
9172 },
9173 );
9174 cx.emit(LspStoreEvent::LanguageServerAdded(
9175 server_id,
9176 server_name,
9177 server.worktree_id.map(WorktreeId::from_proto),
9178 ));
9179 cx.notify();
9180 })?;
9181 Ok(())
9182 }
9183
9184 async fn handle_update_language_server(
9185 lsp_store: Entity<Self>,
9186 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9187 mut cx: AsyncApp,
9188 ) -> Result<()> {
9189 lsp_store.update(&mut cx, |lsp_store, cx| {
9190 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9191
9192 match envelope.payload.variant.context("invalid variant")? {
9193 proto::update_language_server::Variant::WorkStart(payload) => {
9194 lsp_store.on_lsp_work_start(
9195 language_server_id,
9196 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9197 .context("invalid progress token value")?,
9198 LanguageServerProgress {
9199 title: payload.title,
9200 is_disk_based_diagnostics_progress: false,
9201 is_cancellable: payload.is_cancellable.unwrap_or(false),
9202 message: payload.message,
9203 percentage: payload.percentage.map(|p| p as usize),
9204 last_update_at: cx.background_executor().now(),
9205 },
9206 cx,
9207 );
9208 }
9209 proto::update_language_server::Variant::WorkProgress(payload) => {
9210 lsp_store.on_lsp_work_progress(
9211 language_server_id,
9212 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9213 .context("invalid progress token value")?,
9214 LanguageServerProgress {
9215 title: None,
9216 is_disk_based_diagnostics_progress: false,
9217 is_cancellable: payload.is_cancellable.unwrap_or(false),
9218 message: payload.message,
9219 percentage: payload.percentage.map(|p| p as usize),
9220 last_update_at: cx.background_executor().now(),
9221 },
9222 cx,
9223 );
9224 }
9225
9226 proto::update_language_server::Variant::WorkEnd(payload) => {
9227 lsp_store.on_lsp_work_end(
9228 language_server_id,
9229 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9230 .context("invalid progress token value")?,
9231 cx,
9232 );
9233 }
9234
9235 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9236 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9237 }
9238
9239 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9240 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9241 }
9242
9243 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9244 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9245 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9246 cx.emit(LspStoreEvent::LanguageServerUpdate {
9247 language_server_id,
9248 name: envelope
9249 .payload
9250 .server_name
9251 .map(SharedString::new)
9252 .map(LanguageServerName),
9253 message: non_lsp,
9254 });
9255 }
9256 }
9257
9258 Ok(())
9259 })?
9260 }
9261
9262 async fn handle_language_server_log(
9263 this: Entity<Self>,
9264 envelope: TypedEnvelope<proto::LanguageServerLog>,
9265 mut cx: AsyncApp,
9266 ) -> Result<()> {
9267 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9268 let log_type = envelope
9269 .payload
9270 .log_type
9271 .map(LanguageServerLogType::from_proto)
9272 .context("invalid language server log type")?;
9273
9274 let message = envelope.payload.message;
9275
9276 this.update(&mut cx, |_, cx| {
9277 cx.emit(LspStoreEvent::LanguageServerLog(
9278 language_server_id,
9279 log_type,
9280 message,
9281 ));
9282 })
9283 }
9284
9285 async fn handle_lsp_ext_cancel_flycheck(
9286 lsp_store: Entity<Self>,
9287 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9288 cx: AsyncApp,
9289 ) -> Result<proto::Ack> {
9290 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9291 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9292 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9293 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9294 } else {
9295 None
9296 }
9297 })?;
9298 if let Some(task) = task {
9299 task.context("handling lsp ext cancel flycheck")?;
9300 }
9301
9302 Ok(proto::Ack {})
9303 }
9304
9305 async fn handle_lsp_ext_run_flycheck(
9306 lsp_store: Entity<Self>,
9307 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9308 mut cx: AsyncApp,
9309 ) -> Result<proto::Ack> {
9310 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9311 lsp_store.update(&mut cx, |lsp_store, cx| {
9312 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9313 let text_document = if envelope.payload.current_file_only {
9314 let buffer_id = envelope
9315 .payload
9316 .buffer_id
9317 .map(|id| BufferId::new(id))
9318 .transpose()?;
9319 buffer_id
9320 .and_then(|buffer_id| {
9321 lsp_store
9322 .buffer_store()
9323 .read(cx)
9324 .get(buffer_id)
9325 .and_then(|buffer| {
9326 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9327 })
9328 .map(|path| make_text_document_identifier(&path))
9329 })
9330 .transpose()?
9331 } else {
9332 None
9333 };
9334 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9335 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9336 )?;
9337 }
9338 anyhow::Ok(())
9339 })??;
9340
9341 Ok(proto::Ack {})
9342 }
9343
9344 async fn handle_lsp_ext_clear_flycheck(
9345 lsp_store: Entity<Self>,
9346 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9347 cx: AsyncApp,
9348 ) -> Result<proto::Ack> {
9349 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9350 lsp_store
9351 .read_with(&cx, |lsp_store, _| {
9352 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9353 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9354 } else {
9355 None
9356 }
9357 })
9358 .context("handling lsp ext clear flycheck")?;
9359
9360 Ok(proto::Ack {})
9361 }
9362
9363 pub fn disk_based_diagnostics_started(
9364 &mut self,
9365 language_server_id: LanguageServerId,
9366 cx: &mut Context<Self>,
9367 ) {
9368 if let Some(language_server_status) =
9369 self.language_server_statuses.get_mut(&language_server_id)
9370 {
9371 language_server_status.has_pending_diagnostic_updates = true;
9372 }
9373
9374 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9375 cx.emit(LspStoreEvent::LanguageServerUpdate {
9376 language_server_id,
9377 name: self
9378 .language_server_adapter_for_id(language_server_id)
9379 .map(|adapter| adapter.name()),
9380 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9381 Default::default(),
9382 ),
9383 })
9384 }
9385
9386 pub fn disk_based_diagnostics_finished(
9387 &mut self,
9388 language_server_id: LanguageServerId,
9389 cx: &mut Context<Self>,
9390 ) {
9391 if let Some(language_server_status) =
9392 self.language_server_statuses.get_mut(&language_server_id)
9393 {
9394 language_server_status.has_pending_diagnostic_updates = false;
9395 }
9396
9397 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9398 cx.emit(LspStoreEvent::LanguageServerUpdate {
9399 language_server_id,
9400 name: self
9401 .language_server_adapter_for_id(language_server_id)
9402 .map(|adapter| adapter.name()),
9403 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9404 Default::default(),
9405 ),
9406 })
9407 }
9408
9409 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9410 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9411 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9412 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9413 // the language server might take some time to publish diagnostics.
9414 fn simulate_disk_based_diagnostics_events_if_needed(
9415 &mut self,
9416 language_server_id: LanguageServerId,
9417 cx: &mut Context<Self>,
9418 ) {
9419 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9420
9421 let Some(LanguageServerState::Running {
9422 simulate_disk_based_diagnostics_completion,
9423 adapter,
9424 ..
9425 }) = self
9426 .as_local_mut()
9427 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9428 else {
9429 return;
9430 };
9431
9432 if adapter.disk_based_diagnostics_progress_token.is_some() {
9433 return;
9434 }
9435
9436 let prev_task =
9437 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9438 cx.background_executor()
9439 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9440 .await;
9441
9442 this.update(cx, |this, cx| {
9443 this.disk_based_diagnostics_finished(language_server_id, cx);
9444
9445 if let Some(LanguageServerState::Running {
9446 simulate_disk_based_diagnostics_completion,
9447 ..
9448 }) = this.as_local_mut().and_then(|local_store| {
9449 local_store.language_servers.get_mut(&language_server_id)
9450 }) {
9451 *simulate_disk_based_diagnostics_completion = None;
9452 }
9453 })
9454 .ok();
9455 }));
9456
9457 if prev_task.is_none() {
9458 self.disk_based_diagnostics_started(language_server_id, cx);
9459 }
9460 }
9461
9462 pub fn language_server_statuses(
9463 &self,
9464 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9465 self.language_server_statuses
9466 .iter()
9467 .map(|(key, value)| (*key, value))
9468 }
9469
9470 pub(super) fn did_rename_entry(
9471 &self,
9472 worktree_id: WorktreeId,
9473 old_path: &Path,
9474 new_path: &Path,
9475 is_dir: bool,
9476 ) {
9477 maybe!({
9478 let local_store = self.as_local()?;
9479
9480 let old_uri = lsp::Uri::from_file_path(old_path)
9481 .ok()
9482 .map(|uri| uri.to_string())?;
9483 let new_uri = lsp::Uri::from_file_path(new_path)
9484 .ok()
9485 .map(|uri| uri.to_string())?;
9486
9487 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9488 let Some(filter) = local_store
9489 .language_server_paths_watched_for_rename
9490 .get(&language_server.server_id())
9491 else {
9492 continue;
9493 };
9494
9495 if filter.should_send_did_rename(&old_uri, is_dir) {
9496 language_server
9497 .notify::<DidRenameFiles>(RenameFilesParams {
9498 files: vec![FileRename {
9499 old_uri: old_uri.clone(),
9500 new_uri: new_uri.clone(),
9501 }],
9502 })
9503 .ok();
9504 }
9505 }
9506 Some(())
9507 });
9508 }
9509
9510 pub(super) fn will_rename_entry(
9511 this: WeakEntity<Self>,
9512 worktree_id: WorktreeId,
9513 old_path: &Path,
9514 new_path: &Path,
9515 is_dir: bool,
9516 cx: AsyncApp,
9517 ) -> Task<ProjectTransaction> {
9518 let old_uri = lsp::Uri::from_file_path(old_path)
9519 .ok()
9520 .map(|uri| uri.to_string());
9521 let new_uri = lsp::Uri::from_file_path(new_path)
9522 .ok()
9523 .map(|uri| uri.to_string());
9524 cx.spawn(async move |cx| {
9525 let mut tasks = vec![];
9526 this.update(cx, |this, cx| {
9527 let local_store = this.as_local()?;
9528 let old_uri = old_uri?;
9529 let new_uri = new_uri?;
9530 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9531 let Some(filter) = local_store
9532 .language_server_paths_watched_for_rename
9533 .get(&language_server.server_id())
9534 else {
9535 continue;
9536 };
9537
9538 if filter.should_send_will_rename(&old_uri, is_dir) {
9539 let apply_edit = cx.spawn({
9540 let old_uri = old_uri.clone();
9541 let new_uri = new_uri.clone();
9542 let language_server = language_server.clone();
9543 async move |this, cx| {
9544 let edit = language_server
9545 .request::<WillRenameFiles>(RenameFilesParams {
9546 files: vec![FileRename { old_uri, new_uri }],
9547 })
9548 .await
9549 .into_response()
9550 .context("will rename files")
9551 .log_err()
9552 .flatten()?;
9553
9554 let transaction = LocalLspStore::deserialize_workspace_edit(
9555 this.upgrade()?,
9556 edit,
9557 false,
9558 language_server.clone(),
9559 cx,
9560 )
9561 .await
9562 .ok()?;
9563 Some(transaction)
9564 }
9565 });
9566 tasks.push(apply_edit);
9567 }
9568 }
9569 Some(())
9570 })
9571 .ok()
9572 .flatten();
9573 let mut merged_transaction = ProjectTransaction::default();
9574 for task in tasks {
9575 // Await on tasks sequentially so that the order of application of edits is deterministic
9576 // (at least with regards to the order of registration of language servers)
9577 if let Some(transaction) = task.await {
9578 for (buffer, buffer_transaction) in transaction.0 {
9579 merged_transaction.0.insert(buffer, buffer_transaction);
9580 }
9581 }
9582 }
9583 merged_transaction
9584 })
9585 }
9586
9587 fn lsp_notify_abs_paths_changed(
9588 &mut self,
9589 server_id: LanguageServerId,
9590 changes: Vec<PathEvent>,
9591 ) {
9592 maybe!({
9593 let server = self.language_server_for_id(server_id)?;
9594 let changes = changes
9595 .into_iter()
9596 .filter_map(|event| {
9597 let typ = match event.kind? {
9598 PathEventKind::Created => lsp::FileChangeType::CREATED,
9599 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9600 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9601 };
9602 Some(lsp::FileEvent {
9603 uri: file_path_to_lsp_url(&event.path).log_err()?,
9604 typ,
9605 })
9606 })
9607 .collect::<Vec<_>>();
9608 if !changes.is_empty() {
9609 server
9610 .notify::<lsp::notification::DidChangeWatchedFiles>(
9611 lsp::DidChangeWatchedFilesParams { changes },
9612 )
9613 .ok();
9614 }
9615 Some(())
9616 });
9617 }
9618
9619 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9620 self.as_local()?.language_server_for_id(id)
9621 }
9622
9623 fn on_lsp_progress(
9624 &mut self,
9625 progress_params: lsp::ProgressParams,
9626 language_server_id: LanguageServerId,
9627 disk_based_diagnostics_progress_token: Option<String>,
9628 cx: &mut Context<Self>,
9629 ) {
9630 match progress_params.value {
9631 lsp::ProgressParamsValue::WorkDone(progress) => {
9632 self.handle_work_done_progress(
9633 progress,
9634 language_server_id,
9635 disk_based_diagnostics_progress_token,
9636 ProgressToken::from_lsp(progress_params.token),
9637 cx,
9638 );
9639 }
9640 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9641 let identifier = match progress_params.token {
9642 lsp::NumberOrString::Number(_) => None,
9643 lsp::NumberOrString::String(token) => token
9644 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9645 .map(|(_, id)| id.to_owned()),
9646 };
9647 if let Some(LanguageServerState::Running {
9648 workspace_diagnostics_refresh_tasks,
9649 ..
9650 }) = self
9651 .as_local_mut()
9652 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9653 && let Some(workspace_diagnostics) =
9654 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9655 {
9656 workspace_diagnostics.progress_tx.try_send(()).ok();
9657 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9658 }
9659 }
9660 }
9661 }
9662
9663 fn handle_work_done_progress(
9664 &mut self,
9665 progress: lsp::WorkDoneProgress,
9666 language_server_id: LanguageServerId,
9667 disk_based_diagnostics_progress_token: Option<String>,
9668 token: ProgressToken,
9669 cx: &mut Context<Self>,
9670 ) {
9671 let language_server_status =
9672 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9673 status
9674 } else {
9675 return;
9676 };
9677
9678 if !language_server_status.progress_tokens.contains(&token) {
9679 return;
9680 }
9681
9682 let is_disk_based_diagnostics_progress =
9683 if let (Some(disk_based_token), ProgressToken::String(token)) =
9684 (&disk_based_diagnostics_progress_token, &token)
9685 {
9686 token.starts_with(disk_based_token)
9687 } else {
9688 false
9689 };
9690
9691 match progress {
9692 lsp::WorkDoneProgress::Begin(report) => {
9693 if is_disk_based_diagnostics_progress {
9694 self.disk_based_diagnostics_started(language_server_id, cx);
9695 }
9696 self.on_lsp_work_start(
9697 language_server_id,
9698 token.clone(),
9699 LanguageServerProgress {
9700 title: Some(report.title),
9701 is_disk_based_diagnostics_progress,
9702 is_cancellable: report.cancellable.unwrap_or(false),
9703 message: report.message.clone(),
9704 percentage: report.percentage.map(|p| p as usize),
9705 last_update_at: cx.background_executor().now(),
9706 },
9707 cx,
9708 );
9709 }
9710 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9711 language_server_id,
9712 token,
9713 LanguageServerProgress {
9714 title: None,
9715 is_disk_based_diagnostics_progress,
9716 is_cancellable: report.cancellable.unwrap_or(false),
9717 message: report.message,
9718 percentage: report.percentage.map(|p| p as usize),
9719 last_update_at: cx.background_executor().now(),
9720 },
9721 cx,
9722 ),
9723 lsp::WorkDoneProgress::End(_) => {
9724 language_server_status.progress_tokens.remove(&token);
9725 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9726 if is_disk_based_diagnostics_progress {
9727 self.disk_based_diagnostics_finished(language_server_id, cx);
9728 }
9729 }
9730 }
9731 }
9732
9733 fn on_lsp_work_start(
9734 &mut self,
9735 language_server_id: LanguageServerId,
9736 token: ProgressToken,
9737 progress: LanguageServerProgress,
9738 cx: &mut Context<Self>,
9739 ) {
9740 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9741 status.pending_work.insert(token.clone(), progress.clone());
9742 cx.notify();
9743 }
9744 cx.emit(LspStoreEvent::LanguageServerUpdate {
9745 language_server_id,
9746 name: self
9747 .language_server_adapter_for_id(language_server_id)
9748 .map(|adapter| adapter.name()),
9749 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9750 token: Some(token.to_proto()),
9751 title: progress.title,
9752 message: progress.message,
9753 percentage: progress.percentage.map(|p| p as u32),
9754 is_cancellable: Some(progress.is_cancellable),
9755 }),
9756 })
9757 }
9758
9759 fn on_lsp_work_progress(
9760 &mut self,
9761 language_server_id: LanguageServerId,
9762 token: ProgressToken,
9763 progress: LanguageServerProgress,
9764 cx: &mut Context<Self>,
9765 ) {
9766 let mut did_update = false;
9767 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9768 match status.pending_work.entry(token.clone()) {
9769 btree_map::Entry::Vacant(entry) => {
9770 entry.insert(progress.clone());
9771 did_update = true;
9772 }
9773 btree_map::Entry::Occupied(mut entry) => {
9774 let entry = entry.get_mut();
9775 if (progress.last_update_at - entry.last_update_at)
9776 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9777 {
9778 entry.last_update_at = progress.last_update_at;
9779 if progress.message.is_some() {
9780 entry.message = progress.message.clone();
9781 }
9782 if progress.percentage.is_some() {
9783 entry.percentage = progress.percentage;
9784 }
9785 if progress.is_cancellable != entry.is_cancellable {
9786 entry.is_cancellable = progress.is_cancellable;
9787 }
9788 did_update = true;
9789 }
9790 }
9791 }
9792 }
9793
9794 if did_update {
9795 cx.emit(LspStoreEvent::LanguageServerUpdate {
9796 language_server_id,
9797 name: self
9798 .language_server_adapter_for_id(language_server_id)
9799 .map(|adapter| adapter.name()),
9800 message: proto::update_language_server::Variant::WorkProgress(
9801 proto::LspWorkProgress {
9802 token: Some(token.to_proto()),
9803 message: progress.message,
9804 percentage: progress.percentage.map(|p| p as u32),
9805 is_cancellable: Some(progress.is_cancellable),
9806 },
9807 ),
9808 })
9809 }
9810 }
9811
9812 fn on_lsp_work_end(
9813 &mut self,
9814 language_server_id: LanguageServerId,
9815 token: ProgressToken,
9816 cx: &mut Context<Self>,
9817 ) {
9818 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9819 if let Some(work) = status.pending_work.remove(&token)
9820 && !work.is_disk_based_diagnostics_progress
9821 {
9822 cx.emit(LspStoreEvent::RefreshInlayHints {
9823 server_id: language_server_id,
9824 request_id: None,
9825 });
9826 }
9827 cx.notify();
9828 }
9829
9830 cx.emit(LspStoreEvent::LanguageServerUpdate {
9831 language_server_id,
9832 name: self
9833 .language_server_adapter_for_id(language_server_id)
9834 .map(|adapter| adapter.name()),
9835 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9836 token: Some(token.to_proto()),
9837 }),
9838 })
9839 }
9840
9841 pub async fn handle_resolve_completion_documentation(
9842 this: Entity<Self>,
9843 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9844 mut cx: AsyncApp,
9845 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9846 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9847
9848 let completion = this
9849 .read_with(&cx, |this, cx| {
9850 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9851 let server = this
9852 .language_server_for_id(id)
9853 .with_context(|| format!("No language server {id}"))?;
9854
9855 anyhow::Ok(cx.background_spawn(async move {
9856 let can_resolve = server
9857 .capabilities()
9858 .completion_provider
9859 .as_ref()
9860 .and_then(|options| options.resolve_provider)
9861 .unwrap_or(false);
9862 if can_resolve {
9863 server
9864 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9865 .await
9866 .into_response()
9867 .context("resolve completion item")
9868 } else {
9869 anyhow::Ok(lsp_completion)
9870 }
9871 }))
9872 })??
9873 .await?;
9874
9875 let mut documentation_is_markdown = false;
9876 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9877 let documentation = match completion.documentation {
9878 Some(lsp::Documentation::String(text)) => text,
9879
9880 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9881 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9882 value
9883 }
9884
9885 _ => String::new(),
9886 };
9887
9888 // If we have a new buffer_id, that means we're talking to a new client
9889 // and want to check for new text_edits in the completion too.
9890 let mut old_replace_start = None;
9891 let mut old_replace_end = None;
9892 let mut old_insert_start = None;
9893 let mut old_insert_end = None;
9894 let mut new_text = String::default();
9895 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9896 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9897 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9898 anyhow::Ok(buffer.read(cx).snapshot())
9899 })??;
9900
9901 if let Some(text_edit) = completion.text_edit.as_ref() {
9902 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9903
9904 if let Some(mut edit) = edit {
9905 LineEnding::normalize(&mut edit.new_text);
9906
9907 new_text = edit.new_text;
9908 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9909 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9910 if let Some(insert_range) = edit.insert_range {
9911 old_insert_start = Some(serialize_anchor(&insert_range.start));
9912 old_insert_end = Some(serialize_anchor(&insert_range.end));
9913 }
9914 }
9915 }
9916 }
9917
9918 Ok(proto::ResolveCompletionDocumentationResponse {
9919 documentation,
9920 documentation_is_markdown,
9921 old_replace_start,
9922 old_replace_end,
9923 new_text,
9924 lsp_completion,
9925 old_insert_start,
9926 old_insert_end,
9927 })
9928 }
9929
9930 async fn handle_on_type_formatting(
9931 this: Entity<Self>,
9932 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9933 mut cx: AsyncApp,
9934 ) -> Result<proto::OnTypeFormattingResponse> {
9935 let on_type_formatting = this.update(&mut cx, |this, cx| {
9936 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9937 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9938 let position = envelope
9939 .payload
9940 .position
9941 .and_then(deserialize_anchor)
9942 .context("invalid position")?;
9943 anyhow::Ok(this.apply_on_type_formatting(
9944 buffer,
9945 position,
9946 envelope.payload.trigger.clone(),
9947 cx,
9948 ))
9949 })??;
9950
9951 let transaction = on_type_formatting
9952 .await?
9953 .as_ref()
9954 .map(language::proto::serialize_transaction);
9955 Ok(proto::OnTypeFormattingResponse { transaction })
9956 }
9957
9958 async fn handle_refresh_inlay_hints(
9959 lsp_store: Entity<Self>,
9960 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9961 mut cx: AsyncApp,
9962 ) -> Result<proto::Ack> {
9963 lsp_store.update(&mut cx, |_, cx| {
9964 cx.emit(LspStoreEvent::RefreshInlayHints {
9965 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9966 request_id: envelope.payload.request_id.map(|id| id as usize),
9967 });
9968 })?;
9969 Ok(proto::Ack {})
9970 }
9971
9972 async fn handle_pull_workspace_diagnostics(
9973 lsp_store: Entity<Self>,
9974 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9975 mut cx: AsyncApp,
9976 ) -> Result<proto::Ack> {
9977 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9978 lsp_store.update(&mut cx, |lsp_store, _| {
9979 lsp_store.pull_workspace_diagnostics(server_id);
9980 })?;
9981 Ok(proto::Ack {})
9982 }
9983
9984 async fn handle_get_color_presentation(
9985 lsp_store: Entity<Self>,
9986 envelope: TypedEnvelope<proto::GetColorPresentation>,
9987 mut cx: AsyncApp,
9988 ) -> Result<proto::GetColorPresentationResponse> {
9989 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9990 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9991 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9992 })??;
9993
9994 let color = envelope
9995 .payload
9996 .color
9997 .context("invalid color resolve request")?;
9998 let start = color
9999 .lsp_range_start
10000 .context("invalid color resolve request")?;
10001 let end = color
10002 .lsp_range_end
10003 .context("invalid color resolve request")?;
10004
10005 let color = DocumentColor {
10006 lsp_range: lsp::Range {
10007 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10008 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10009 },
10010 color: lsp::Color {
10011 red: color.red,
10012 green: color.green,
10013 blue: color.blue,
10014 alpha: color.alpha,
10015 },
10016 resolved: false,
10017 color_presentations: Vec::new(),
10018 };
10019 let resolved_color = lsp_store
10020 .update(&mut cx, |lsp_store, cx| {
10021 lsp_store.resolve_color_presentation(
10022 color,
10023 buffer.clone(),
10024 LanguageServerId(envelope.payload.server_id as usize),
10025 cx,
10026 )
10027 })?
10028 .await
10029 .context("resolving color presentation")?;
10030
10031 Ok(proto::GetColorPresentationResponse {
10032 presentations: resolved_color
10033 .color_presentations
10034 .into_iter()
10035 .map(|presentation| proto::ColorPresentation {
10036 label: presentation.label.to_string(),
10037 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10038 additional_text_edits: presentation
10039 .additional_text_edits
10040 .into_iter()
10041 .map(serialize_lsp_edit)
10042 .collect(),
10043 })
10044 .collect(),
10045 })
10046 }
10047
10048 async fn handle_resolve_inlay_hint(
10049 lsp_store: Entity<Self>,
10050 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10051 mut cx: AsyncApp,
10052 ) -> Result<proto::ResolveInlayHintResponse> {
10053 let proto_hint = envelope
10054 .payload
10055 .hint
10056 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10057 let hint = InlayHints::proto_to_project_hint(proto_hint)
10058 .context("resolved proto inlay hint conversion")?;
10059 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10060 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10061 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10062 })??;
10063 let response_hint = lsp_store
10064 .update(&mut cx, |lsp_store, cx| {
10065 lsp_store.resolve_inlay_hint(
10066 hint,
10067 buffer,
10068 LanguageServerId(envelope.payload.language_server_id as usize),
10069 cx,
10070 )
10071 })?
10072 .await
10073 .context("inlay hints fetch")?;
10074 Ok(proto::ResolveInlayHintResponse {
10075 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10076 })
10077 }
10078
10079 async fn handle_refresh_code_lens(
10080 this: Entity<Self>,
10081 _: TypedEnvelope<proto::RefreshCodeLens>,
10082 mut cx: AsyncApp,
10083 ) -> Result<proto::Ack> {
10084 this.update(&mut cx, |_, cx| {
10085 cx.emit(LspStoreEvent::RefreshCodeLens);
10086 })?;
10087 Ok(proto::Ack {})
10088 }
10089
10090 async fn handle_open_buffer_for_symbol(
10091 this: Entity<Self>,
10092 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10093 mut cx: AsyncApp,
10094 ) -> Result<proto::OpenBufferForSymbolResponse> {
10095 let peer_id = envelope.original_sender_id().unwrap_or_default();
10096 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10097 let symbol = Self::deserialize_symbol(symbol)?;
10098 this.read_with(&cx, |this, _| {
10099 if let SymbolLocation::OutsideProject {
10100 abs_path,
10101 signature,
10102 } = &symbol.path
10103 {
10104 let new_signature = this.symbol_signature(&abs_path);
10105 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10106 }
10107 Ok(())
10108 })??;
10109 let buffer = this
10110 .update(&mut cx, |this, cx| {
10111 this.open_buffer_for_symbol(
10112 &Symbol {
10113 language_server_name: symbol.language_server_name,
10114 source_worktree_id: symbol.source_worktree_id,
10115 source_language_server_id: symbol.source_language_server_id,
10116 path: symbol.path,
10117 name: symbol.name,
10118 kind: symbol.kind,
10119 range: symbol.range,
10120 label: CodeLabel::default(),
10121 },
10122 cx,
10123 )
10124 })?
10125 .await?;
10126
10127 this.update(&mut cx, |this, cx| {
10128 let is_private = buffer
10129 .read(cx)
10130 .file()
10131 .map(|f| f.is_private())
10132 .unwrap_or_default();
10133 if is_private {
10134 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10135 } else {
10136 this.buffer_store
10137 .update(cx, |buffer_store, cx| {
10138 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10139 })
10140 .detach_and_log_err(cx);
10141 let buffer_id = buffer.read(cx).remote_id().to_proto();
10142 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10143 }
10144 })?
10145 }
10146
10147 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10148 let mut hasher = Sha256::new();
10149 hasher.update(abs_path.to_string_lossy().as_bytes());
10150 hasher.update(self.nonce.to_be_bytes());
10151 hasher.finalize().as_slice().try_into().unwrap()
10152 }
10153
10154 pub async fn handle_get_project_symbols(
10155 this: Entity<Self>,
10156 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10157 mut cx: AsyncApp,
10158 ) -> Result<proto::GetProjectSymbolsResponse> {
10159 let symbols = this
10160 .update(&mut cx, |this, cx| {
10161 this.symbols(&envelope.payload.query, cx)
10162 })?
10163 .await?;
10164
10165 Ok(proto::GetProjectSymbolsResponse {
10166 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10167 })
10168 }
10169
10170 pub async fn handle_restart_language_servers(
10171 this: Entity<Self>,
10172 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10173 mut cx: AsyncApp,
10174 ) -> Result<proto::Ack> {
10175 this.update(&mut cx, |lsp_store, cx| {
10176 let buffers =
10177 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10178 lsp_store.restart_language_servers_for_buffers(
10179 buffers,
10180 envelope
10181 .payload
10182 .only_servers
10183 .into_iter()
10184 .filter_map(|selector| {
10185 Some(match selector.selector? {
10186 proto::language_server_selector::Selector::ServerId(server_id) => {
10187 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10188 }
10189 proto::language_server_selector::Selector::Name(name) => {
10190 LanguageServerSelector::Name(LanguageServerName(
10191 SharedString::from(name),
10192 ))
10193 }
10194 })
10195 })
10196 .collect(),
10197 cx,
10198 );
10199 })?;
10200
10201 Ok(proto::Ack {})
10202 }
10203
10204 pub async fn handle_stop_language_servers(
10205 lsp_store: Entity<Self>,
10206 envelope: TypedEnvelope<proto::StopLanguageServers>,
10207 mut cx: AsyncApp,
10208 ) -> Result<proto::Ack> {
10209 lsp_store.update(&mut cx, |lsp_store, cx| {
10210 if envelope.payload.all
10211 && envelope.payload.also_servers.is_empty()
10212 && envelope.payload.buffer_ids.is_empty()
10213 {
10214 lsp_store.stop_all_language_servers(cx);
10215 } else {
10216 let buffers =
10217 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10218 lsp_store
10219 .stop_language_servers_for_buffers(
10220 buffers,
10221 envelope
10222 .payload
10223 .also_servers
10224 .into_iter()
10225 .filter_map(|selector| {
10226 Some(match selector.selector? {
10227 proto::language_server_selector::Selector::ServerId(
10228 server_id,
10229 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10230 server_id,
10231 )),
10232 proto::language_server_selector::Selector::Name(name) => {
10233 LanguageServerSelector::Name(LanguageServerName(
10234 SharedString::from(name),
10235 ))
10236 }
10237 })
10238 })
10239 .collect(),
10240 cx,
10241 )
10242 .detach_and_log_err(cx);
10243 }
10244 })?;
10245
10246 Ok(proto::Ack {})
10247 }
10248
10249 pub async fn handle_cancel_language_server_work(
10250 lsp_store: Entity<Self>,
10251 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10252 mut cx: AsyncApp,
10253 ) -> Result<proto::Ack> {
10254 lsp_store.update(&mut cx, |lsp_store, cx| {
10255 if let Some(work) = envelope.payload.work {
10256 match work {
10257 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10258 let buffers =
10259 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10260 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10261 }
10262 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10263 let server_id = LanguageServerId::from_proto(work.language_server_id);
10264 let token = work
10265 .token
10266 .map(|token| {
10267 ProgressToken::from_proto(token)
10268 .context("invalid work progress token")
10269 })
10270 .transpose()?;
10271 lsp_store.cancel_language_server_work(server_id, token, cx);
10272 }
10273 }
10274 }
10275 anyhow::Ok(())
10276 })??;
10277
10278 Ok(proto::Ack {})
10279 }
10280
10281 fn buffer_ids_to_buffers(
10282 &mut self,
10283 buffer_ids: impl Iterator<Item = u64>,
10284 cx: &mut Context<Self>,
10285 ) -> Vec<Entity<Buffer>> {
10286 buffer_ids
10287 .into_iter()
10288 .flat_map(|buffer_id| {
10289 self.buffer_store
10290 .read(cx)
10291 .get(BufferId::new(buffer_id).log_err()?)
10292 })
10293 .collect::<Vec<_>>()
10294 }
10295
10296 async fn handle_apply_additional_edits_for_completion(
10297 this: Entity<Self>,
10298 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10299 mut cx: AsyncApp,
10300 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10301 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10302 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10303 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10304 let completion = Self::deserialize_completion(
10305 envelope.payload.completion.context("invalid completion")?,
10306 )?;
10307 anyhow::Ok((buffer, completion))
10308 })??;
10309
10310 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10311 this.apply_additional_edits_for_completion(
10312 buffer,
10313 Rc::new(RefCell::new(Box::new([Completion {
10314 replace_range: completion.replace_range,
10315 new_text: completion.new_text,
10316 source: completion.source,
10317 documentation: None,
10318 label: CodeLabel::default(),
10319 match_start: None,
10320 snippet_deduplication_key: None,
10321 insert_text_mode: None,
10322 icon_path: None,
10323 confirm: None,
10324 }]))),
10325 0,
10326 false,
10327 cx,
10328 )
10329 })?;
10330
10331 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10332 transaction: apply_additional_edits
10333 .await?
10334 .as_ref()
10335 .map(language::proto::serialize_transaction),
10336 })
10337 }
10338
10339 pub fn last_formatting_failure(&self) -> Option<&str> {
10340 self.last_formatting_failure.as_deref()
10341 }
10342
10343 pub fn reset_last_formatting_failure(&mut self) {
10344 self.last_formatting_failure = None;
10345 }
10346
10347 pub fn environment_for_buffer(
10348 &self,
10349 buffer: &Entity<Buffer>,
10350 cx: &mut Context<Self>,
10351 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10352 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10353 environment.update(cx, |env, cx| {
10354 env.buffer_environment(buffer, &self.worktree_store, cx)
10355 })
10356 } else {
10357 Task::ready(None).shared()
10358 }
10359 }
10360
10361 pub fn format(
10362 &mut self,
10363 buffers: HashSet<Entity<Buffer>>,
10364 target: LspFormatTarget,
10365 push_to_history: bool,
10366 trigger: FormatTrigger,
10367 cx: &mut Context<Self>,
10368 ) -> Task<anyhow::Result<ProjectTransaction>> {
10369 let logger = zlog::scoped!("format");
10370 if self.as_local().is_some() {
10371 zlog::trace!(logger => "Formatting locally");
10372 let logger = zlog::scoped!(logger => "local");
10373 let buffers = buffers
10374 .into_iter()
10375 .map(|buffer_handle| {
10376 let buffer = buffer_handle.read(cx);
10377 let buffer_abs_path = File::from_dyn(buffer.file())
10378 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10379
10380 (buffer_handle, buffer_abs_path, buffer.remote_id())
10381 })
10382 .collect::<Vec<_>>();
10383
10384 cx.spawn(async move |lsp_store, cx| {
10385 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10386
10387 for (handle, abs_path, id) in buffers {
10388 let env = lsp_store
10389 .update(cx, |lsp_store, cx| {
10390 lsp_store.environment_for_buffer(&handle, cx)
10391 })?
10392 .await;
10393
10394 let ranges = match &target {
10395 LspFormatTarget::Buffers => None,
10396 LspFormatTarget::Ranges(ranges) => {
10397 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10398 }
10399 };
10400
10401 formattable_buffers.push(FormattableBuffer {
10402 handle,
10403 abs_path,
10404 env,
10405 ranges,
10406 });
10407 }
10408 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10409
10410 let format_timer = zlog::time!(logger => "Formatting buffers");
10411 let result = LocalLspStore::format_locally(
10412 lsp_store.clone(),
10413 formattable_buffers,
10414 push_to_history,
10415 trigger,
10416 logger,
10417 cx,
10418 )
10419 .await;
10420 format_timer.end();
10421
10422 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10423
10424 lsp_store.update(cx, |lsp_store, _| {
10425 lsp_store.update_last_formatting_failure(&result);
10426 })?;
10427
10428 result
10429 })
10430 } else if let Some((client, project_id)) = self.upstream_client() {
10431 zlog::trace!(logger => "Formatting remotely");
10432 let logger = zlog::scoped!(logger => "remote");
10433 // Don't support formatting ranges via remote
10434 match target {
10435 LspFormatTarget::Buffers => {}
10436 LspFormatTarget::Ranges(_) => {
10437 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10438 return Task::ready(Ok(ProjectTransaction::default()));
10439 }
10440 }
10441
10442 let buffer_store = self.buffer_store();
10443 cx.spawn(async move |lsp_store, cx| {
10444 zlog::trace!(logger => "Sending remote format request");
10445 let request_timer = zlog::time!(logger => "remote format request");
10446 let result = client
10447 .request(proto::FormatBuffers {
10448 project_id,
10449 trigger: trigger as i32,
10450 buffer_ids: buffers
10451 .iter()
10452 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10453 .collect::<Result<_>>()?,
10454 })
10455 .await
10456 .and_then(|result| result.transaction.context("missing transaction"));
10457 request_timer.end();
10458
10459 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10460
10461 lsp_store.update(cx, |lsp_store, _| {
10462 lsp_store.update_last_formatting_failure(&result);
10463 })?;
10464
10465 let transaction_response = result?;
10466 let _timer = zlog::time!(logger => "deserializing project transaction");
10467 buffer_store
10468 .update(cx, |buffer_store, cx| {
10469 buffer_store.deserialize_project_transaction(
10470 transaction_response,
10471 push_to_history,
10472 cx,
10473 )
10474 })?
10475 .await
10476 })
10477 } else {
10478 zlog::trace!(logger => "Not formatting");
10479 Task::ready(Ok(ProjectTransaction::default()))
10480 }
10481 }
10482
10483 async fn handle_format_buffers(
10484 this: Entity<Self>,
10485 envelope: TypedEnvelope<proto::FormatBuffers>,
10486 mut cx: AsyncApp,
10487 ) -> Result<proto::FormatBuffersResponse> {
10488 let sender_id = envelope.original_sender_id().unwrap_or_default();
10489 let format = this.update(&mut cx, |this, cx| {
10490 let mut buffers = HashSet::default();
10491 for buffer_id in &envelope.payload.buffer_ids {
10492 let buffer_id = BufferId::new(*buffer_id)?;
10493 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10494 }
10495 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10496 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10497 })??;
10498
10499 let project_transaction = format.await?;
10500 let project_transaction = this.update(&mut cx, |this, cx| {
10501 this.buffer_store.update(cx, |buffer_store, cx| {
10502 buffer_store.serialize_project_transaction_for_peer(
10503 project_transaction,
10504 sender_id,
10505 cx,
10506 )
10507 })
10508 })?;
10509 Ok(proto::FormatBuffersResponse {
10510 transaction: Some(project_transaction),
10511 })
10512 }
10513
10514 async fn handle_apply_code_action_kind(
10515 this: Entity<Self>,
10516 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10517 mut cx: AsyncApp,
10518 ) -> Result<proto::ApplyCodeActionKindResponse> {
10519 let sender_id = envelope.original_sender_id().unwrap_or_default();
10520 let format = this.update(&mut cx, |this, cx| {
10521 let mut buffers = HashSet::default();
10522 for buffer_id in &envelope.payload.buffer_ids {
10523 let buffer_id = BufferId::new(*buffer_id)?;
10524 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10525 }
10526 let kind = match envelope.payload.kind.as_str() {
10527 "" => CodeActionKind::EMPTY,
10528 "quickfix" => CodeActionKind::QUICKFIX,
10529 "refactor" => CodeActionKind::REFACTOR,
10530 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10531 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10532 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10533 "source" => CodeActionKind::SOURCE,
10534 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10535 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10536 _ => anyhow::bail!(
10537 "Invalid code action kind {}",
10538 envelope.payload.kind.as_str()
10539 ),
10540 };
10541 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10542 })??;
10543
10544 let project_transaction = format.await?;
10545 let project_transaction = this.update(&mut cx, |this, cx| {
10546 this.buffer_store.update(cx, |buffer_store, cx| {
10547 buffer_store.serialize_project_transaction_for_peer(
10548 project_transaction,
10549 sender_id,
10550 cx,
10551 )
10552 })
10553 })?;
10554 Ok(proto::ApplyCodeActionKindResponse {
10555 transaction: Some(project_transaction),
10556 })
10557 }
10558
10559 async fn shutdown_language_server(
10560 server_state: Option<LanguageServerState>,
10561 name: LanguageServerName,
10562 cx: &mut AsyncApp,
10563 ) {
10564 let server = match server_state {
10565 Some(LanguageServerState::Starting { startup, .. }) => {
10566 let mut timer = cx
10567 .background_executor()
10568 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10569 .fuse();
10570
10571 select! {
10572 server = startup.fuse() => server,
10573 () = timer => {
10574 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10575 None
10576 },
10577 }
10578 }
10579
10580 Some(LanguageServerState::Running { server, .. }) => Some(server),
10581
10582 None => None,
10583 };
10584
10585 if let Some(server) = server
10586 && let Some(shutdown) = server.shutdown()
10587 {
10588 shutdown.await;
10589 }
10590 }
10591
10592 // Returns a list of all of the worktrees which no longer have a language server and the root path
10593 // for the stopped server
10594 fn stop_local_language_server(
10595 &mut self,
10596 server_id: LanguageServerId,
10597 cx: &mut Context<Self>,
10598 ) -> Task<()> {
10599 let local = match &mut self.mode {
10600 LspStoreMode::Local(local) => local,
10601 _ => {
10602 return Task::ready(());
10603 }
10604 };
10605
10606 // Remove this server ID from all entries in the given worktree.
10607 local
10608 .language_server_ids
10609 .retain(|_, state| state.id != server_id);
10610 self.buffer_store.update(cx, |buffer_store, cx| {
10611 for buffer in buffer_store.buffers() {
10612 buffer.update(cx, |buffer, cx| {
10613 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10614 buffer.set_completion_triggers(server_id, Default::default(), cx);
10615 });
10616 }
10617 });
10618
10619 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10620 summaries.retain(|path, summaries_by_server_id| {
10621 if summaries_by_server_id.remove(&server_id).is_some() {
10622 if let Some((client, project_id)) = self.downstream_client.clone() {
10623 client
10624 .send(proto::UpdateDiagnosticSummary {
10625 project_id,
10626 worktree_id: worktree_id.to_proto(),
10627 summary: Some(proto::DiagnosticSummary {
10628 path: path.as_ref().to_proto(),
10629 language_server_id: server_id.0 as u64,
10630 error_count: 0,
10631 warning_count: 0,
10632 }),
10633 more_summaries: Vec::new(),
10634 })
10635 .log_err();
10636 }
10637 !summaries_by_server_id.is_empty()
10638 } else {
10639 true
10640 }
10641 });
10642 }
10643
10644 let local = self.as_local_mut().unwrap();
10645 for diagnostics in local.diagnostics.values_mut() {
10646 diagnostics.retain(|_, diagnostics_by_server_id| {
10647 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10648 diagnostics_by_server_id.remove(ix);
10649 !diagnostics_by_server_id.is_empty()
10650 } else {
10651 true
10652 }
10653 });
10654 }
10655 local.language_server_watched_paths.remove(&server_id);
10656
10657 let server_state = local.language_servers.remove(&server_id);
10658 self.cleanup_lsp_data(server_id);
10659 let name = self
10660 .language_server_statuses
10661 .remove(&server_id)
10662 .map(|status| status.name)
10663 .or_else(|| {
10664 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10665 Some(adapter.name())
10666 } else {
10667 None
10668 }
10669 });
10670
10671 if let Some(name) = name {
10672 log::info!("stopping language server {name}");
10673 self.languages
10674 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10675 cx.notify();
10676
10677 return cx.spawn(async move |lsp_store, cx| {
10678 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10679 lsp_store
10680 .update(cx, |lsp_store, cx| {
10681 lsp_store
10682 .languages
10683 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10684 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10685 cx.notify();
10686 })
10687 .ok();
10688 });
10689 }
10690
10691 if server_state.is_some() {
10692 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10693 }
10694 Task::ready(())
10695 }
10696
10697 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10698 if let Some((client, project_id)) = self.upstream_client() {
10699 let request = client.request(proto::StopLanguageServers {
10700 project_id,
10701 buffer_ids: Vec::new(),
10702 also_servers: Vec::new(),
10703 all: true,
10704 });
10705 cx.background_spawn(request).detach_and_log_err(cx);
10706 } else {
10707 let Some(local) = self.as_local_mut() else {
10708 return;
10709 };
10710 let language_servers_to_stop = local
10711 .language_server_ids
10712 .values()
10713 .map(|state| state.id)
10714 .collect();
10715 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10716 let tasks = language_servers_to_stop
10717 .into_iter()
10718 .map(|server| self.stop_local_language_server(server, cx))
10719 .collect::<Vec<_>>();
10720 cx.background_spawn(async move {
10721 futures::future::join_all(tasks).await;
10722 })
10723 .detach();
10724 }
10725 }
10726
10727 pub fn restart_language_servers_for_buffers(
10728 &mut self,
10729 buffers: Vec<Entity<Buffer>>,
10730 only_restart_servers: HashSet<LanguageServerSelector>,
10731 cx: &mut Context<Self>,
10732 ) {
10733 if let Some((client, project_id)) = self.upstream_client() {
10734 let request = client.request(proto::RestartLanguageServers {
10735 project_id,
10736 buffer_ids: buffers
10737 .into_iter()
10738 .map(|b| b.read(cx).remote_id().to_proto())
10739 .collect(),
10740 only_servers: only_restart_servers
10741 .into_iter()
10742 .map(|selector| {
10743 let selector = match selector {
10744 LanguageServerSelector::Id(language_server_id) => {
10745 proto::language_server_selector::Selector::ServerId(
10746 language_server_id.to_proto(),
10747 )
10748 }
10749 LanguageServerSelector::Name(language_server_name) => {
10750 proto::language_server_selector::Selector::Name(
10751 language_server_name.to_string(),
10752 )
10753 }
10754 };
10755 proto::LanguageServerSelector {
10756 selector: Some(selector),
10757 }
10758 })
10759 .collect(),
10760 all: false,
10761 });
10762 cx.background_spawn(request).detach_and_log_err(cx);
10763 } else {
10764 let stop_task = if only_restart_servers.is_empty() {
10765 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10766 } else {
10767 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10768 };
10769 cx.spawn(async move |lsp_store, cx| {
10770 stop_task.await;
10771 lsp_store
10772 .update(cx, |lsp_store, cx| {
10773 for buffer in buffers {
10774 lsp_store.register_buffer_with_language_servers(
10775 &buffer,
10776 only_restart_servers.clone(),
10777 true,
10778 cx,
10779 );
10780 }
10781 })
10782 .ok()
10783 })
10784 .detach();
10785 }
10786 }
10787
10788 pub fn stop_language_servers_for_buffers(
10789 &mut self,
10790 buffers: Vec<Entity<Buffer>>,
10791 also_stop_servers: HashSet<LanguageServerSelector>,
10792 cx: &mut Context<Self>,
10793 ) -> Task<Result<()>> {
10794 if let Some((client, project_id)) = self.upstream_client() {
10795 let request = client.request(proto::StopLanguageServers {
10796 project_id,
10797 buffer_ids: buffers
10798 .into_iter()
10799 .map(|b| b.read(cx).remote_id().to_proto())
10800 .collect(),
10801 also_servers: also_stop_servers
10802 .into_iter()
10803 .map(|selector| {
10804 let selector = match selector {
10805 LanguageServerSelector::Id(language_server_id) => {
10806 proto::language_server_selector::Selector::ServerId(
10807 language_server_id.to_proto(),
10808 )
10809 }
10810 LanguageServerSelector::Name(language_server_name) => {
10811 proto::language_server_selector::Selector::Name(
10812 language_server_name.to_string(),
10813 )
10814 }
10815 };
10816 proto::LanguageServerSelector {
10817 selector: Some(selector),
10818 }
10819 })
10820 .collect(),
10821 all: false,
10822 });
10823 cx.background_spawn(async move {
10824 let _ = request.await?;
10825 Ok(())
10826 })
10827 } else {
10828 let task =
10829 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10830 cx.background_spawn(async move {
10831 task.await;
10832 Ok(())
10833 })
10834 }
10835 }
10836
10837 fn stop_local_language_servers_for_buffers(
10838 &mut self,
10839 buffers: &[Entity<Buffer>],
10840 also_stop_servers: HashSet<LanguageServerSelector>,
10841 cx: &mut Context<Self>,
10842 ) -> Task<()> {
10843 let Some(local) = self.as_local_mut() else {
10844 return Task::ready(());
10845 };
10846 let mut language_server_names_to_stop = BTreeSet::default();
10847 let mut language_servers_to_stop = also_stop_servers
10848 .into_iter()
10849 .flat_map(|selector| match selector {
10850 LanguageServerSelector::Id(id) => Some(id),
10851 LanguageServerSelector::Name(name) => {
10852 language_server_names_to_stop.insert(name);
10853 None
10854 }
10855 })
10856 .collect::<BTreeSet<_>>();
10857
10858 let mut covered_worktrees = HashSet::default();
10859 for buffer in buffers {
10860 buffer.update(cx, |buffer, cx| {
10861 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10862 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10863 && covered_worktrees.insert(worktree_id)
10864 {
10865 language_server_names_to_stop.retain(|name| {
10866 let old_ids_count = language_servers_to_stop.len();
10867 let all_language_servers_with_this_name = local
10868 .language_server_ids
10869 .iter()
10870 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10871 language_servers_to_stop.extend(all_language_servers_with_this_name);
10872 old_ids_count == language_servers_to_stop.len()
10873 });
10874 }
10875 });
10876 }
10877 for name in language_server_names_to_stop {
10878 language_servers_to_stop.extend(
10879 local
10880 .language_server_ids
10881 .iter()
10882 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10883 );
10884 }
10885
10886 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10887 let tasks = language_servers_to_stop
10888 .into_iter()
10889 .map(|server| self.stop_local_language_server(server, cx))
10890 .collect::<Vec<_>>();
10891
10892 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10893 }
10894
10895 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10896 let (worktree, relative_path) =
10897 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10898
10899 let project_path = ProjectPath {
10900 worktree_id: worktree.read(cx).id(),
10901 path: relative_path,
10902 };
10903
10904 Some(
10905 self.buffer_store()
10906 .read(cx)
10907 .get_by_path(&project_path)?
10908 .read(cx),
10909 )
10910 }
10911
10912 #[cfg(any(test, feature = "test-support"))]
10913 pub fn update_diagnostics(
10914 &mut self,
10915 server_id: LanguageServerId,
10916 diagnostics: lsp::PublishDiagnosticsParams,
10917 result_id: Option<String>,
10918 source_kind: DiagnosticSourceKind,
10919 disk_based_sources: &[String],
10920 cx: &mut Context<Self>,
10921 ) -> Result<()> {
10922 self.merge_lsp_diagnostics(
10923 source_kind,
10924 vec![DocumentDiagnosticsUpdate {
10925 diagnostics,
10926 result_id,
10927 server_id,
10928 disk_based_sources: Cow::Borrowed(disk_based_sources),
10929 }],
10930 |_, _, _| false,
10931 cx,
10932 )
10933 }
10934
10935 pub fn merge_lsp_diagnostics(
10936 &mut self,
10937 source_kind: DiagnosticSourceKind,
10938 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10939 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10940 cx: &mut Context<Self>,
10941 ) -> Result<()> {
10942 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10943 let updates = lsp_diagnostics
10944 .into_iter()
10945 .filter_map(|update| {
10946 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10947 Some(DocumentDiagnosticsUpdate {
10948 diagnostics: self.lsp_to_document_diagnostics(
10949 abs_path,
10950 source_kind,
10951 update.server_id,
10952 update.diagnostics,
10953 &update.disk_based_sources,
10954 ),
10955 result_id: update.result_id,
10956 server_id: update.server_id,
10957 disk_based_sources: update.disk_based_sources,
10958 })
10959 })
10960 .collect();
10961 self.merge_diagnostic_entries(updates, merge, cx)?;
10962 Ok(())
10963 }
10964
10965 fn lsp_to_document_diagnostics(
10966 &mut self,
10967 document_abs_path: PathBuf,
10968 source_kind: DiagnosticSourceKind,
10969 server_id: LanguageServerId,
10970 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10971 disk_based_sources: &[String],
10972 ) -> DocumentDiagnostics {
10973 let mut diagnostics = Vec::default();
10974 let mut primary_diagnostic_group_ids = HashMap::default();
10975 let mut sources_by_group_id = HashMap::default();
10976 let mut supporting_diagnostics = HashMap::default();
10977
10978 let adapter = self.language_server_adapter_for_id(server_id);
10979
10980 // Ensure that primary diagnostics are always the most severe
10981 lsp_diagnostics
10982 .diagnostics
10983 .sort_by_key(|item| item.severity);
10984
10985 for diagnostic in &lsp_diagnostics.diagnostics {
10986 let source = diagnostic.source.as_ref();
10987 let range = range_from_lsp(diagnostic.range);
10988 let is_supporting = diagnostic
10989 .related_information
10990 .as_ref()
10991 .is_some_and(|infos| {
10992 infos.iter().any(|info| {
10993 primary_diagnostic_group_ids.contains_key(&(
10994 source,
10995 diagnostic.code.clone(),
10996 range_from_lsp(info.location.range),
10997 ))
10998 })
10999 });
11000
11001 let is_unnecessary = diagnostic
11002 .tags
11003 .as_ref()
11004 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11005
11006 let underline = self
11007 .language_server_adapter_for_id(server_id)
11008 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11009
11010 if is_supporting {
11011 supporting_diagnostics.insert(
11012 (source, diagnostic.code.clone(), range),
11013 (diagnostic.severity, is_unnecessary),
11014 );
11015 } else {
11016 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11017 let is_disk_based =
11018 source.is_some_and(|source| disk_based_sources.contains(source));
11019
11020 sources_by_group_id.insert(group_id, source);
11021 primary_diagnostic_group_ids
11022 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11023
11024 diagnostics.push(DiagnosticEntry {
11025 range,
11026 diagnostic: Diagnostic {
11027 source: diagnostic.source.clone(),
11028 source_kind,
11029 code: diagnostic.code.clone(),
11030 code_description: diagnostic
11031 .code_description
11032 .as_ref()
11033 .and_then(|d| d.href.clone()),
11034 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11035 markdown: adapter.as_ref().and_then(|adapter| {
11036 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11037 }),
11038 message: diagnostic.message.trim().to_string(),
11039 group_id,
11040 is_primary: true,
11041 is_disk_based,
11042 is_unnecessary,
11043 underline,
11044 data: diagnostic.data.clone(),
11045 },
11046 });
11047 if let Some(infos) = &diagnostic.related_information {
11048 for info in infos {
11049 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11050 let range = range_from_lsp(info.location.range);
11051 diagnostics.push(DiagnosticEntry {
11052 range,
11053 diagnostic: Diagnostic {
11054 source: diagnostic.source.clone(),
11055 source_kind,
11056 code: diagnostic.code.clone(),
11057 code_description: diagnostic
11058 .code_description
11059 .as_ref()
11060 .and_then(|d| d.href.clone()),
11061 severity: DiagnosticSeverity::INFORMATION,
11062 markdown: adapter.as_ref().and_then(|adapter| {
11063 adapter.diagnostic_message_to_markdown(&info.message)
11064 }),
11065 message: info.message.trim().to_string(),
11066 group_id,
11067 is_primary: false,
11068 is_disk_based,
11069 is_unnecessary: false,
11070 underline,
11071 data: diagnostic.data.clone(),
11072 },
11073 });
11074 }
11075 }
11076 }
11077 }
11078 }
11079
11080 for entry in &mut diagnostics {
11081 let diagnostic = &mut entry.diagnostic;
11082 if !diagnostic.is_primary {
11083 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11084 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11085 source,
11086 diagnostic.code.clone(),
11087 entry.range.clone(),
11088 )) {
11089 if let Some(severity) = severity {
11090 diagnostic.severity = severity;
11091 }
11092 diagnostic.is_unnecessary = is_unnecessary;
11093 }
11094 }
11095 }
11096
11097 DocumentDiagnostics {
11098 diagnostics,
11099 document_abs_path,
11100 version: lsp_diagnostics.version,
11101 }
11102 }
11103
11104 fn insert_newly_running_language_server(
11105 &mut self,
11106 adapter: Arc<CachedLspAdapter>,
11107 language_server: Arc<LanguageServer>,
11108 server_id: LanguageServerId,
11109 key: LanguageServerSeed,
11110 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11111 cx: &mut Context<Self>,
11112 ) {
11113 let Some(local) = self.as_local_mut() else {
11114 return;
11115 };
11116 // If the language server for this key doesn't match the server id, don't store the
11117 // server. Which will cause it to be dropped, killing the process
11118 if local
11119 .language_server_ids
11120 .get(&key)
11121 .map(|state| state.id != server_id)
11122 .unwrap_or(false)
11123 {
11124 return;
11125 }
11126
11127 // Update language_servers collection with Running variant of LanguageServerState
11128 // indicating that the server is up and running and ready
11129 let workspace_folders = workspace_folders.lock().clone();
11130 language_server.set_workspace_folders(workspace_folders);
11131
11132 let workspace_diagnostics_refresh_tasks = language_server
11133 .capabilities()
11134 .diagnostic_provider
11135 .and_then(|provider| {
11136 local
11137 .language_server_dynamic_registrations
11138 .entry(server_id)
11139 .or_default()
11140 .diagnostics
11141 .entry(None)
11142 .or_insert(provider.clone());
11143 let workspace_refresher =
11144 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11145
11146 Some((None, workspace_refresher))
11147 })
11148 .into_iter()
11149 .collect();
11150 local.language_servers.insert(
11151 server_id,
11152 LanguageServerState::Running {
11153 workspace_diagnostics_refresh_tasks,
11154 adapter: adapter.clone(),
11155 server: language_server.clone(),
11156 simulate_disk_based_diagnostics_completion: None,
11157 },
11158 );
11159 local
11160 .languages
11161 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11162 if let Some(file_ops_caps) = language_server
11163 .capabilities()
11164 .workspace
11165 .as_ref()
11166 .and_then(|ws| ws.file_operations.as_ref())
11167 {
11168 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11169 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11170 if did_rename_caps.or(will_rename_caps).is_some() {
11171 let watcher = RenamePathsWatchedForServer::default()
11172 .with_did_rename_patterns(did_rename_caps)
11173 .with_will_rename_patterns(will_rename_caps);
11174 local
11175 .language_server_paths_watched_for_rename
11176 .insert(server_id, watcher);
11177 }
11178 }
11179
11180 self.language_server_statuses.insert(
11181 server_id,
11182 LanguageServerStatus {
11183 name: language_server.name(),
11184 pending_work: Default::default(),
11185 has_pending_diagnostic_updates: false,
11186 progress_tokens: Default::default(),
11187 worktree: Some(key.worktree_id),
11188 binary: Some(language_server.binary().clone()),
11189 configuration: Some(language_server.configuration().clone()),
11190 workspace_folders: language_server.workspace_folders(),
11191 },
11192 );
11193
11194 cx.emit(LspStoreEvent::LanguageServerAdded(
11195 server_id,
11196 language_server.name(),
11197 Some(key.worktree_id),
11198 ));
11199
11200 let server_capabilities = language_server.capabilities();
11201 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11202 downstream_client
11203 .send(proto::StartLanguageServer {
11204 project_id: *project_id,
11205 server: Some(proto::LanguageServer {
11206 id: server_id.to_proto(),
11207 name: language_server.name().to_string(),
11208 worktree_id: Some(key.worktree_id.to_proto()),
11209 }),
11210 capabilities: serde_json::to_string(&server_capabilities)
11211 .expect("serializing server LSP capabilities"),
11212 })
11213 .log_err();
11214 }
11215 self.lsp_server_capabilities
11216 .insert(server_id, server_capabilities);
11217
11218 // Tell the language server about every open buffer in the worktree that matches the language.
11219 // Also check for buffers in worktrees that reused this server
11220 let mut worktrees_using_server = vec![key.worktree_id];
11221 if let Some(local) = self.as_local() {
11222 // Find all worktrees that have this server in their language server tree
11223 for (worktree_id, servers) in &local.lsp_tree.instances {
11224 if *worktree_id != key.worktree_id {
11225 for server_map in servers.roots.values() {
11226 if server_map
11227 .values()
11228 .any(|(node, _)| node.id() == Some(server_id))
11229 {
11230 worktrees_using_server.push(*worktree_id);
11231 }
11232 }
11233 }
11234 }
11235 }
11236
11237 let mut buffer_paths_registered = Vec::new();
11238 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11239 let mut lsp_adapters = HashMap::default();
11240 for buffer_handle in buffer_store.buffers() {
11241 let buffer = buffer_handle.read(cx);
11242 let file = match File::from_dyn(buffer.file()) {
11243 Some(file) => file,
11244 None => continue,
11245 };
11246 let language = match buffer.language() {
11247 Some(language) => language,
11248 None => continue,
11249 };
11250
11251 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11252 || !lsp_adapters
11253 .entry(language.name())
11254 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11255 .iter()
11256 .any(|a| a.name == key.name)
11257 {
11258 continue;
11259 }
11260 // didOpen
11261 let file = match file.as_local() {
11262 Some(file) => file,
11263 None => continue,
11264 };
11265
11266 let local = self.as_local_mut().unwrap();
11267
11268 let buffer_id = buffer.remote_id();
11269 if local.registered_buffers.contains_key(&buffer_id) {
11270 let versions = local
11271 .buffer_snapshots
11272 .entry(buffer_id)
11273 .or_default()
11274 .entry(server_id)
11275 .and_modify(|_| {
11276 assert!(
11277 false,
11278 "There should not be an existing snapshot for a newly inserted buffer"
11279 )
11280 })
11281 .or_insert_with(|| {
11282 vec![LspBufferSnapshot {
11283 version: 0,
11284 snapshot: buffer.text_snapshot(),
11285 }]
11286 });
11287
11288 let snapshot = versions.last().unwrap();
11289 let version = snapshot.version;
11290 let initial_snapshot = &snapshot.snapshot;
11291 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11292 language_server.register_buffer(
11293 uri,
11294 adapter.language_id(&language.name()),
11295 version,
11296 initial_snapshot.text(),
11297 );
11298 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11299 local
11300 .buffers_opened_in_servers
11301 .entry(buffer_id)
11302 .or_default()
11303 .insert(server_id);
11304 }
11305 buffer_handle.update(cx, |buffer, cx| {
11306 buffer.set_completion_triggers(
11307 server_id,
11308 language_server
11309 .capabilities()
11310 .completion_provider
11311 .as_ref()
11312 .and_then(|provider| {
11313 provider
11314 .trigger_characters
11315 .as_ref()
11316 .map(|characters| characters.iter().cloned().collect())
11317 })
11318 .unwrap_or_default(),
11319 cx,
11320 )
11321 });
11322 }
11323 });
11324
11325 for (buffer_id, abs_path) in buffer_paths_registered {
11326 cx.emit(LspStoreEvent::LanguageServerUpdate {
11327 language_server_id: server_id,
11328 name: Some(adapter.name()),
11329 message: proto::update_language_server::Variant::RegisteredForBuffer(
11330 proto::RegisteredForBuffer {
11331 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11332 buffer_id: buffer_id.to_proto(),
11333 },
11334 ),
11335 });
11336 }
11337
11338 cx.notify();
11339 }
11340
11341 pub fn language_servers_running_disk_based_diagnostics(
11342 &self,
11343 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11344 self.language_server_statuses
11345 .iter()
11346 .filter_map(|(id, status)| {
11347 if status.has_pending_diagnostic_updates {
11348 Some(*id)
11349 } else {
11350 None
11351 }
11352 })
11353 }
11354
11355 pub(crate) fn cancel_language_server_work_for_buffers(
11356 &mut self,
11357 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11358 cx: &mut Context<Self>,
11359 ) {
11360 if let Some((client, project_id)) = self.upstream_client() {
11361 let request = client.request(proto::CancelLanguageServerWork {
11362 project_id,
11363 work: Some(proto::cancel_language_server_work::Work::Buffers(
11364 proto::cancel_language_server_work::Buffers {
11365 buffer_ids: buffers
11366 .into_iter()
11367 .map(|b| b.read(cx).remote_id().to_proto())
11368 .collect(),
11369 },
11370 )),
11371 });
11372 cx.background_spawn(request).detach_and_log_err(cx);
11373 } else if let Some(local) = self.as_local() {
11374 let servers = buffers
11375 .into_iter()
11376 .flat_map(|buffer| {
11377 buffer.update(cx, |buffer, cx| {
11378 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11379 })
11380 })
11381 .collect::<HashSet<_>>();
11382 for server_id in servers {
11383 self.cancel_language_server_work(server_id, None, cx);
11384 }
11385 }
11386 }
11387
11388 pub(crate) fn cancel_language_server_work(
11389 &mut self,
11390 server_id: LanguageServerId,
11391 token_to_cancel: Option<ProgressToken>,
11392 cx: &mut Context<Self>,
11393 ) {
11394 if let Some(local) = self.as_local() {
11395 let status = self.language_server_statuses.get(&server_id);
11396 let server = local.language_servers.get(&server_id);
11397 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11398 {
11399 for (token, progress) in &status.pending_work {
11400 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11401 && token != token_to_cancel
11402 {
11403 continue;
11404 }
11405 if progress.is_cancellable {
11406 server
11407 .notify::<lsp::notification::WorkDoneProgressCancel>(
11408 WorkDoneProgressCancelParams {
11409 token: token.to_lsp(),
11410 },
11411 )
11412 .ok();
11413 }
11414 }
11415 }
11416 } else if let Some((client, project_id)) = self.upstream_client() {
11417 let request = client.request(proto::CancelLanguageServerWork {
11418 project_id,
11419 work: Some(
11420 proto::cancel_language_server_work::Work::LanguageServerWork(
11421 proto::cancel_language_server_work::LanguageServerWork {
11422 language_server_id: server_id.to_proto(),
11423 token: token_to_cancel.map(|token| token.to_proto()),
11424 },
11425 ),
11426 ),
11427 });
11428 cx.background_spawn(request).detach_and_log_err(cx);
11429 }
11430 }
11431
11432 fn register_supplementary_language_server(
11433 &mut self,
11434 id: LanguageServerId,
11435 name: LanguageServerName,
11436 server: Arc<LanguageServer>,
11437 cx: &mut Context<Self>,
11438 ) {
11439 if let Some(local) = self.as_local_mut() {
11440 local
11441 .supplementary_language_servers
11442 .insert(id, (name.clone(), server));
11443 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11444 }
11445 }
11446
11447 fn unregister_supplementary_language_server(
11448 &mut self,
11449 id: LanguageServerId,
11450 cx: &mut Context<Self>,
11451 ) {
11452 if let Some(local) = self.as_local_mut() {
11453 local.supplementary_language_servers.remove(&id);
11454 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11455 }
11456 }
11457
11458 pub(crate) fn supplementary_language_servers(
11459 &self,
11460 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11461 self.as_local().into_iter().flat_map(|local| {
11462 local
11463 .supplementary_language_servers
11464 .iter()
11465 .map(|(id, (name, _))| (*id, name.clone()))
11466 })
11467 }
11468
11469 pub fn language_server_adapter_for_id(
11470 &self,
11471 id: LanguageServerId,
11472 ) -> Option<Arc<CachedLspAdapter>> {
11473 self.as_local()
11474 .and_then(|local| local.language_servers.get(&id))
11475 .and_then(|language_server_state| match language_server_state {
11476 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11477 _ => None,
11478 })
11479 }
11480
11481 pub(super) fn update_local_worktree_language_servers(
11482 &mut self,
11483 worktree_handle: &Entity<Worktree>,
11484 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11485 cx: &mut Context<Self>,
11486 ) {
11487 if changes.is_empty() {
11488 return;
11489 }
11490
11491 let Some(local) = self.as_local() else { return };
11492
11493 local.prettier_store.update(cx, |prettier_store, cx| {
11494 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11495 });
11496
11497 let worktree_id = worktree_handle.read(cx).id();
11498 let mut language_server_ids = local
11499 .language_server_ids
11500 .iter()
11501 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11502 .collect::<Vec<_>>();
11503 language_server_ids.sort();
11504 language_server_ids.dedup();
11505
11506 // let abs_path = worktree_handle.read(cx).abs_path();
11507 for server_id in &language_server_ids {
11508 if let Some(LanguageServerState::Running { server, .. }) =
11509 local.language_servers.get(server_id)
11510 && let Some(watched_paths) = local
11511 .language_server_watched_paths
11512 .get(server_id)
11513 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11514 {
11515 let params = lsp::DidChangeWatchedFilesParams {
11516 changes: changes
11517 .iter()
11518 .filter_map(|(path, _, change)| {
11519 if !watched_paths.is_match(path.as_std_path()) {
11520 return None;
11521 }
11522 let typ = match change {
11523 PathChange::Loaded => return None,
11524 PathChange::Added => lsp::FileChangeType::CREATED,
11525 PathChange::Removed => lsp::FileChangeType::DELETED,
11526 PathChange::Updated => lsp::FileChangeType::CHANGED,
11527 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11528 };
11529 let uri = lsp::Uri::from_file_path(
11530 worktree_handle.read(cx).absolutize(&path),
11531 )
11532 .ok()?;
11533 Some(lsp::FileEvent { uri, typ })
11534 })
11535 .collect(),
11536 };
11537 if !params.changes.is_empty() {
11538 server
11539 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11540 .ok();
11541 }
11542 }
11543 }
11544 for (path, _, _) in changes {
11545 if let Some(file_name) = path.file_name()
11546 && local.watched_manifest_filenames.contains(file_name)
11547 {
11548 self.request_workspace_config_refresh();
11549 break;
11550 }
11551 }
11552 }
11553
11554 pub fn wait_for_remote_buffer(
11555 &mut self,
11556 id: BufferId,
11557 cx: &mut Context<Self>,
11558 ) -> Task<Result<Entity<Buffer>>> {
11559 self.buffer_store.update(cx, |buffer_store, cx| {
11560 buffer_store.wait_for_remote_buffer(id, cx)
11561 })
11562 }
11563
11564 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11565 let mut result = proto::Symbol {
11566 language_server_name: symbol.language_server_name.0.to_string(),
11567 source_worktree_id: symbol.source_worktree_id.to_proto(),
11568 language_server_id: symbol.source_language_server_id.to_proto(),
11569 name: symbol.name.clone(),
11570 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11571 start: Some(proto::PointUtf16 {
11572 row: symbol.range.start.0.row,
11573 column: symbol.range.start.0.column,
11574 }),
11575 end: Some(proto::PointUtf16 {
11576 row: symbol.range.end.0.row,
11577 column: symbol.range.end.0.column,
11578 }),
11579 worktree_id: Default::default(),
11580 path: Default::default(),
11581 signature: Default::default(),
11582 };
11583 match &symbol.path {
11584 SymbolLocation::InProject(path) => {
11585 result.worktree_id = path.worktree_id.to_proto();
11586 result.path = path.path.to_proto();
11587 }
11588 SymbolLocation::OutsideProject {
11589 abs_path,
11590 signature,
11591 } => {
11592 result.path = abs_path.to_string_lossy().into_owned();
11593 result.signature = signature.to_vec();
11594 }
11595 }
11596 result
11597 }
11598
11599 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11600 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11601 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11602 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11603
11604 let path = if serialized_symbol.signature.is_empty() {
11605 SymbolLocation::InProject(ProjectPath {
11606 worktree_id,
11607 path: RelPath::from_proto(&serialized_symbol.path)
11608 .context("invalid symbol path")?,
11609 })
11610 } else {
11611 SymbolLocation::OutsideProject {
11612 abs_path: Path::new(&serialized_symbol.path).into(),
11613 signature: serialized_symbol
11614 .signature
11615 .try_into()
11616 .map_err(|_| anyhow!("invalid signature"))?,
11617 }
11618 };
11619
11620 let start = serialized_symbol.start.context("invalid start")?;
11621 let end = serialized_symbol.end.context("invalid end")?;
11622 Ok(CoreSymbol {
11623 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11624 source_worktree_id,
11625 source_language_server_id: LanguageServerId::from_proto(
11626 serialized_symbol.language_server_id,
11627 ),
11628 path,
11629 name: serialized_symbol.name,
11630 range: Unclipped(PointUtf16::new(start.row, start.column))
11631 ..Unclipped(PointUtf16::new(end.row, end.column)),
11632 kind,
11633 })
11634 }
11635
11636 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11637 let mut serialized_completion = proto::Completion {
11638 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11639 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11640 new_text: completion.new_text.clone(),
11641 ..proto::Completion::default()
11642 };
11643 match &completion.source {
11644 CompletionSource::Lsp {
11645 insert_range,
11646 server_id,
11647 lsp_completion,
11648 lsp_defaults,
11649 resolved,
11650 } => {
11651 let (old_insert_start, old_insert_end) = insert_range
11652 .as_ref()
11653 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11654 .unzip();
11655
11656 serialized_completion.old_insert_start = old_insert_start;
11657 serialized_completion.old_insert_end = old_insert_end;
11658 serialized_completion.source = proto::completion::Source::Lsp as i32;
11659 serialized_completion.server_id = server_id.0 as u64;
11660 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11661 serialized_completion.lsp_defaults = lsp_defaults
11662 .as_deref()
11663 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11664 serialized_completion.resolved = *resolved;
11665 }
11666 CompletionSource::BufferWord {
11667 word_range,
11668 resolved,
11669 } => {
11670 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11671 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11672 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11673 serialized_completion.resolved = *resolved;
11674 }
11675 CompletionSource::Custom => {
11676 serialized_completion.source = proto::completion::Source::Custom as i32;
11677 serialized_completion.resolved = true;
11678 }
11679 CompletionSource::Dap { sort_text } => {
11680 serialized_completion.source = proto::completion::Source::Dap as i32;
11681 serialized_completion.sort_text = Some(sort_text.clone());
11682 }
11683 }
11684
11685 serialized_completion
11686 }
11687
11688 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11689 let old_replace_start = completion
11690 .old_replace_start
11691 .and_then(deserialize_anchor)
11692 .context("invalid old start")?;
11693 let old_replace_end = completion
11694 .old_replace_end
11695 .and_then(deserialize_anchor)
11696 .context("invalid old end")?;
11697 let insert_range = {
11698 match completion.old_insert_start.zip(completion.old_insert_end) {
11699 Some((start, end)) => {
11700 let start = deserialize_anchor(start).context("invalid insert old start")?;
11701 let end = deserialize_anchor(end).context("invalid insert old end")?;
11702 Some(start..end)
11703 }
11704 None => None,
11705 }
11706 };
11707 Ok(CoreCompletion {
11708 replace_range: old_replace_start..old_replace_end,
11709 new_text: completion.new_text,
11710 source: match proto::completion::Source::from_i32(completion.source) {
11711 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11712 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11713 insert_range,
11714 server_id: LanguageServerId::from_proto(completion.server_id),
11715 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11716 lsp_defaults: completion
11717 .lsp_defaults
11718 .as_deref()
11719 .map(serde_json::from_slice)
11720 .transpose()?,
11721 resolved: completion.resolved,
11722 },
11723 Some(proto::completion::Source::BufferWord) => {
11724 let word_range = completion
11725 .buffer_word_start
11726 .and_then(deserialize_anchor)
11727 .context("invalid buffer word start")?
11728 ..completion
11729 .buffer_word_end
11730 .and_then(deserialize_anchor)
11731 .context("invalid buffer word end")?;
11732 CompletionSource::BufferWord {
11733 word_range,
11734 resolved: completion.resolved,
11735 }
11736 }
11737 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11738 sort_text: completion
11739 .sort_text
11740 .context("expected sort text to exist")?,
11741 },
11742 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11743 },
11744 })
11745 }
11746
11747 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11748 let (kind, lsp_action) = match &action.lsp_action {
11749 LspAction::Action(code_action) => (
11750 proto::code_action::Kind::Action as i32,
11751 serde_json::to_vec(code_action).unwrap(),
11752 ),
11753 LspAction::Command(command) => (
11754 proto::code_action::Kind::Command as i32,
11755 serde_json::to_vec(command).unwrap(),
11756 ),
11757 LspAction::CodeLens(code_lens) => (
11758 proto::code_action::Kind::CodeLens as i32,
11759 serde_json::to_vec(code_lens).unwrap(),
11760 ),
11761 };
11762
11763 proto::CodeAction {
11764 server_id: action.server_id.0 as u64,
11765 start: Some(serialize_anchor(&action.range.start)),
11766 end: Some(serialize_anchor(&action.range.end)),
11767 lsp_action,
11768 kind,
11769 resolved: action.resolved,
11770 }
11771 }
11772
11773 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11774 let start = action
11775 .start
11776 .and_then(deserialize_anchor)
11777 .context("invalid start")?;
11778 let end = action
11779 .end
11780 .and_then(deserialize_anchor)
11781 .context("invalid end")?;
11782 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11783 Some(proto::code_action::Kind::Action) => {
11784 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11785 }
11786 Some(proto::code_action::Kind::Command) => {
11787 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11788 }
11789 Some(proto::code_action::Kind::CodeLens) => {
11790 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11791 }
11792 None => anyhow::bail!("Unknown action kind {}", action.kind),
11793 };
11794 Ok(CodeAction {
11795 server_id: LanguageServerId(action.server_id as usize),
11796 range: start..end,
11797 resolved: action.resolved,
11798 lsp_action,
11799 })
11800 }
11801
11802 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11803 match &formatting_result {
11804 Ok(_) => self.last_formatting_failure = None,
11805 Err(error) => {
11806 let error_string = format!("{error:#}");
11807 log::error!("Formatting failed: {error_string}");
11808 self.last_formatting_failure
11809 .replace(error_string.lines().join(" "));
11810 }
11811 }
11812 }
11813
11814 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11815 self.lsp_server_capabilities.remove(&for_server);
11816 for lsp_data in self.lsp_data.values_mut() {
11817 lsp_data.remove_server_data(for_server);
11818 }
11819 if let Some(local) = self.as_local_mut() {
11820 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11821 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11822 buffer_servers.remove(&for_server);
11823 }
11824 }
11825 }
11826
11827 pub fn result_id(
11828 &self,
11829 server_id: LanguageServerId,
11830 buffer_id: BufferId,
11831 cx: &App,
11832 ) -> Option<String> {
11833 let abs_path = self
11834 .buffer_store
11835 .read(cx)
11836 .get(buffer_id)
11837 .and_then(|b| File::from_dyn(b.read(cx).file()))
11838 .map(|f| f.abs_path(cx))?;
11839 self.as_local()?
11840 .buffer_pull_diagnostics_result_ids
11841 .get(&server_id)?
11842 .get(&abs_path)?
11843 .clone()
11844 }
11845
11846 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11847 let Some(local) = self.as_local() else {
11848 return HashMap::default();
11849 };
11850 local
11851 .buffer_pull_diagnostics_result_ids
11852 .get(&server_id)
11853 .into_iter()
11854 .flatten()
11855 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11856 .collect()
11857 }
11858
11859 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11860 if let Some(LanguageServerState::Running {
11861 workspace_diagnostics_refresh_tasks,
11862 ..
11863 }) = self
11864 .as_local_mut()
11865 .and_then(|local| local.language_servers.get_mut(&server_id))
11866 {
11867 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11868 diagnostics.refresh_tx.try_send(()).ok();
11869 }
11870 }
11871 }
11872
11873 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11874 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11875 return;
11876 };
11877 let Some(local) = self.as_local_mut() else {
11878 return;
11879 };
11880
11881 for server_id in buffer.update(cx, |buffer, cx| {
11882 local.language_server_ids_for_buffer(buffer, cx)
11883 }) {
11884 if let Some(LanguageServerState::Running {
11885 workspace_diagnostics_refresh_tasks,
11886 ..
11887 }) = local.language_servers.get_mut(&server_id)
11888 {
11889 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11890 diagnostics.refresh_tx.try_send(()).ok();
11891 }
11892 }
11893 }
11894 }
11895
11896 fn apply_workspace_diagnostic_report(
11897 &mut self,
11898 server_id: LanguageServerId,
11899 report: lsp::WorkspaceDiagnosticReportResult,
11900 cx: &mut Context<Self>,
11901 ) {
11902 let workspace_diagnostics =
11903 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11904 let mut unchanged_buffers = HashSet::default();
11905 let mut changed_buffers = HashSet::default();
11906 let workspace_diagnostics_updates = workspace_diagnostics
11907 .into_iter()
11908 .filter_map(
11909 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11910 LspPullDiagnostics::Response {
11911 server_id,
11912 uri,
11913 diagnostics,
11914 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11915 LspPullDiagnostics::Default => None,
11916 },
11917 )
11918 .fold(
11919 HashMap::default(),
11920 |mut acc, (server_id, uri, diagnostics, version)| {
11921 let (result_id, diagnostics) = match diagnostics {
11922 PulledDiagnostics::Unchanged { result_id } => {
11923 unchanged_buffers.insert(uri.clone());
11924 (Some(result_id), Vec::new())
11925 }
11926 PulledDiagnostics::Changed {
11927 result_id,
11928 diagnostics,
11929 } => {
11930 changed_buffers.insert(uri.clone());
11931 (result_id, diagnostics)
11932 }
11933 };
11934 let disk_based_sources = Cow::Owned(
11935 self.language_server_adapter_for_id(server_id)
11936 .as_ref()
11937 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11938 .unwrap_or(&[])
11939 .to_vec(),
11940 );
11941 acc.entry(server_id)
11942 .or_insert_with(Vec::new)
11943 .push(DocumentDiagnosticsUpdate {
11944 server_id,
11945 diagnostics: lsp::PublishDiagnosticsParams {
11946 uri,
11947 diagnostics,
11948 version,
11949 },
11950 result_id,
11951 disk_based_sources,
11952 });
11953 acc
11954 },
11955 );
11956
11957 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11958 self.merge_lsp_diagnostics(
11959 DiagnosticSourceKind::Pulled,
11960 diagnostic_updates,
11961 |buffer, old_diagnostic, cx| {
11962 File::from_dyn(buffer.file())
11963 .and_then(|file| {
11964 let abs_path = file.as_local()?.abs_path(cx);
11965 lsp::Uri::from_file_path(abs_path).ok()
11966 })
11967 .is_none_or(|buffer_uri| {
11968 unchanged_buffers.contains(&buffer_uri)
11969 || match old_diagnostic.source_kind {
11970 DiagnosticSourceKind::Pulled => {
11971 !changed_buffers.contains(&buffer_uri)
11972 }
11973 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11974 true
11975 }
11976 }
11977 })
11978 },
11979 cx,
11980 )
11981 .log_err();
11982 }
11983 }
11984
11985 fn register_server_capabilities(
11986 &mut self,
11987 server_id: LanguageServerId,
11988 params: lsp::RegistrationParams,
11989 cx: &mut Context<Self>,
11990 ) -> anyhow::Result<()> {
11991 let server = self
11992 .language_server_for_id(server_id)
11993 .with_context(|| format!("no server {server_id} found"))?;
11994 for reg in params.registrations {
11995 match reg.method.as_str() {
11996 "workspace/didChangeWatchedFiles" => {
11997 if let Some(options) = reg.register_options {
11998 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11999 let caps = serde_json::from_value(options)?;
12000 local_lsp_store
12001 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12002 true
12003 } else {
12004 false
12005 };
12006 if notify {
12007 notify_server_capabilities_updated(&server, cx);
12008 }
12009 }
12010 }
12011 "workspace/didChangeConfiguration" => {
12012 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12013 }
12014 "workspace/didChangeWorkspaceFolders" => {
12015 // In this case register options is an empty object, we can ignore it
12016 let caps = lsp::WorkspaceFoldersServerCapabilities {
12017 supported: Some(true),
12018 change_notifications: Some(OneOf::Right(reg.id)),
12019 };
12020 server.update_capabilities(|capabilities| {
12021 capabilities
12022 .workspace
12023 .get_or_insert_default()
12024 .workspace_folders = Some(caps);
12025 });
12026 notify_server_capabilities_updated(&server, cx);
12027 }
12028 "workspace/symbol" => {
12029 let options = parse_register_capabilities(reg)?;
12030 server.update_capabilities(|capabilities| {
12031 capabilities.workspace_symbol_provider = Some(options);
12032 });
12033 notify_server_capabilities_updated(&server, cx);
12034 }
12035 "workspace/fileOperations" => {
12036 if let Some(options) = reg.register_options {
12037 let caps = serde_json::from_value(options)?;
12038 server.update_capabilities(|capabilities| {
12039 capabilities
12040 .workspace
12041 .get_or_insert_default()
12042 .file_operations = Some(caps);
12043 });
12044 notify_server_capabilities_updated(&server, cx);
12045 }
12046 }
12047 "workspace/executeCommand" => {
12048 if let Some(options) = reg.register_options {
12049 let options = serde_json::from_value(options)?;
12050 server.update_capabilities(|capabilities| {
12051 capabilities.execute_command_provider = Some(options);
12052 });
12053 notify_server_capabilities_updated(&server, cx);
12054 }
12055 }
12056 "textDocument/rangeFormatting" => {
12057 let options = parse_register_capabilities(reg)?;
12058 server.update_capabilities(|capabilities| {
12059 capabilities.document_range_formatting_provider = Some(options);
12060 });
12061 notify_server_capabilities_updated(&server, cx);
12062 }
12063 "textDocument/onTypeFormatting" => {
12064 if let Some(options) = reg
12065 .register_options
12066 .map(serde_json::from_value)
12067 .transpose()?
12068 {
12069 server.update_capabilities(|capabilities| {
12070 capabilities.document_on_type_formatting_provider = Some(options);
12071 });
12072 notify_server_capabilities_updated(&server, cx);
12073 }
12074 }
12075 "textDocument/formatting" => {
12076 let options = parse_register_capabilities(reg)?;
12077 server.update_capabilities(|capabilities| {
12078 capabilities.document_formatting_provider = Some(options);
12079 });
12080 notify_server_capabilities_updated(&server, cx);
12081 }
12082 "textDocument/rename" => {
12083 let options = parse_register_capabilities(reg)?;
12084 server.update_capabilities(|capabilities| {
12085 capabilities.rename_provider = Some(options);
12086 });
12087 notify_server_capabilities_updated(&server, cx);
12088 }
12089 "textDocument/inlayHint" => {
12090 let options = parse_register_capabilities(reg)?;
12091 server.update_capabilities(|capabilities| {
12092 capabilities.inlay_hint_provider = Some(options);
12093 });
12094 notify_server_capabilities_updated(&server, cx);
12095 }
12096 "textDocument/documentSymbol" => {
12097 let options = parse_register_capabilities(reg)?;
12098 server.update_capabilities(|capabilities| {
12099 capabilities.document_symbol_provider = Some(options);
12100 });
12101 notify_server_capabilities_updated(&server, cx);
12102 }
12103 "textDocument/codeAction" => {
12104 let options = parse_register_capabilities(reg)?;
12105 let provider = match options {
12106 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12107 OneOf::Right(caps) => caps,
12108 };
12109 server.update_capabilities(|capabilities| {
12110 capabilities.code_action_provider = Some(provider);
12111 });
12112 notify_server_capabilities_updated(&server, cx);
12113 }
12114 "textDocument/definition" => {
12115 let options = parse_register_capabilities(reg)?;
12116 server.update_capabilities(|capabilities| {
12117 capabilities.definition_provider = Some(options);
12118 });
12119 notify_server_capabilities_updated(&server, cx);
12120 }
12121 "textDocument/completion" => {
12122 if let Some(caps) = reg
12123 .register_options
12124 .map(serde_json::from_value::<CompletionOptions>)
12125 .transpose()?
12126 {
12127 server.update_capabilities(|capabilities| {
12128 capabilities.completion_provider = Some(caps.clone());
12129 });
12130
12131 if let Some(local) = self.as_local() {
12132 let mut buffers_with_language_server = Vec::new();
12133 for handle in self.buffer_store.read(cx).buffers() {
12134 let buffer_id = handle.read(cx).remote_id();
12135 if local
12136 .buffers_opened_in_servers
12137 .get(&buffer_id)
12138 .filter(|s| s.contains(&server_id))
12139 .is_some()
12140 {
12141 buffers_with_language_server.push(handle);
12142 }
12143 }
12144 let triggers = caps
12145 .trigger_characters
12146 .unwrap_or_default()
12147 .into_iter()
12148 .collect::<BTreeSet<_>>();
12149 for handle in buffers_with_language_server {
12150 let triggers = triggers.clone();
12151 let _ = handle.update(cx, move |buffer, cx| {
12152 buffer.set_completion_triggers(server_id, triggers, cx);
12153 });
12154 }
12155 }
12156 notify_server_capabilities_updated(&server, cx);
12157 }
12158 }
12159 "textDocument/hover" => {
12160 let options = parse_register_capabilities(reg)?;
12161 let provider = match options {
12162 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12163 OneOf::Right(caps) => caps,
12164 };
12165 server.update_capabilities(|capabilities| {
12166 capabilities.hover_provider = Some(provider);
12167 });
12168 notify_server_capabilities_updated(&server, cx);
12169 }
12170 "textDocument/signatureHelp" => {
12171 if let Some(caps) = reg
12172 .register_options
12173 .map(serde_json::from_value)
12174 .transpose()?
12175 {
12176 server.update_capabilities(|capabilities| {
12177 capabilities.signature_help_provider = Some(caps);
12178 });
12179 notify_server_capabilities_updated(&server, cx);
12180 }
12181 }
12182 "textDocument/didChange" => {
12183 if let Some(sync_kind) = reg
12184 .register_options
12185 .and_then(|opts| opts.get("syncKind").cloned())
12186 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12187 .transpose()?
12188 {
12189 server.update_capabilities(|capabilities| {
12190 let mut sync_options =
12191 Self::take_text_document_sync_options(capabilities);
12192 sync_options.change = Some(sync_kind);
12193 capabilities.text_document_sync =
12194 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12195 });
12196 notify_server_capabilities_updated(&server, cx);
12197 }
12198 }
12199 "textDocument/didSave" => {
12200 if let Some(include_text) = reg
12201 .register_options
12202 .map(|opts| {
12203 let transpose = opts
12204 .get("includeText")
12205 .cloned()
12206 .map(serde_json::from_value::<Option<bool>>)
12207 .transpose();
12208 match transpose {
12209 Ok(value) => Ok(value.flatten()),
12210 Err(e) => Err(e),
12211 }
12212 })
12213 .transpose()?
12214 {
12215 server.update_capabilities(|capabilities| {
12216 let mut sync_options =
12217 Self::take_text_document_sync_options(capabilities);
12218 sync_options.save =
12219 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12220 include_text,
12221 }));
12222 capabilities.text_document_sync =
12223 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12224 });
12225 notify_server_capabilities_updated(&server, cx);
12226 }
12227 }
12228 "textDocument/codeLens" => {
12229 if let Some(caps) = reg
12230 .register_options
12231 .map(serde_json::from_value)
12232 .transpose()?
12233 {
12234 server.update_capabilities(|capabilities| {
12235 capabilities.code_lens_provider = Some(caps);
12236 });
12237 notify_server_capabilities_updated(&server, cx);
12238 }
12239 }
12240 "textDocument/diagnostic" => {
12241 if let Some(caps) = reg
12242 .register_options
12243 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12244 .transpose()?
12245 {
12246 let local = self
12247 .as_local_mut()
12248 .context("Expected LSP Store to be local")?;
12249 let state = local
12250 .language_servers
12251 .get_mut(&server_id)
12252 .context("Could not obtain Language Servers state")?;
12253 local
12254 .language_server_dynamic_registrations
12255 .entry(server_id)
12256 .or_default()
12257 .diagnostics
12258 .insert(Some(reg.id.clone()), caps.clone());
12259
12260 if let LanguageServerState::Running {
12261 workspace_diagnostics_refresh_tasks,
12262 ..
12263 } = state
12264 && let Some(task) = lsp_workspace_diagnostics_refresh(
12265 Some(reg.id.clone()),
12266 caps.clone(),
12267 server.clone(),
12268 cx,
12269 )
12270 {
12271 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12272 }
12273
12274 let mut did_update_caps = false;
12275 server.update_capabilities(|capabilities| {
12276 if capabilities.diagnostic_provider.as_ref().is_none_or(
12277 |current_caps| {
12278 let supports_workspace_diagnostics =
12279 |capabilities: &DiagnosticServerCapabilities| {
12280 match capabilities {
12281 DiagnosticServerCapabilities::Options(
12282 diagnostic_options,
12283 ) => diagnostic_options.workspace_diagnostics,
12284 DiagnosticServerCapabilities::RegistrationOptions(
12285 diagnostic_registration_options,
12286 ) => {
12287 diagnostic_registration_options
12288 .diagnostic_options
12289 .workspace_diagnostics
12290 }
12291 }
12292 };
12293 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12294 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12295 // as it'll think that they're not supported.
12296 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12297 !supports_workspace_diagnostics(current_caps)
12298 & supports_workspace_diagnostics(&caps)
12299 },
12300 ) {
12301 did_update_caps = true;
12302 capabilities.diagnostic_provider = Some(caps);
12303 }
12304 });
12305 if did_update_caps {
12306 notify_server_capabilities_updated(&server, cx);
12307 }
12308 }
12309 }
12310 "textDocument/documentColor" => {
12311 let options = parse_register_capabilities(reg)?;
12312 let provider = match options {
12313 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12314 OneOf::Right(caps) => caps,
12315 };
12316 server.update_capabilities(|capabilities| {
12317 capabilities.color_provider = Some(provider);
12318 });
12319 notify_server_capabilities_updated(&server, cx);
12320 }
12321 _ => log::warn!("unhandled capability registration: {reg:?}"),
12322 }
12323 }
12324
12325 Ok(())
12326 }
12327
12328 fn unregister_server_capabilities(
12329 &mut self,
12330 server_id: LanguageServerId,
12331 params: lsp::UnregistrationParams,
12332 cx: &mut Context<Self>,
12333 ) -> anyhow::Result<()> {
12334 let server = self
12335 .language_server_for_id(server_id)
12336 .with_context(|| format!("no server {server_id} found"))?;
12337 for unreg in params.unregisterations.iter() {
12338 match unreg.method.as_str() {
12339 "workspace/didChangeWatchedFiles" => {
12340 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12341 local_lsp_store
12342 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12343 true
12344 } else {
12345 false
12346 };
12347 if notify {
12348 notify_server_capabilities_updated(&server, cx);
12349 }
12350 }
12351 "workspace/didChangeConfiguration" => {
12352 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12353 }
12354 "workspace/didChangeWorkspaceFolders" => {
12355 server.update_capabilities(|capabilities| {
12356 capabilities
12357 .workspace
12358 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12359 workspace_folders: None,
12360 file_operations: None,
12361 })
12362 .workspace_folders = None;
12363 });
12364 notify_server_capabilities_updated(&server, cx);
12365 }
12366 "workspace/symbol" => {
12367 server.update_capabilities(|capabilities| {
12368 capabilities.workspace_symbol_provider = None
12369 });
12370 notify_server_capabilities_updated(&server, cx);
12371 }
12372 "workspace/fileOperations" => {
12373 server.update_capabilities(|capabilities| {
12374 capabilities
12375 .workspace
12376 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12377 workspace_folders: None,
12378 file_operations: None,
12379 })
12380 .file_operations = None;
12381 });
12382 notify_server_capabilities_updated(&server, cx);
12383 }
12384 "workspace/executeCommand" => {
12385 server.update_capabilities(|capabilities| {
12386 capabilities.execute_command_provider = None;
12387 });
12388 notify_server_capabilities_updated(&server, cx);
12389 }
12390 "textDocument/rangeFormatting" => {
12391 server.update_capabilities(|capabilities| {
12392 capabilities.document_range_formatting_provider = None
12393 });
12394 notify_server_capabilities_updated(&server, cx);
12395 }
12396 "textDocument/onTypeFormatting" => {
12397 server.update_capabilities(|capabilities| {
12398 capabilities.document_on_type_formatting_provider = None;
12399 });
12400 notify_server_capabilities_updated(&server, cx);
12401 }
12402 "textDocument/formatting" => {
12403 server.update_capabilities(|capabilities| {
12404 capabilities.document_formatting_provider = None;
12405 });
12406 notify_server_capabilities_updated(&server, cx);
12407 }
12408 "textDocument/rename" => {
12409 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12410 notify_server_capabilities_updated(&server, cx);
12411 }
12412 "textDocument/codeAction" => {
12413 server.update_capabilities(|capabilities| {
12414 capabilities.code_action_provider = None;
12415 });
12416 notify_server_capabilities_updated(&server, cx);
12417 }
12418 "textDocument/definition" => {
12419 server.update_capabilities(|capabilities| {
12420 capabilities.definition_provider = None;
12421 });
12422 notify_server_capabilities_updated(&server, cx);
12423 }
12424 "textDocument/completion" => {
12425 server.update_capabilities(|capabilities| {
12426 capabilities.completion_provider = None;
12427 });
12428 notify_server_capabilities_updated(&server, cx);
12429 }
12430 "textDocument/hover" => {
12431 server.update_capabilities(|capabilities| {
12432 capabilities.hover_provider = None;
12433 });
12434 notify_server_capabilities_updated(&server, cx);
12435 }
12436 "textDocument/signatureHelp" => {
12437 server.update_capabilities(|capabilities| {
12438 capabilities.signature_help_provider = None;
12439 });
12440 notify_server_capabilities_updated(&server, cx);
12441 }
12442 "textDocument/didChange" => {
12443 server.update_capabilities(|capabilities| {
12444 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12445 sync_options.change = None;
12446 capabilities.text_document_sync =
12447 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12448 });
12449 notify_server_capabilities_updated(&server, cx);
12450 }
12451 "textDocument/didSave" => {
12452 server.update_capabilities(|capabilities| {
12453 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12454 sync_options.save = None;
12455 capabilities.text_document_sync =
12456 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12457 });
12458 notify_server_capabilities_updated(&server, cx);
12459 }
12460 "textDocument/codeLens" => {
12461 server.update_capabilities(|capabilities| {
12462 capabilities.code_lens_provider = None;
12463 });
12464 notify_server_capabilities_updated(&server, cx);
12465 }
12466 "textDocument/diagnostic" => {
12467 let local = self
12468 .as_local_mut()
12469 .context("Expected LSP Store to be local")?;
12470
12471 let state = local
12472 .language_servers
12473 .get_mut(&server_id)
12474 .context("Could not obtain Language Servers state")?;
12475 let options = local
12476 .language_server_dynamic_registrations
12477 .get_mut(&server_id)
12478 .with_context(|| {
12479 format!("Expected dynamic registration to exist for server {server_id}")
12480 })?.diagnostics
12481 .remove(&Some(unreg.id.clone()))
12482 .with_context(|| format!(
12483 "Attempted to unregister non-existent diagnostic registration with ID {}",
12484 unreg.id)
12485 )?;
12486
12487 let mut has_any_diagnostic_providers_still = true;
12488 if let Some(identifier) = diagnostic_identifier(&options)
12489 && let LanguageServerState::Running {
12490 workspace_diagnostics_refresh_tasks,
12491 ..
12492 } = state
12493 {
12494 workspace_diagnostics_refresh_tasks.remove(&identifier);
12495 has_any_diagnostic_providers_still =
12496 !workspace_diagnostics_refresh_tasks.is_empty();
12497 }
12498
12499 if !has_any_diagnostic_providers_still {
12500 server.update_capabilities(|capabilities| {
12501 debug_assert!(capabilities.diagnostic_provider.is_some());
12502 capabilities.diagnostic_provider = None;
12503 });
12504 }
12505
12506 notify_server_capabilities_updated(&server, cx);
12507 }
12508 "textDocument/documentColor" => {
12509 server.update_capabilities(|capabilities| {
12510 capabilities.color_provider = None;
12511 });
12512 notify_server_capabilities_updated(&server, cx);
12513 }
12514 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12515 }
12516 }
12517
12518 Ok(())
12519 }
12520
12521 async fn deduplicate_range_based_lsp_requests<T>(
12522 lsp_store: &Entity<Self>,
12523 server_id: Option<LanguageServerId>,
12524 lsp_request_id: LspRequestId,
12525 proto_request: &T::ProtoRequest,
12526 range: Range<Anchor>,
12527 cx: &mut AsyncApp,
12528 ) -> Result<()>
12529 where
12530 T: LspCommand,
12531 T::ProtoRequest: proto::LspRequestMessage,
12532 {
12533 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12534 let version = deserialize_version(proto_request.buffer_version());
12535 let buffer = lsp_store.update(cx, |this, cx| {
12536 this.buffer_store.read(cx).get_existing(buffer_id)
12537 })??;
12538 buffer
12539 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12540 .await?;
12541 lsp_store.update(cx, |lsp_store, cx| {
12542 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12543 let chunks_queried_for = lsp_data
12544 .inlay_hints
12545 .applicable_chunks(&[range])
12546 .collect::<Vec<_>>();
12547 match chunks_queried_for.as_slice() {
12548 &[chunk] => {
12549 let key = LspKey {
12550 request_type: TypeId::of::<T>(),
12551 server_queried: server_id,
12552 };
12553 let previous_request = lsp_data
12554 .chunk_lsp_requests
12555 .entry(key)
12556 .or_default()
12557 .insert(chunk, lsp_request_id);
12558 if let Some((previous_request, running_requests)) =
12559 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12560 {
12561 running_requests.remove(&previous_request);
12562 }
12563 }
12564 _ambiguous_chunks => {
12565 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12566 // there, a buffer version-based check will be performed and outdated requests discarded.
12567 }
12568 }
12569 anyhow::Ok(())
12570 })??;
12571
12572 Ok(())
12573 }
12574
12575 async fn query_lsp_locally<T>(
12576 lsp_store: Entity<Self>,
12577 for_server_id: Option<LanguageServerId>,
12578 sender_id: proto::PeerId,
12579 lsp_request_id: LspRequestId,
12580 proto_request: T::ProtoRequest,
12581 position: Option<Anchor>,
12582 cx: &mut AsyncApp,
12583 ) -> Result<()>
12584 where
12585 T: LspCommand + Clone,
12586 T::ProtoRequest: proto::LspRequestMessage,
12587 <T::ProtoRequest as proto::RequestMessage>::Response:
12588 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12589 {
12590 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12591 let version = deserialize_version(proto_request.buffer_version());
12592 let buffer = lsp_store.update(cx, |this, cx| {
12593 this.buffer_store.read(cx).get_existing(buffer_id)
12594 })??;
12595 buffer
12596 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12597 .await?;
12598 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12599 let request =
12600 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12601 let key = LspKey {
12602 request_type: TypeId::of::<T>(),
12603 server_queried: for_server_id,
12604 };
12605 lsp_store.update(cx, |lsp_store, cx| {
12606 let request_task = match for_server_id {
12607 Some(server_id) => {
12608 let server_task = lsp_store.request_lsp(
12609 buffer.clone(),
12610 LanguageServerToQuery::Other(server_id),
12611 request.clone(),
12612 cx,
12613 );
12614 cx.background_spawn(async move {
12615 let mut responses = Vec::new();
12616 match server_task.await {
12617 Ok(response) => responses.push((server_id, response)),
12618 // rust-analyzer likes to error with this when its still loading up
12619 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12620 Err(e) => log::error!(
12621 "Error handling response for request {request:?}: {e:#}"
12622 ),
12623 }
12624 responses
12625 })
12626 }
12627 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12628 };
12629 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12630 if T::ProtoRequest::stop_previous_requests() {
12631 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12632 lsp_requests.clear();
12633 }
12634 }
12635 lsp_data.lsp_requests.entry(key).or_default().insert(
12636 lsp_request_id,
12637 cx.spawn(async move |lsp_store, cx| {
12638 let response = request_task.await;
12639 lsp_store
12640 .update(cx, |lsp_store, cx| {
12641 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12642 {
12643 let response = response
12644 .into_iter()
12645 .map(|(server_id, response)| {
12646 (
12647 server_id.to_proto(),
12648 T::response_to_proto(
12649 response,
12650 lsp_store,
12651 sender_id,
12652 &buffer_version,
12653 cx,
12654 )
12655 .into(),
12656 )
12657 })
12658 .collect::<HashMap<_, _>>();
12659 match client.send_lsp_response::<T::ProtoRequest>(
12660 project_id,
12661 lsp_request_id,
12662 response,
12663 ) {
12664 Ok(()) => {}
12665 Err(e) => {
12666 log::error!("Failed to send LSP response: {e:#}",)
12667 }
12668 }
12669 }
12670 })
12671 .ok();
12672 }),
12673 );
12674 })?;
12675 Ok(())
12676 }
12677
12678 fn take_text_document_sync_options(
12679 capabilities: &mut lsp::ServerCapabilities,
12680 ) -> lsp::TextDocumentSyncOptions {
12681 match capabilities.text_document_sync.take() {
12682 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12683 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12684 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12685 sync_options.change = Some(sync_kind);
12686 sync_options
12687 }
12688 None => lsp::TextDocumentSyncOptions::default(),
12689 }
12690 }
12691
12692 #[cfg(any(test, feature = "test-support"))]
12693 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12694 Some(
12695 self.lsp_data
12696 .get_mut(&buffer_id)?
12697 .code_lens
12698 .take()?
12699 .update
12700 .take()?
12701 .1,
12702 )
12703 }
12704
12705 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12706 self.downstream_client.clone()
12707 }
12708
12709 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12710 self.worktree_store.clone()
12711 }
12712
12713 /// Gets what's stored in the LSP data for the given buffer.
12714 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12715 self.lsp_data.get_mut(&buffer_id)
12716 }
12717
12718 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12719 /// new [`BufferLspData`] will be created to replace the previous state.
12720 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12721 let (buffer_id, buffer_version) =
12722 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12723 let lsp_data = self
12724 .lsp_data
12725 .entry(buffer_id)
12726 .or_insert_with(|| BufferLspData::new(buffer, cx));
12727 if buffer_version.changed_since(&lsp_data.buffer_version) {
12728 *lsp_data = BufferLspData::new(buffer, cx);
12729 }
12730 lsp_data
12731 }
12732}
12733
12734// Registration with registerOptions as null, should fallback to true.
12735// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12736fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12737 reg: lsp::Registration,
12738) -> Result<OneOf<bool, T>> {
12739 Ok(match reg.register_options {
12740 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12741 None => OneOf::Left(true),
12742 })
12743}
12744
12745fn subscribe_to_binary_statuses(
12746 languages: &Arc<LanguageRegistry>,
12747 cx: &mut Context<'_, LspStore>,
12748) -> Task<()> {
12749 let mut server_statuses = languages.language_server_binary_statuses();
12750 cx.spawn(async move |lsp_store, cx| {
12751 while let Some((server_name, binary_status)) = server_statuses.next().await {
12752 if lsp_store
12753 .update(cx, |_, cx| {
12754 let mut message = None;
12755 let binary_status = match binary_status {
12756 BinaryStatus::None => proto::ServerBinaryStatus::None,
12757 BinaryStatus::CheckingForUpdate => {
12758 proto::ServerBinaryStatus::CheckingForUpdate
12759 }
12760 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12761 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12762 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12763 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12764 BinaryStatus::Failed { error } => {
12765 message = Some(error);
12766 proto::ServerBinaryStatus::Failed
12767 }
12768 };
12769 cx.emit(LspStoreEvent::LanguageServerUpdate {
12770 // Binary updates are about the binary that might not have any language server id at that point.
12771 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12772 language_server_id: LanguageServerId(0),
12773 name: Some(server_name),
12774 message: proto::update_language_server::Variant::StatusUpdate(
12775 proto::StatusUpdate {
12776 message,
12777 status: Some(proto::status_update::Status::Binary(
12778 binary_status as i32,
12779 )),
12780 },
12781 ),
12782 });
12783 })
12784 .is_err()
12785 {
12786 break;
12787 }
12788 }
12789 })
12790}
12791
12792fn lsp_workspace_diagnostics_refresh(
12793 registration_id: Option<String>,
12794 options: DiagnosticServerCapabilities,
12795 server: Arc<LanguageServer>,
12796 cx: &mut Context<'_, LspStore>,
12797) -> Option<WorkspaceRefreshTask> {
12798 let identifier = diagnostic_identifier(&options)?;
12799
12800 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12801 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12802 refresh_tx.try_send(()).ok();
12803
12804 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12805 let mut attempts = 0;
12806 let max_attempts = 50;
12807 let mut requests = 0;
12808
12809 loop {
12810 let Some(()) = refresh_rx.recv().await else {
12811 return;
12812 };
12813
12814 'request: loop {
12815 requests += 1;
12816 if attempts > max_attempts {
12817 log::error!(
12818 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12819 );
12820 return;
12821 }
12822 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12823 cx.background_executor()
12824 .timer(Duration::from_millis(backoff_millis))
12825 .await;
12826 attempts += 1;
12827
12828 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12829 lsp_store
12830 .all_result_ids(server.server_id())
12831 .into_iter()
12832 .filter_map(|(abs_path, result_id)| {
12833 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12834 Some(lsp::PreviousResultId {
12835 uri,
12836 value: result_id,
12837 })
12838 })
12839 .collect()
12840 }) else {
12841 return;
12842 };
12843
12844 let token = if let Some(identifier) = ®istration_id {
12845 format!(
12846 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12847 server.server_id(),
12848 )
12849 } else {
12850 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12851 };
12852
12853 progress_rx.try_recv().ok();
12854 let timer =
12855 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12856 let progress = pin!(progress_rx.recv().fuse());
12857 let response_result = server
12858 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12859 lsp::WorkspaceDiagnosticParams {
12860 previous_result_ids,
12861 identifier: identifier.clone(),
12862 work_done_progress_params: Default::default(),
12863 partial_result_params: lsp::PartialResultParams {
12864 partial_result_token: Some(lsp::ProgressToken::String(token)),
12865 },
12866 },
12867 select(timer, progress).then(|either| match either {
12868 Either::Left((message, ..)) => ready(message).left_future(),
12869 Either::Right(..) => pending::<String>().right_future(),
12870 }),
12871 )
12872 .await;
12873
12874 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12875 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12876 match response_result {
12877 ConnectionResult::Timeout => {
12878 log::error!("Timeout during workspace diagnostics pull");
12879 continue 'request;
12880 }
12881 ConnectionResult::ConnectionReset => {
12882 log::error!("Server closed a workspace diagnostics pull request");
12883 continue 'request;
12884 }
12885 ConnectionResult::Result(Err(e)) => {
12886 log::error!("Error during workspace diagnostics pull: {e:#}");
12887 break 'request;
12888 }
12889 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12890 attempts = 0;
12891 if lsp_store
12892 .update(cx, |lsp_store, cx| {
12893 lsp_store.apply_workspace_diagnostic_report(
12894 server.server_id(),
12895 pulled_diagnostics,
12896 cx,
12897 )
12898 })
12899 .is_err()
12900 {
12901 return;
12902 }
12903 break 'request;
12904 }
12905 }
12906 }
12907 }
12908 });
12909
12910 Some(WorkspaceRefreshTask {
12911 refresh_tx,
12912 progress_tx,
12913 task: workspace_query_language_server,
12914 })
12915}
12916
12917fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12918 match &options {
12919 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12920 if !diagnostic_options.workspace_diagnostics {
12921 return None;
12922 }
12923 Some(diagnostic_options.identifier.clone())
12924 }
12925 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12926 let diagnostic_options = ®istration_options.diagnostic_options;
12927 if !diagnostic_options.workspace_diagnostics {
12928 return None;
12929 }
12930 Some(diagnostic_options.identifier.clone())
12931 }
12932 }
12933}
12934
12935fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12936 let CompletionSource::BufferWord {
12937 word_range,
12938 resolved,
12939 } = &mut completion.source
12940 else {
12941 return;
12942 };
12943 if *resolved {
12944 return;
12945 }
12946
12947 if completion.new_text
12948 != snapshot
12949 .text_for_range(word_range.clone())
12950 .collect::<String>()
12951 {
12952 return;
12953 }
12954
12955 let mut offset = 0;
12956 for chunk in snapshot.chunks(word_range.clone(), true) {
12957 let end_offset = offset + chunk.text.len();
12958 if let Some(highlight_id) = chunk.syntax_highlight_id {
12959 completion
12960 .label
12961 .runs
12962 .push((offset..end_offset, highlight_id));
12963 }
12964 offset = end_offset;
12965 }
12966 *resolved = true;
12967}
12968
12969impl EventEmitter<LspStoreEvent> for LspStore {}
12970
12971fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12972 hover
12973 .contents
12974 .retain(|hover_block| !hover_block.text.trim().is_empty());
12975 if hover.contents.is_empty() {
12976 None
12977 } else {
12978 Some(hover)
12979 }
12980}
12981
12982async fn populate_labels_for_completions(
12983 new_completions: Vec<CoreCompletion>,
12984 language: Option<Arc<Language>>,
12985 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12986) -> Vec<Completion> {
12987 let lsp_completions = new_completions
12988 .iter()
12989 .filter_map(|new_completion| {
12990 new_completion
12991 .source
12992 .lsp_completion(true)
12993 .map(|lsp_completion| lsp_completion.into_owned())
12994 })
12995 .collect::<Vec<_>>();
12996
12997 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12998 lsp_adapter
12999 .labels_for_completions(&lsp_completions, language)
13000 .await
13001 .log_err()
13002 .unwrap_or_default()
13003 } else {
13004 Vec::new()
13005 }
13006 .into_iter()
13007 .fuse();
13008
13009 let mut completions = Vec::new();
13010 for completion in new_completions {
13011 match completion.source.lsp_completion(true) {
13012 Some(lsp_completion) => {
13013 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13014
13015 let mut label = labels.next().flatten().unwrap_or_else(|| {
13016 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13017 });
13018 ensure_uniform_list_compatible_label(&mut label);
13019 completions.push(Completion {
13020 label,
13021 documentation,
13022 replace_range: completion.replace_range,
13023 new_text: completion.new_text,
13024 insert_text_mode: lsp_completion.insert_text_mode,
13025 source: completion.source,
13026 icon_path: None,
13027 confirm: None,
13028 match_start: None,
13029 snippet_deduplication_key: None,
13030 });
13031 }
13032 None => {
13033 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13034 ensure_uniform_list_compatible_label(&mut label);
13035 completions.push(Completion {
13036 label,
13037 documentation: None,
13038 replace_range: completion.replace_range,
13039 new_text: completion.new_text,
13040 source: completion.source,
13041 insert_text_mode: None,
13042 icon_path: None,
13043 confirm: None,
13044 match_start: None,
13045 snippet_deduplication_key: None,
13046 });
13047 }
13048 }
13049 }
13050 completions
13051}
13052
13053#[derive(Debug)]
13054pub enum LanguageServerToQuery {
13055 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13056 FirstCapable,
13057 /// Query a specific language server.
13058 Other(LanguageServerId),
13059}
13060
13061#[derive(Default)]
13062struct RenamePathsWatchedForServer {
13063 did_rename: Vec<RenameActionPredicate>,
13064 will_rename: Vec<RenameActionPredicate>,
13065}
13066
13067impl RenamePathsWatchedForServer {
13068 fn with_did_rename_patterns(
13069 mut self,
13070 did_rename: Option<&FileOperationRegistrationOptions>,
13071 ) -> Self {
13072 if let Some(did_rename) = did_rename {
13073 self.did_rename = did_rename
13074 .filters
13075 .iter()
13076 .filter_map(|filter| filter.try_into().log_err())
13077 .collect();
13078 }
13079 self
13080 }
13081 fn with_will_rename_patterns(
13082 mut self,
13083 will_rename: Option<&FileOperationRegistrationOptions>,
13084 ) -> Self {
13085 if let Some(will_rename) = will_rename {
13086 self.will_rename = will_rename
13087 .filters
13088 .iter()
13089 .filter_map(|filter| filter.try_into().log_err())
13090 .collect();
13091 }
13092 self
13093 }
13094
13095 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13096 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13097 }
13098 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13099 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13100 }
13101}
13102
13103impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13104 type Error = globset::Error;
13105 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13106 Ok(Self {
13107 kind: ops.pattern.matches.clone(),
13108 glob: GlobBuilder::new(&ops.pattern.glob)
13109 .case_insensitive(
13110 ops.pattern
13111 .options
13112 .as_ref()
13113 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13114 )
13115 .build()?
13116 .compile_matcher(),
13117 })
13118 }
13119}
13120struct RenameActionPredicate {
13121 glob: GlobMatcher,
13122 kind: Option<FileOperationPatternKind>,
13123}
13124
13125impl RenameActionPredicate {
13126 // Returns true if language server should be notified
13127 fn eval(&self, path: &str, is_dir: bool) -> bool {
13128 self.kind.as_ref().is_none_or(|kind| {
13129 let expected_kind = if is_dir {
13130 FileOperationPatternKind::Folder
13131 } else {
13132 FileOperationPatternKind::File
13133 };
13134 kind == &expected_kind
13135 }) && self.glob.is_match(path)
13136 }
13137}
13138
13139#[derive(Default)]
13140struct LanguageServerWatchedPaths {
13141 worktree_paths: HashMap<WorktreeId, GlobSet>,
13142 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13143}
13144
13145#[derive(Default)]
13146struct LanguageServerWatchedPathsBuilder {
13147 worktree_paths: HashMap<WorktreeId, GlobSet>,
13148 abs_paths: HashMap<Arc<Path>, GlobSet>,
13149}
13150
13151impl LanguageServerWatchedPathsBuilder {
13152 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13153 self.worktree_paths.insert(worktree_id, glob_set);
13154 }
13155 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13156 self.abs_paths.insert(path, glob_set);
13157 }
13158 fn build(
13159 self,
13160 fs: Arc<dyn Fs>,
13161 language_server_id: LanguageServerId,
13162 cx: &mut Context<LspStore>,
13163 ) -> LanguageServerWatchedPaths {
13164 let lsp_store = cx.weak_entity();
13165
13166 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13167 let abs_paths = self
13168 .abs_paths
13169 .into_iter()
13170 .map(|(abs_path, globset)| {
13171 let task = cx.spawn({
13172 let abs_path = abs_path.clone();
13173 let fs = fs.clone();
13174
13175 let lsp_store = lsp_store.clone();
13176 async move |_, cx| {
13177 maybe!(async move {
13178 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13179 while let Some(update) = push_updates.0.next().await {
13180 let action = lsp_store
13181 .update(cx, |this, _| {
13182 let Some(local) = this.as_local() else {
13183 return ControlFlow::Break(());
13184 };
13185 let Some(watcher) = local
13186 .language_server_watched_paths
13187 .get(&language_server_id)
13188 else {
13189 return ControlFlow::Break(());
13190 };
13191 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13192 "Watched abs path is not registered with a watcher",
13193 );
13194 let matching_entries = update
13195 .into_iter()
13196 .filter(|event| globs.is_match(&event.path))
13197 .collect::<Vec<_>>();
13198 this.lsp_notify_abs_paths_changed(
13199 language_server_id,
13200 matching_entries,
13201 );
13202 ControlFlow::Continue(())
13203 })
13204 .ok()?;
13205
13206 if action.is_break() {
13207 break;
13208 }
13209 }
13210 Some(())
13211 })
13212 .await;
13213 }
13214 });
13215 (abs_path, (globset, task))
13216 })
13217 .collect();
13218 LanguageServerWatchedPaths {
13219 worktree_paths: self.worktree_paths,
13220 abs_paths,
13221 }
13222 }
13223}
13224
13225struct LspBufferSnapshot {
13226 version: i32,
13227 snapshot: TextBufferSnapshot,
13228}
13229
13230/// A prompt requested by LSP server.
13231#[derive(Clone, Debug)]
13232pub struct LanguageServerPromptRequest {
13233 pub level: PromptLevel,
13234 pub message: String,
13235 pub actions: Vec<MessageActionItem>,
13236 pub lsp_name: String,
13237 pub(crate) response_channel: Sender<MessageActionItem>,
13238}
13239
13240impl LanguageServerPromptRequest {
13241 pub async fn respond(self, index: usize) -> Option<()> {
13242 if let Some(response) = self.actions.into_iter().nth(index) {
13243 self.response_channel.send(response).await.ok()
13244 } else {
13245 None
13246 }
13247 }
13248}
13249impl PartialEq for LanguageServerPromptRequest {
13250 fn eq(&self, other: &Self) -> bool {
13251 self.message == other.message && self.actions == other.actions
13252 }
13253}
13254
13255#[derive(Clone, Debug, PartialEq)]
13256pub enum LanguageServerLogType {
13257 Log(MessageType),
13258 Trace { verbose_info: Option<String> },
13259 Rpc { received: bool },
13260}
13261
13262impl LanguageServerLogType {
13263 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13264 match self {
13265 Self::Log(log_type) => {
13266 use proto::log_message::LogLevel;
13267 let level = match *log_type {
13268 MessageType::ERROR => LogLevel::Error,
13269 MessageType::WARNING => LogLevel::Warning,
13270 MessageType::INFO => LogLevel::Info,
13271 MessageType::LOG => LogLevel::Log,
13272 other => {
13273 log::warn!("Unknown lsp log message type: {other:?}");
13274 LogLevel::Log
13275 }
13276 };
13277 proto::language_server_log::LogType::Log(proto::LogMessage {
13278 level: level as i32,
13279 })
13280 }
13281 Self::Trace { verbose_info } => {
13282 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13283 verbose_info: verbose_info.to_owned(),
13284 })
13285 }
13286 Self::Rpc { received } => {
13287 let kind = if *received {
13288 proto::rpc_message::Kind::Received
13289 } else {
13290 proto::rpc_message::Kind::Sent
13291 };
13292 let kind = kind as i32;
13293 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13294 }
13295 }
13296 }
13297
13298 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13299 use proto::log_message::LogLevel;
13300 use proto::rpc_message;
13301 match log_type {
13302 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13303 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13304 LogLevel::Error => MessageType::ERROR,
13305 LogLevel::Warning => MessageType::WARNING,
13306 LogLevel::Info => MessageType::INFO,
13307 LogLevel::Log => MessageType::LOG,
13308 },
13309 ),
13310 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13311 verbose_info: trace_message.verbose_info,
13312 },
13313 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13314 received: match rpc_message::Kind::from_i32(message.kind)
13315 .unwrap_or(rpc_message::Kind::Received)
13316 {
13317 rpc_message::Kind::Received => true,
13318 rpc_message::Kind::Sent => false,
13319 },
13320 },
13321 }
13322 }
13323}
13324
13325pub struct WorkspaceRefreshTask {
13326 refresh_tx: mpsc::Sender<()>,
13327 progress_tx: mpsc::Sender<()>,
13328 #[allow(dead_code)]
13329 task: Task<()>,
13330}
13331
13332pub enum LanguageServerState {
13333 Starting {
13334 startup: Task<Option<Arc<LanguageServer>>>,
13335 /// List of language servers that will be added to the workspace once it's initialization completes.
13336 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13337 },
13338
13339 Running {
13340 adapter: Arc<CachedLspAdapter>,
13341 server: Arc<LanguageServer>,
13342 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13343 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13344 },
13345}
13346
13347impl LanguageServerState {
13348 fn add_workspace_folder(&self, uri: Uri) {
13349 match self {
13350 LanguageServerState::Starting {
13351 pending_workspace_folders,
13352 ..
13353 } => {
13354 pending_workspace_folders.lock().insert(uri);
13355 }
13356 LanguageServerState::Running { server, .. } => {
13357 server.add_workspace_folder(uri);
13358 }
13359 }
13360 }
13361 fn _remove_workspace_folder(&self, uri: Uri) {
13362 match self {
13363 LanguageServerState::Starting {
13364 pending_workspace_folders,
13365 ..
13366 } => {
13367 pending_workspace_folders.lock().remove(&uri);
13368 }
13369 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13370 }
13371 }
13372}
13373
13374impl std::fmt::Debug for LanguageServerState {
13375 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13376 match self {
13377 LanguageServerState::Starting { .. } => {
13378 f.debug_struct("LanguageServerState::Starting").finish()
13379 }
13380 LanguageServerState::Running { .. } => {
13381 f.debug_struct("LanguageServerState::Running").finish()
13382 }
13383 }
13384 }
13385}
13386
13387#[derive(Clone, Debug, Serialize)]
13388pub struct LanguageServerProgress {
13389 pub is_disk_based_diagnostics_progress: bool,
13390 pub is_cancellable: bool,
13391 pub title: Option<String>,
13392 pub message: Option<String>,
13393 pub percentage: Option<usize>,
13394 #[serde(skip_serializing)]
13395 pub last_update_at: Instant,
13396}
13397
13398#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13399pub struct DiagnosticSummary {
13400 pub error_count: usize,
13401 pub warning_count: usize,
13402}
13403
13404impl DiagnosticSummary {
13405 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13406 let mut this = Self {
13407 error_count: 0,
13408 warning_count: 0,
13409 };
13410
13411 for entry in diagnostics {
13412 if entry.diagnostic.is_primary {
13413 match entry.diagnostic.severity {
13414 DiagnosticSeverity::ERROR => this.error_count += 1,
13415 DiagnosticSeverity::WARNING => this.warning_count += 1,
13416 _ => {}
13417 }
13418 }
13419 }
13420
13421 this
13422 }
13423
13424 pub fn is_empty(&self) -> bool {
13425 self.error_count == 0 && self.warning_count == 0
13426 }
13427
13428 pub fn to_proto(
13429 self,
13430 language_server_id: LanguageServerId,
13431 path: &RelPath,
13432 ) -> proto::DiagnosticSummary {
13433 proto::DiagnosticSummary {
13434 path: path.to_proto(),
13435 language_server_id: language_server_id.0 as u64,
13436 error_count: self.error_count as u32,
13437 warning_count: self.warning_count as u32,
13438 }
13439 }
13440}
13441
13442#[derive(Clone, Debug)]
13443pub enum CompletionDocumentation {
13444 /// There is no documentation for this completion.
13445 Undocumented,
13446 /// A single line of documentation.
13447 SingleLine(SharedString),
13448 /// Multiple lines of plain text documentation.
13449 MultiLinePlainText(SharedString),
13450 /// Markdown documentation.
13451 MultiLineMarkdown(SharedString),
13452 /// Both single line and multiple lines of plain text documentation.
13453 SingleLineAndMultiLinePlainText {
13454 single_line: SharedString,
13455 plain_text: Option<SharedString>,
13456 },
13457}
13458
13459impl CompletionDocumentation {
13460 #[cfg(any(test, feature = "test-support"))]
13461 pub fn text(&self) -> SharedString {
13462 match self {
13463 CompletionDocumentation::Undocumented => "".into(),
13464 CompletionDocumentation::SingleLine(s) => s.clone(),
13465 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13466 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13467 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13468 single_line.clone()
13469 }
13470 }
13471 }
13472}
13473
13474impl From<lsp::Documentation> for CompletionDocumentation {
13475 fn from(docs: lsp::Documentation) -> Self {
13476 match docs {
13477 lsp::Documentation::String(text) => {
13478 if text.lines().count() <= 1 {
13479 CompletionDocumentation::SingleLine(text.into())
13480 } else {
13481 CompletionDocumentation::MultiLinePlainText(text.into())
13482 }
13483 }
13484
13485 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13486 lsp::MarkupKind::PlainText => {
13487 if value.lines().count() <= 1 {
13488 CompletionDocumentation::SingleLine(value.into())
13489 } else {
13490 CompletionDocumentation::MultiLinePlainText(value.into())
13491 }
13492 }
13493
13494 lsp::MarkupKind::Markdown => {
13495 CompletionDocumentation::MultiLineMarkdown(value.into())
13496 }
13497 },
13498 }
13499 }
13500}
13501
13502pub enum ResolvedHint {
13503 Resolved(InlayHint),
13504 Resolving(Shared<Task<()>>),
13505}
13506
13507fn glob_literal_prefix(glob: &Path) -> PathBuf {
13508 glob.components()
13509 .take_while(|component| match component {
13510 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13511 _ => true,
13512 })
13513 .collect()
13514}
13515
13516pub struct SshLspAdapter {
13517 name: LanguageServerName,
13518 binary: LanguageServerBinary,
13519 initialization_options: Option<String>,
13520 code_action_kinds: Option<Vec<CodeActionKind>>,
13521}
13522
13523impl SshLspAdapter {
13524 pub fn new(
13525 name: LanguageServerName,
13526 binary: LanguageServerBinary,
13527 initialization_options: Option<String>,
13528 code_action_kinds: Option<String>,
13529 ) -> Self {
13530 Self {
13531 name,
13532 binary,
13533 initialization_options,
13534 code_action_kinds: code_action_kinds
13535 .as_ref()
13536 .and_then(|c| serde_json::from_str(c).ok()),
13537 }
13538 }
13539}
13540
13541impl LspInstaller for SshLspAdapter {
13542 type BinaryVersion = ();
13543 async fn check_if_user_installed(
13544 &self,
13545 _: &dyn LspAdapterDelegate,
13546 _: Option<Toolchain>,
13547 _: &AsyncApp,
13548 ) -> Option<LanguageServerBinary> {
13549 Some(self.binary.clone())
13550 }
13551
13552 async fn cached_server_binary(
13553 &self,
13554 _: PathBuf,
13555 _: &dyn LspAdapterDelegate,
13556 ) -> Option<LanguageServerBinary> {
13557 None
13558 }
13559
13560 async fn fetch_latest_server_version(
13561 &self,
13562 _: &dyn LspAdapterDelegate,
13563 _: bool,
13564 _: &mut AsyncApp,
13565 ) -> Result<()> {
13566 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13567 }
13568
13569 async fn fetch_server_binary(
13570 &self,
13571 _: (),
13572 _: PathBuf,
13573 _: &dyn LspAdapterDelegate,
13574 ) -> Result<LanguageServerBinary> {
13575 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13576 }
13577}
13578
13579#[async_trait(?Send)]
13580impl LspAdapter for SshLspAdapter {
13581 fn name(&self) -> LanguageServerName {
13582 self.name.clone()
13583 }
13584
13585 async fn initialization_options(
13586 self: Arc<Self>,
13587 _: &Arc<dyn LspAdapterDelegate>,
13588 ) -> Result<Option<serde_json::Value>> {
13589 let Some(options) = &self.initialization_options else {
13590 return Ok(None);
13591 };
13592 let result = serde_json::from_str(options)?;
13593 Ok(result)
13594 }
13595
13596 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13597 self.code_action_kinds.clone()
13598 }
13599}
13600
13601pub fn language_server_settings<'a>(
13602 delegate: &'a dyn LspAdapterDelegate,
13603 language: &LanguageServerName,
13604 cx: &'a App,
13605) -> Option<&'a LspSettings> {
13606 language_server_settings_for(
13607 SettingsLocation {
13608 worktree_id: delegate.worktree_id(),
13609 path: RelPath::empty(),
13610 },
13611 language,
13612 cx,
13613 )
13614}
13615
13616pub(crate) fn language_server_settings_for<'a>(
13617 location: SettingsLocation<'a>,
13618 language: &LanguageServerName,
13619 cx: &'a App,
13620) -> Option<&'a LspSettings> {
13621 ProjectSettings::get(Some(location), cx).lsp.get(language)
13622}
13623
13624pub struct LocalLspAdapterDelegate {
13625 lsp_store: WeakEntity<LspStore>,
13626 worktree: worktree::Snapshot,
13627 fs: Arc<dyn Fs>,
13628 http_client: Arc<dyn HttpClient>,
13629 language_registry: Arc<LanguageRegistry>,
13630 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13631}
13632
13633impl LocalLspAdapterDelegate {
13634 pub fn new(
13635 language_registry: Arc<LanguageRegistry>,
13636 environment: &Entity<ProjectEnvironment>,
13637 lsp_store: WeakEntity<LspStore>,
13638 worktree: &Entity<Worktree>,
13639 http_client: Arc<dyn HttpClient>,
13640 fs: Arc<dyn Fs>,
13641 cx: &mut App,
13642 ) -> Arc<Self> {
13643 let load_shell_env_task =
13644 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13645
13646 Arc::new(Self {
13647 lsp_store,
13648 worktree: worktree.read(cx).snapshot(),
13649 fs,
13650 http_client,
13651 language_registry,
13652 load_shell_env_task,
13653 })
13654 }
13655
13656 fn from_local_lsp(
13657 local: &LocalLspStore,
13658 worktree: &Entity<Worktree>,
13659 cx: &mut App,
13660 ) -> Arc<Self> {
13661 Self::new(
13662 local.languages.clone(),
13663 &local.environment,
13664 local.weak.clone(),
13665 worktree,
13666 local.http_client.clone(),
13667 local.fs.clone(),
13668 cx,
13669 )
13670 }
13671}
13672
13673#[async_trait]
13674impl LspAdapterDelegate for LocalLspAdapterDelegate {
13675 fn show_notification(&self, message: &str, cx: &mut App) {
13676 self.lsp_store
13677 .update(cx, |_, cx| {
13678 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13679 })
13680 .ok();
13681 }
13682
13683 fn http_client(&self) -> Arc<dyn HttpClient> {
13684 self.http_client.clone()
13685 }
13686
13687 fn worktree_id(&self) -> WorktreeId {
13688 self.worktree.id()
13689 }
13690
13691 fn worktree_root_path(&self) -> &Path {
13692 self.worktree.abs_path().as_ref()
13693 }
13694
13695 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13696 self.worktree.resolve_executable_path(path)
13697 }
13698
13699 async fn shell_env(&self) -> HashMap<String, String> {
13700 let task = self.load_shell_env_task.clone();
13701 task.await.unwrap_or_default()
13702 }
13703
13704 async fn npm_package_installed_version(
13705 &self,
13706 package_name: &str,
13707 ) -> Result<Option<(PathBuf, String)>> {
13708 let local_package_directory = self.worktree_root_path();
13709 let node_modules_directory = local_package_directory.join("node_modules");
13710
13711 if let Some(version) =
13712 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13713 {
13714 return Ok(Some((node_modules_directory, version)));
13715 }
13716 let Some(npm) = self.which("npm".as_ref()).await else {
13717 log::warn!(
13718 "Failed to find npm executable for {:?}",
13719 local_package_directory
13720 );
13721 return Ok(None);
13722 };
13723
13724 let env = self.shell_env().await;
13725 let output = util::command::new_smol_command(&npm)
13726 .args(["root", "-g"])
13727 .envs(env)
13728 .current_dir(local_package_directory)
13729 .output()
13730 .await?;
13731 let global_node_modules =
13732 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13733
13734 if let Some(version) =
13735 read_package_installed_version(global_node_modules.clone(), package_name).await?
13736 {
13737 return Ok(Some((global_node_modules, version)));
13738 }
13739 return Ok(None);
13740 }
13741
13742 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13743 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13744 if self.fs.is_file(&worktree_abs_path).await {
13745 worktree_abs_path.pop();
13746 }
13747
13748 let env = self.shell_env().await;
13749
13750 let shell_path = env.get("PATH").cloned();
13751
13752 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13753 }
13754
13755 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13756 let mut working_dir = self.worktree_root_path().to_path_buf();
13757 if self.fs.is_file(&working_dir).await {
13758 working_dir.pop();
13759 }
13760 let output = util::command::new_smol_command(&command.path)
13761 .args(command.arguments)
13762 .envs(command.env.clone().unwrap_or_default())
13763 .current_dir(working_dir)
13764 .output()
13765 .await?;
13766
13767 anyhow::ensure!(
13768 output.status.success(),
13769 "{}, stdout: {:?}, stderr: {:?}",
13770 output.status,
13771 String::from_utf8_lossy(&output.stdout),
13772 String::from_utf8_lossy(&output.stderr)
13773 );
13774 Ok(())
13775 }
13776
13777 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13778 self.language_registry
13779 .update_lsp_binary_status(server_name, status);
13780 }
13781
13782 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13783 self.language_registry
13784 .all_lsp_adapters()
13785 .into_iter()
13786 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13787 .collect()
13788 }
13789
13790 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13791 let dir = self.language_registry.language_server_download_dir(name)?;
13792
13793 if !dir.exists() {
13794 smol::fs::create_dir_all(&dir)
13795 .await
13796 .context("failed to create container directory")
13797 .log_err()?;
13798 }
13799
13800 Some(dir)
13801 }
13802
13803 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13804 let entry = self
13805 .worktree
13806 .entry_for_path(path)
13807 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13808 let abs_path = self.worktree.absolutize(&entry.path);
13809 self.fs.load(&abs_path).await
13810 }
13811}
13812
13813async fn populate_labels_for_symbols(
13814 symbols: Vec<CoreSymbol>,
13815 language_registry: &Arc<LanguageRegistry>,
13816 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13817 output: &mut Vec<Symbol>,
13818) {
13819 #[allow(clippy::mutable_key_type)]
13820 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13821
13822 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13823 for symbol in symbols {
13824 let Some(file_name) = symbol.path.file_name() else {
13825 continue;
13826 };
13827 let language = language_registry
13828 .load_language_for_file_path(Path::new(file_name))
13829 .await
13830 .ok()
13831 .or_else(|| {
13832 unknown_paths.insert(file_name.into());
13833 None
13834 });
13835 symbols_by_language
13836 .entry(language)
13837 .or_default()
13838 .push(symbol);
13839 }
13840
13841 for unknown_path in unknown_paths {
13842 log::info!("no language found for symbol in file {unknown_path:?}");
13843 }
13844
13845 let mut label_params = Vec::new();
13846 for (language, mut symbols) in symbols_by_language {
13847 label_params.clear();
13848 label_params.extend(
13849 symbols
13850 .iter_mut()
13851 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13852 );
13853
13854 let mut labels = Vec::new();
13855 if let Some(language) = language {
13856 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13857 language_registry
13858 .lsp_adapters(&language.name())
13859 .first()
13860 .cloned()
13861 });
13862 if let Some(lsp_adapter) = lsp_adapter {
13863 labels = lsp_adapter
13864 .labels_for_symbols(&label_params, &language)
13865 .await
13866 .log_err()
13867 .unwrap_or_default();
13868 }
13869 }
13870
13871 for ((symbol, (name, _)), label) in symbols
13872 .into_iter()
13873 .zip(label_params.drain(..))
13874 .zip(labels.into_iter().chain(iter::repeat(None)))
13875 {
13876 output.push(Symbol {
13877 language_server_name: symbol.language_server_name,
13878 source_worktree_id: symbol.source_worktree_id,
13879 source_language_server_id: symbol.source_language_server_id,
13880 path: symbol.path,
13881 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13882 name,
13883 kind: symbol.kind,
13884 range: symbol.range,
13885 });
13886 }
13887 }
13888}
13889
13890fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13891 match server.capabilities().text_document_sync.as_ref()? {
13892 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13893 // Server wants didSave but didn't specify includeText.
13894 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13895 // Server doesn't want didSave at all.
13896 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13897 // Server provided SaveOptions.
13898 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13899 Some(save_options.include_text.unwrap_or(false))
13900 }
13901 },
13902 // We do not have any save info. Kind affects didChange only.
13903 lsp::TextDocumentSyncCapability::Kind(_) => None,
13904 }
13905}
13906
13907/// Completion items are displayed in a `UniformList`.
13908/// Usually, those items are single-line strings, but in LSP responses,
13909/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13910/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13911/// 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,
13912/// breaking the completions menu presentation.
13913///
13914/// 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.
13915fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13916 let mut new_text = String::with_capacity(label.text.len());
13917 let mut offset_map = vec![0; label.text.len() + 1];
13918 let mut last_char_was_space = false;
13919 let mut new_idx = 0;
13920 let chars = label.text.char_indices().fuse();
13921 let mut newlines_removed = false;
13922
13923 for (idx, c) in chars {
13924 offset_map[idx] = new_idx;
13925
13926 match c {
13927 '\n' if last_char_was_space => {
13928 newlines_removed = true;
13929 }
13930 '\t' | ' ' if last_char_was_space => {}
13931 '\n' if !last_char_was_space => {
13932 new_text.push(' ');
13933 new_idx += 1;
13934 last_char_was_space = true;
13935 newlines_removed = true;
13936 }
13937 ' ' | '\t' => {
13938 new_text.push(' ');
13939 new_idx += 1;
13940 last_char_was_space = true;
13941 }
13942 _ => {
13943 new_text.push(c);
13944 new_idx += c.len_utf8();
13945 last_char_was_space = false;
13946 }
13947 }
13948 }
13949 offset_map[label.text.len()] = new_idx;
13950
13951 // Only modify the label if newlines were removed.
13952 if !newlines_removed {
13953 return;
13954 }
13955
13956 let last_index = new_idx;
13957 let mut run_ranges_errors = Vec::new();
13958 label.runs.retain_mut(|(range, _)| {
13959 match offset_map.get(range.start) {
13960 Some(&start) => range.start = start,
13961 None => {
13962 run_ranges_errors.push(range.clone());
13963 return false;
13964 }
13965 }
13966
13967 match offset_map.get(range.end) {
13968 Some(&end) => range.end = end,
13969 None => {
13970 run_ranges_errors.push(range.clone());
13971 range.end = last_index;
13972 }
13973 }
13974 true
13975 });
13976 if !run_ranges_errors.is_empty() {
13977 log::error!(
13978 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13979 label.text
13980 );
13981 }
13982
13983 let mut wrong_filter_range = None;
13984 if label.filter_range == (0..label.text.len()) {
13985 label.filter_range = 0..new_text.len();
13986 } else {
13987 let mut original_filter_range = Some(label.filter_range.clone());
13988 match offset_map.get(label.filter_range.start) {
13989 Some(&start) => label.filter_range.start = start,
13990 None => {
13991 wrong_filter_range = original_filter_range.take();
13992 label.filter_range.start = last_index;
13993 }
13994 }
13995
13996 match offset_map.get(label.filter_range.end) {
13997 Some(&end) => label.filter_range.end = end,
13998 None => {
13999 wrong_filter_range = original_filter_range.take();
14000 label.filter_range.end = last_index;
14001 }
14002 }
14003 }
14004 if let Some(wrong_filter_range) = wrong_filter_range {
14005 log::error!(
14006 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14007 label.text
14008 );
14009 }
14010
14011 label.text = new_text;
14012}
14013
14014#[cfg(test)]
14015mod tests {
14016 use language::HighlightId;
14017
14018 use super::*;
14019
14020 #[test]
14021 fn test_glob_literal_prefix() {
14022 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14023 assert_eq!(
14024 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14025 Path::new("node_modules")
14026 );
14027 assert_eq!(
14028 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14029 Path::new("foo")
14030 );
14031 assert_eq!(
14032 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14033 Path::new("foo/bar/baz.js")
14034 );
14035
14036 #[cfg(target_os = "windows")]
14037 {
14038 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14039 assert_eq!(
14040 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14041 Path::new("node_modules")
14042 );
14043 assert_eq!(
14044 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14045 Path::new("foo")
14046 );
14047 assert_eq!(
14048 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14049 Path::new("foo/bar/baz.js")
14050 );
14051 }
14052 }
14053
14054 #[test]
14055 fn test_multi_len_chars_normalization() {
14056 let mut label = CodeLabel::new(
14057 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14058 0..6,
14059 vec![(0..6, HighlightId(1))],
14060 );
14061 ensure_uniform_list_compatible_label(&mut label);
14062 assert_eq!(
14063 label,
14064 CodeLabel::new(
14065 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14066 0..6,
14067 vec![(0..6, HighlightId(1))],
14068 )
14069 );
14070 }
14071}