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 _ = self.buffer_snapshots.remove(&buffer.remote_id());
2688
2689 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2690 language_server.unregister_buffer(file_url.clone());
2691 }
2692 });
2693 }
2694
2695 fn buffer_snapshot_for_lsp_version(
2696 &mut self,
2697 buffer: &Entity<Buffer>,
2698 server_id: LanguageServerId,
2699 version: Option<i32>,
2700 cx: &App,
2701 ) -> Result<TextBufferSnapshot> {
2702 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2703
2704 if let Some(version) = version {
2705 let buffer_id = buffer.read(cx).remote_id();
2706 let snapshots = if let Some(snapshots) = self
2707 .buffer_snapshots
2708 .get_mut(&buffer_id)
2709 .and_then(|m| m.get_mut(&server_id))
2710 {
2711 snapshots
2712 } else if version == 0 {
2713 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2714 // We detect this case and treat it as if the version was `None`.
2715 return Ok(buffer.read(cx).text_snapshot());
2716 } else {
2717 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2718 };
2719
2720 let found_snapshot = snapshots
2721 .binary_search_by_key(&version, |e| e.version)
2722 .map(|ix| snapshots[ix].snapshot.clone())
2723 .map_err(|_| {
2724 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2725 })?;
2726
2727 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2728 Ok(found_snapshot)
2729 } else {
2730 Ok((buffer.read(cx)).text_snapshot())
2731 }
2732 }
2733
2734 async fn get_server_code_actions_from_action_kinds(
2735 lsp_store: &WeakEntity<LspStore>,
2736 language_server_id: LanguageServerId,
2737 code_action_kinds: Vec<lsp::CodeActionKind>,
2738 buffer: &Entity<Buffer>,
2739 cx: &mut AsyncApp,
2740 ) -> Result<Vec<CodeAction>> {
2741 let actions = lsp_store
2742 .update(cx, move |this, cx| {
2743 let request = GetCodeActions {
2744 range: text::Anchor::MIN..text::Anchor::MAX,
2745 kinds: Some(code_action_kinds),
2746 };
2747 let server = LanguageServerToQuery::Other(language_server_id);
2748 this.request_lsp(buffer.clone(), server, request, cx)
2749 })?
2750 .await?;
2751 Ok(actions)
2752 }
2753
2754 pub async fn execute_code_actions_on_server(
2755 lsp_store: &WeakEntity<LspStore>,
2756 language_server: &Arc<LanguageServer>,
2757
2758 actions: Vec<CodeAction>,
2759 push_to_history: bool,
2760 project_transaction: &mut ProjectTransaction,
2761 cx: &mut AsyncApp,
2762 ) -> anyhow::Result<()> {
2763 for mut action in actions {
2764 Self::try_resolve_code_action(language_server, &mut action)
2765 .await
2766 .context("resolving a formatting code action")?;
2767
2768 if let Some(edit) = action.lsp_action.edit() {
2769 if edit.changes.is_none() && edit.document_changes.is_none() {
2770 continue;
2771 }
2772
2773 let new = Self::deserialize_workspace_edit(
2774 lsp_store.upgrade().context("project dropped")?,
2775 edit.clone(),
2776 push_to_history,
2777 language_server.clone(),
2778 cx,
2779 )
2780 .await?;
2781 project_transaction.0.extend(new.0);
2782 }
2783
2784 if let Some(command) = action.lsp_action.command() {
2785 let server_capabilities = language_server.capabilities();
2786 let available_commands = server_capabilities
2787 .execute_command_provider
2788 .as_ref()
2789 .map(|options| options.commands.as_slice())
2790 .unwrap_or_default();
2791 if available_commands.contains(&command.command) {
2792 lsp_store.update(cx, |lsp_store, _| {
2793 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2794 mode.last_workspace_edits_by_language_server
2795 .remove(&language_server.server_id());
2796 }
2797 })?;
2798
2799 language_server
2800 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2801 command: command.command.clone(),
2802 arguments: command.arguments.clone().unwrap_or_default(),
2803 ..Default::default()
2804 })
2805 .await
2806 .into_response()
2807 .context("execute command")?;
2808
2809 lsp_store.update(cx, |this, _| {
2810 if let LspStoreMode::Local(mode) = &mut this.mode {
2811 project_transaction.0.extend(
2812 mode.last_workspace_edits_by_language_server
2813 .remove(&language_server.server_id())
2814 .unwrap_or_default()
2815 .0,
2816 )
2817 }
2818 })?;
2819 } else {
2820 log::warn!(
2821 "Cannot execute a command {} not listed in the language server capabilities",
2822 command.command
2823 )
2824 }
2825 }
2826 }
2827 Ok(())
2828 }
2829
2830 pub async fn deserialize_text_edits(
2831 this: Entity<LspStore>,
2832 buffer_to_edit: Entity<Buffer>,
2833 edits: Vec<lsp::TextEdit>,
2834 push_to_history: bool,
2835 _: Arc<CachedLspAdapter>,
2836 language_server: Arc<LanguageServer>,
2837 cx: &mut AsyncApp,
2838 ) -> Result<Option<Transaction>> {
2839 let edits = this
2840 .update(cx, |this, cx| {
2841 this.as_local_mut().unwrap().edits_from_lsp(
2842 &buffer_to_edit,
2843 edits,
2844 language_server.server_id(),
2845 None,
2846 cx,
2847 )
2848 })?
2849 .await?;
2850
2851 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2852 buffer.finalize_last_transaction();
2853 buffer.start_transaction();
2854 for (range, text) in edits {
2855 buffer.edit([(range, text)], None, cx);
2856 }
2857
2858 if buffer.end_transaction(cx).is_some() {
2859 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2860 if !push_to_history {
2861 buffer.forget_transaction(transaction.id);
2862 }
2863 Some(transaction)
2864 } else {
2865 None
2866 }
2867 })?;
2868
2869 Ok(transaction)
2870 }
2871
2872 #[allow(clippy::type_complexity)]
2873 pub(crate) fn edits_from_lsp(
2874 &mut self,
2875 buffer: &Entity<Buffer>,
2876 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2877 server_id: LanguageServerId,
2878 version: Option<i32>,
2879 cx: &mut Context<LspStore>,
2880 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2881 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2882 cx.background_spawn(async move {
2883 let snapshot = snapshot?;
2884 let mut lsp_edits = lsp_edits
2885 .into_iter()
2886 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2887 .collect::<Vec<_>>();
2888
2889 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2890
2891 let mut lsp_edits = lsp_edits.into_iter().peekable();
2892 let mut edits = Vec::new();
2893 while let Some((range, mut new_text)) = lsp_edits.next() {
2894 // Clip invalid ranges provided by the language server.
2895 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2896 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2897
2898 // Combine any LSP edits that are adjacent.
2899 //
2900 // Also, combine LSP edits that are separated from each other by only
2901 // a newline. This is important because for some code actions,
2902 // Rust-analyzer rewrites the entire buffer via a series of edits that
2903 // are separated by unchanged newline characters.
2904 //
2905 // In order for the diffing logic below to work properly, any edits that
2906 // cancel each other out must be combined into one.
2907 while let Some((next_range, next_text)) = lsp_edits.peek() {
2908 if next_range.start.0 > range.end {
2909 if next_range.start.0.row > range.end.row + 1
2910 || next_range.start.0.column > 0
2911 || snapshot.clip_point_utf16(
2912 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2913 Bias::Left,
2914 ) > range.end
2915 {
2916 break;
2917 }
2918 new_text.push('\n');
2919 }
2920 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2921 new_text.push_str(next_text);
2922 lsp_edits.next();
2923 }
2924
2925 // For multiline edits, perform a diff of the old and new text so that
2926 // we can identify the changes more precisely, preserving the locations
2927 // of any anchors positioned in the unchanged regions.
2928 if range.end.row > range.start.row {
2929 let offset = range.start.to_offset(&snapshot);
2930 let old_text = snapshot.text_for_range(range).collect::<String>();
2931 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2932 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2933 (
2934 snapshot.anchor_after(offset + range.start)
2935 ..snapshot.anchor_before(offset + range.end),
2936 replacement,
2937 )
2938 }));
2939 } else if range.end == range.start {
2940 let anchor = snapshot.anchor_after(range.start);
2941 edits.push((anchor..anchor, new_text.into()));
2942 } else {
2943 let edit_start = snapshot.anchor_after(range.start);
2944 let edit_end = snapshot.anchor_before(range.end);
2945 edits.push((edit_start..edit_end, new_text.into()));
2946 }
2947 }
2948
2949 Ok(edits)
2950 })
2951 }
2952
2953 pub(crate) async fn deserialize_workspace_edit(
2954 this: Entity<LspStore>,
2955 edit: lsp::WorkspaceEdit,
2956 push_to_history: bool,
2957 language_server: Arc<LanguageServer>,
2958 cx: &mut AsyncApp,
2959 ) -> Result<ProjectTransaction> {
2960 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2961
2962 let mut operations = Vec::new();
2963 if let Some(document_changes) = edit.document_changes {
2964 match document_changes {
2965 lsp::DocumentChanges::Edits(edits) => {
2966 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2967 }
2968 lsp::DocumentChanges::Operations(ops) => operations = ops,
2969 }
2970 } else if let Some(changes) = edit.changes {
2971 operations.extend(changes.into_iter().map(|(uri, edits)| {
2972 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2973 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2974 uri,
2975 version: None,
2976 },
2977 edits: edits.into_iter().map(Edit::Plain).collect(),
2978 })
2979 }));
2980 }
2981
2982 let mut project_transaction = ProjectTransaction::default();
2983 for operation in operations {
2984 match operation {
2985 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2986 let abs_path = op
2987 .uri
2988 .to_file_path()
2989 .map_err(|()| anyhow!("can't convert URI to path"))?;
2990
2991 if let Some(parent_path) = abs_path.parent() {
2992 fs.create_dir(parent_path).await?;
2993 }
2994 if abs_path.ends_with("/") {
2995 fs.create_dir(&abs_path).await?;
2996 } else {
2997 fs.create_file(
2998 &abs_path,
2999 op.options
3000 .map(|options| fs::CreateOptions {
3001 overwrite: options.overwrite.unwrap_or(false),
3002 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3003 })
3004 .unwrap_or_default(),
3005 )
3006 .await?;
3007 }
3008 }
3009
3010 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3011 let source_abs_path = op
3012 .old_uri
3013 .to_file_path()
3014 .map_err(|()| anyhow!("can't convert URI to path"))?;
3015 let target_abs_path = op
3016 .new_uri
3017 .to_file_path()
3018 .map_err(|()| anyhow!("can't convert URI to path"))?;
3019 fs.rename(
3020 &source_abs_path,
3021 &target_abs_path,
3022 op.options
3023 .map(|options| fs::RenameOptions {
3024 overwrite: options.overwrite.unwrap_or(false),
3025 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3026 })
3027 .unwrap_or_default(),
3028 )
3029 .await?;
3030 }
3031
3032 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3033 let abs_path = op
3034 .uri
3035 .to_file_path()
3036 .map_err(|()| anyhow!("can't convert URI to path"))?;
3037 let options = op
3038 .options
3039 .map(|options| fs::RemoveOptions {
3040 recursive: options.recursive.unwrap_or(false),
3041 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3042 })
3043 .unwrap_or_default();
3044 if abs_path.ends_with("/") {
3045 fs.remove_dir(&abs_path, options).await?;
3046 } else {
3047 fs.remove_file(&abs_path, options).await?;
3048 }
3049 }
3050
3051 lsp::DocumentChangeOperation::Edit(op) => {
3052 let buffer_to_edit = this
3053 .update(cx, |this, cx| {
3054 this.open_local_buffer_via_lsp(
3055 op.text_document.uri.clone(),
3056 language_server.server_id(),
3057 cx,
3058 )
3059 })?
3060 .await?;
3061
3062 let edits = this
3063 .update(cx, |this, cx| {
3064 let path = buffer_to_edit.read(cx).project_path(cx);
3065 let active_entry = this.active_entry;
3066 let is_active_entry = path.is_some_and(|project_path| {
3067 this.worktree_store
3068 .read(cx)
3069 .entry_for_path(&project_path, cx)
3070 .is_some_and(|entry| Some(entry.id) == active_entry)
3071 });
3072 let local = this.as_local_mut().unwrap();
3073
3074 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3075 for edit in op.edits {
3076 match edit {
3077 Edit::Plain(edit) => {
3078 if !edits.contains(&edit) {
3079 edits.push(edit)
3080 }
3081 }
3082 Edit::Annotated(edit) => {
3083 if !edits.contains(&edit.text_edit) {
3084 edits.push(edit.text_edit)
3085 }
3086 }
3087 Edit::Snippet(edit) => {
3088 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3089 else {
3090 continue;
3091 };
3092
3093 if is_active_entry {
3094 snippet_edits.push((edit.range, snippet));
3095 } else {
3096 // Since this buffer is not focused, apply a normal edit.
3097 let new_edit = TextEdit {
3098 range: edit.range,
3099 new_text: snippet.text,
3100 };
3101 if !edits.contains(&new_edit) {
3102 edits.push(new_edit);
3103 }
3104 }
3105 }
3106 }
3107 }
3108 if !snippet_edits.is_empty() {
3109 let buffer_id = buffer_to_edit.read(cx).remote_id();
3110 let version = if let Some(buffer_version) = op.text_document.version
3111 {
3112 local
3113 .buffer_snapshot_for_lsp_version(
3114 &buffer_to_edit,
3115 language_server.server_id(),
3116 Some(buffer_version),
3117 cx,
3118 )
3119 .ok()
3120 .map(|snapshot| snapshot.version)
3121 } else {
3122 Some(buffer_to_edit.read(cx).saved_version().clone())
3123 };
3124
3125 let most_recent_edit =
3126 version.and_then(|version| version.most_recent());
3127 // Check if the edit that triggered that edit has been made by this participant.
3128
3129 if let Some(most_recent_edit) = most_recent_edit {
3130 cx.emit(LspStoreEvent::SnippetEdit {
3131 buffer_id,
3132 edits: snippet_edits,
3133 most_recent_edit,
3134 });
3135 }
3136 }
3137
3138 local.edits_from_lsp(
3139 &buffer_to_edit,
3140 edits,
3141 language_server.server_id(),
3142 op.text_document.version,
3143 cx,
3144 )
3145 })?
3146 .await?;
3147
3148 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3149 buffer.finalize_last_transaction();
3150 buffer.start_transaction();
3151 for (range, text) in edits {
3152 buffer.edit([(range, text)], None, cx);
3153 }
3154
3155 buffer.end_transaction(cx).and_then(|transaction_id| {
3156 if push_to_history {
3157 buffer.finalize_last_transaction();
3158 buffer.get_transaction(transaction_id).cloned()
3159 } else {
3160 buffer.forget_transaction(transaction_id)
3161 }
3162 })
3163 })?;
3164 if let Some(transaction) = transaction {
3165 project_transaction.0.insert(buffer_to_edit, transaction);
3166 }
3167 }
3168 }
3169 }
3170
3171 Ok(project_transaction)
3172 }
3173
3174 async fn on_lsp_workspace_edit(
3175 this: WeakEntity<LspStore>,
3176 params: lsp::ApplyWorkspaceEditParams,
3177 server_id: LanguageServerId,
3178 cx: &mut AsyncApp,
3179 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3180 let this = this.upgrade().context("project project closed")?;
3181 let language_server = this
3182 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3183 .context("language server not found")?;
3184 let transaction = Self::deserialize_workspace_edit(
3185 this.clone(),
3186 params.edit,
3187 true,
3188 language_server.clone(),
3189 cx,
3190 )
3191 .await
3192 .log_err();
3193 this.update(cx, |this, _| {
3194 if let Some(transaction) = transaction {
3195 this.as_local_mut()
3196 .unwrap()
3197 .last_workspace_edits_by_language_server
3198 .insert(server_id, transaction);
3199 }
3200 })?;
3201 Ok(lsp::ApplyWorkspaceEditResponse {
3202 applied: true,
3203 failed_change: None,
3204 failure_reason: None,
3205 })
3206 }
3207
3208 fn remove_worktree(
3209 &mut self,
3210 id_to_remove: WorktreeId,
3211 cx: &mut Context<LspStore>,
3212 ) -> Vec<LanguageServerId> {
3213 self.diagnostics.remove(&id_to_remove);
3214 self.prettier_store.update(cx, |prettier_store, cx| {
3215 prettier_store.remove_worktree(id_to_remove, cx);
3216 });
3217
3218 let mut servers_to_remove = BTreeSet::default();
3219 let mut servers_to_preserve = HashSet::default();
3220 for (seed, state) in &self.language_server_ids {
3221 if seed.worktree_id == id_to_remove {
3222 servers_to_remove.insert(state.id);
3223 } else {
3224 servers_to_preserve.insert(state.id);
3225 }
3226 }
3227 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3228 self.language_server_ids
3229 .retain(|_, state| !servers_to_remove.contains(&state.id));
3230 for server_id_to_remove in &servers_to_remove {
3231 self.language_server_watched_paths
3232 .remove(server_id_to_remove);
3233 self.language_server_paths_watched_for_rename
3234 .remove(server_id_to_remove);
3235 self.last_workspace_edits_by_language_server
3236 .remove(server_id_to_remove);
3237 self.language_servers.remove(server_id_to_remove);
3238 self.buffer_pull_diagnostics_result_ids
3239 .remove(server_id_to_remove);
3240 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3241 buffer_servers.remove(server_id_to_remove);
3242 }
3243 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3244 }
3245 servers_to_remove.into_iter().collect()
3246 }
3247
3248 fn rebuild_watched_paths_inner<'a>(
3249 &'a self,
3250 language_server_id: LanguageServerId,
3251 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3252 cx: &mut Context<LspStore>,
3253 ) -> LanguageServerWatchedPathsBuilder {
3254 let worktrees = self
3255 .worktree_store
3256 .read(cx)
3257 .worktrees()
3258 .filter_map(|worktree| {
3259 self.language_servers_for_worktree(worktree.read(cx).id())
3260 .find(|server| server.server_id() == language_server_id)
3261 .map(|_| worktree)
3262 })
3263 .collect::<Vec<_>>();
3264
3265 let mut worktree_globs = HashMap::default();
3266 let mut abs_globs = HashMap::default();
3267 log::trace!(
3268 "Processing new watcher paths for language server with id {}",
3269 language_server_id
3270 );
3271
3272 for watcher in watchers {
3273 if let Some((worktree, literal_prefix, pattern)) =
3274 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3275 {
3276 worktree.update(cx, |worktree, _| {
3277 if let Some((tree, glob)) =
3278 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3279 {
3280 tree.add_path_prefix_to_scan(literal_prefix);
3281 worktree_globs
3282 .entry(tree.id())
3283 .or_insert_with(GlobSetBuilder::new)
3284 .add(glob);
3285 }
3286 });
3287 } else {
3288 let (path, pattern) = match &watcher.glob_pattern {
3289 lsp::GlobPattern::String(s) => {
3290 let watcher_path = SanitizedPath::new(s);
3291 let path = glob_literal_prefix(watcher_path.as_path());
3292 let pattern = watcher_path
3293 .as_path()
3294 .strip_prefix(&path)
3295 .map(|p| p.to_string_lossy().into_owned())
3296 .unwrap_or_else(|e| {
3297 debug_panic!(
3298 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3299 s,
3300 path.display(),
3301 e
3302 );
3303 watcher_path.as_path().to_string_lossy().into_owned()
3304 });
3305 (path, pattern)
3306 }
3307 lsp::GlobPattern::Relative(rp) => {
3308 let Ok(mut base_uri) = match &rp.base_uri {
3309 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3310 lsp::OneOf::Right(base_uri) => base_uri,
3311 }
3312 .to_file_path() else {
3313 continue;
3314 };
3315
3316 let path = glob_literal_prefix(Path::new(&rp.pattern));
3317 let pattern = Path::new(&rp.pattern)
3318 .strip_prefix(&path)
3319 .map(|p| p.to_string_lossy().into_owned())
3320 .unwrap_or_else(|e| {
3321 debug_panic!(
3322 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3323 rp.pattern,
3324 path.display(),
3325 e
3326 );
3327 rp.pattern.clone()
3328 });
3329 base_uri.push(path);
3330 (base_uri, pattern)
3331 }
3332 };
3333
3334 if let Some(glob) = Glob::new(&pattern).log_err() {
3335 if !path
3336 .components()
3337 .any(|c| matches!(c, path::Component::Normal(_)))
3338 {
3339 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3340 // rather than adding a new watcher for `/`.
3341 for worktree in &worktrees {
3342 worktree_globs
3343 .entry(worktree.read(cx).id())
3344 .or_insert_with(GlobSetBuilder::new)
3345 .add(glob.clone());
3346 }
3347 } else {
3348 abs_globs
3349 .entry(path.into())
3350 .or_insert_with(GlobSetBuilder::new)
3351 .add(glob);
3352 }
3353 }
3354 }
3355 }
3356
3357 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3358 for (worktree_id, builder) in worktree_globs {
3359 if let Ok(globset) = builder.build() {
3360 watch_builder.watch_worktree(worktree_id, globset);
3361 }
3362 }
3363 for (abs_path, builder) in abs_globs {
3364 if let Ok(globset) = builder.build() {
3365 watch_builder.watch_abs_path(abs_path, globset);
3366 }
3367 }
3368 watch_builder
3369 }
3370
3371 fn worktree_and_path_for_file_watcher(
3372 worktrees: &[Entity<Worktree>],
3373 watcher: &FileSystemWatcher,
3374 cx: &App,
3375 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3376 worktrees.iter().find_map(|worktree| {
3377 let tree = worktree.read(cx);
3378 let worktree_root_path = tree.abs_path();
3379 let path_style = tree.path_style();
3380 match &watcher.glob_pattern {
3381 lsp::GlobPattern::String(s) => {
3382 let watcher_path = SanitizedPath::new(s);
3383 let relative = watcher_path
3384 .as_path()
3385 .strip_prefix(&worktree_root_path)
3386 .ok()?;
3387 let literal_prefix = glob_literal_prefix(relative);
3388 Some((
3389 worktree.clone(),
3390 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3391 relative.to_string_lossy().into_owned(),
3392 ))
3393 }
3394 lsp::GlobPattern::Relative(rp) => {
3395 let base_uri = match &rp.base_uri {
3396 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3397 lsp::OneOf::Right(base_uri) => base_uri,
3398 }
3399 .to_file_path()
3400 .ok()?;
3401 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3402 let mut literal_prefix = relative.to_owned();
3403 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3404 Some((
3405 worktree.clone(),
3406 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3407 rp.pattern.clone(),
3408 ))
3409 }
3410 }
3411 })
3412 }
3413
3414 fn rebuild_watched_paths(
3415 &mut self,
3416 language_server_id: LanguageServerId,
3417 cx: &mut Context<LspStore>,
3418 ) {
3419 let Some(registrations) = self
3420 .language_server_dynamic_registrations
3421 .get(&language_server_id)
3422 else {
3423 return;
3424 };
3425
3426 let watch_builder = self.rebuild_watched_paths_inner(
3427 language_server_id,
3428 registrations.did_change_watched_files.values().flatten(),
3429 cx,
3430 );
3431 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3432 self.language_server_watched_paths
3433 .insert(language_server_id, watcher);
3434
3435 cx.notify();
3436 }
3437
3438 fn on_lsp_did_change_watched_files(
3439 &mut self,
3440 language_server_id: LanguageServerId,
3441 registration_id: &str,
3442 params: DidChangeWatchedFilesRegistrationOptions,
3443 cx: &mut Context<LspStore>,
3444 ) {
3445 let registrations = self
3446 .language_server_dynamic_registrations
3447 .entry(language_server_id)
3448 .or_default();
3449
3450 registrations
3451 .did_change_watched_files
3452 .insert(registration_id.to_string(), params.watchers);
3453
3454 self.rebuild_watched_paths(language_server_id, cx);
3455 }
3456
3457 fn on_lsp_unregister_did_change_watched_files(
3458 &mut self,
3459 language_server_id: LanguageServerId,
3460 registration_id: &str,
3461 cx: &mut Context<LspStore>,
3462 ) {
3463 let registrations = self
3464 .language_server_dynamic_registrations
3465 .entry(language_server_id)
3466 .or_default();
3467
3468 if registrations
3469 .did_change_watched_files
3470 .remove(registration_id)
3471 .is_some()
3472 {
3473 log::info!(
3474 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3475 language_server_id,
3476 registration_id
3477 );
3478 } else {
3479 log::warn!(
3480 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3481 language_server_id,
3482 registration_id
3483 );
3484 }
3485
3486 self.rebuild_watched_paths(language_server_id, cx);
3487 }
3488
3489 async fn initialization_options_for_adapter(
3490 adapter: Arc<dyn LspAdapter>,
3491 delegate: &Arc<dyn LspAdapterDelegate>,
3492 ) -> Result<Option<serde_json::Value>> {
3493 let Some(mut initialization_config) =
3494 adapter.clone().initialization_options(delegate).await?
3495 else {
3496 return Ok(None);
3497 };
3498
3499 for other_adapter in delegate.registered_lsp_adapters() {
3500 if other_adapter.name() == adapter.name() {
3501 continue;
3502 }
3503 if let Ok(Some(target_config)) = other_adapter
3504 .clone()
3505 .additional_initialization_options(adapter.name(), delegate)
3506 .await
3507 {
3508 merge_json_value_into(target_config.clone(), &mut initialization_config);
3509 }
3510 }
3511
3512 Ok(Some(initialization_config))
3513 }
3514
3515 async fn workspace_configuration_for_adapter(
3516 adapter: Arc<dyn LspAdapter>,
3517 delegate: &Arc<dyn LspAdapterDelegate>,
3518 toolchain: Option<Toolchain>,
3519 cx: &mut AsyncApp,
3520 ) -> Result<serde_json::Value> {
3521 let mut workspace_config = adapter
3522 .clone()
3523 .workspace_configuration(delegate, toolchain, cx)
3524 .await?;
3525
3526 for other_adapter in delegate.registered_lsp_adapters() {
3527 if other_adapter.name() == adapter.name() {
3528 continue;
3529 }
3530 if let Ok(Some(target_config)) = other_adapter
3531 .clone()
3532 .additional_workspace_configuration(adapter.name(), delegate, cx)
3533 .await
3534 {
3535 merge_json_value_into(target_config.clone(), &mut workspace_config);
3536 }
3537 }
3538
3539 Ok(workspace_config)
3540 }
3541
3542 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3543 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3544 Some(server.clone())
3545 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3546 Some(Arc::clone(server))
3547 } else {
3548 None
3549 }
3550 }
3551}
3552
3553fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3554 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3555 cx.emit(LspStoreEvent::LanguageServerUpdate {
3556 language_server_id: server.server_id(),
3557 name: Some(server.name()),
3558 message: proto::update_language_server::Variant::MetadataUpdated(
3559 proto::ServerMetadataUpdated {
3560 capabilities: Some(capabilities),
3561 binary: Some(proto::LanguageServerBinaryInfo {
3562 path: server.binary().path.to_string_lossy().into_owned(),
3563 arguments: server
3564 .binary()
3565 .arguments
3566 .iter()
3567 .map(|arg| arg.to_string_lossy().into_owned())
3568 .collect(),
3569 }),
3570 configuration: serde_json::to_string(server.configuration()).ok(),
3571 workspace_folders: server
3572 .workspace_folders()
3573 .iter()
3574 .map(|uri| uri.to_string())
3575 .collect(),
3576 },
3577 ),
3578 });
3579 }
3580}
3581
3582#[derive(Debug)]
3583pub struct FormattableBuffer {
3584 handle: Entity<Buffer>,
3585 abs_path: Option<PathBuf>,
3586 env: Option<HashMap<String, String>>,
3587 ranges: Option<Vec<Range<Anchor>>>,
3588}
3589
3590pub struct RemoteLspStore {
3591 upstream_client: Option<AnyProtoClient>,
3592 upstream_project_id: u64,
3593}
3594
3595pub(crate) enum LspStoreMode {
3596 Local(LocalLspStore), // ssh host and collab host
3597 Remote(RemoteLspStore), // collab guest
3598}
3599
3600impl LspStoreMode {
3601 fn is_local(&self) -> bool {
3602 matches!(self, LspStoreMode::Local(_))
3603 }
3604}
3605
3606pub struct LspStore {
3607 mode: LspStoreMode,
3608 last_formatting_failure: Option<String>,
3609 downstream_client: Option<(AnyProtoClient, u64)>,
3610 nonce: u128,
3611 buffer_store: Entity<BufferStore>,
3612 worktree_store: Entity<WorktreeStore>,
3613 pub languages: Arc<LanguageRegistry>,
3614 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3615 active_entry: Option<ProjectEntryId>,
3616 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3617 _maintain_buffer_languages: Task<()>,
3618 diagnostic_summaries:
3619 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3620 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3621 lsp_data: HashMap<BufferId, BufferLspData>,
3622 next_hint_id: Arc<AtomicUsize>,
3623}
3624
3625#[derive(Debug)]
3626pub struct BufferLspData {
3627 buffer_version: Global,
3628 document_colors: Option<DocumentColorData>,
3629 code_lens: Option<CodeLensData>,
3630 inlay_hints: BufferInlayHints,
3631 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3632 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3633}
3634
3635#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3636struct LspKey {
3637 request_type: TypeId,
3638 server_queried: Option<LanguageServerId>,
3639}
3640
3641impl BufferLspData {
3642 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3643 Self {
3644 buffer_version: buffer.read(cx).version(),
3645 document_colors: None,
3646 code_lens: None,
3647 inlay_hints: BufferInlayHints::new(buffer, cx),
3648 lsp_requests: HashMap::default(),
3649 chunk_lsp_requests: HashMap::default(),
3650 }
3651 }
3652
3653 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3654 if let Some(document_colors) = &mut self.document_colors {
3655 document_colors.colors.remove(&for_server);
3656 document_colors.cache_version += 1;
3657 }
3658
3659 if let Some(code_lens) = &mut self.code_lens {
3660 code_lens.lens.remove(&for_server);
3661 }
3662
3663 self.inlay_hints.remove_server_data(for_server);
3664 }
3665
3666 #[cfg(any(test, feature = "test-support"))]
3667 pub fn inlay_hints(&self) -> &BufferInlayHints {
3668 &self.inlay_hints
3669 }
3670}
3671
3672#[derive(Debug, Default, Clone)]
3673pub struct DocumentColors {
3674 pub colors: HashSet<DocumentColor>,
3675 pub cache_version: Option<usize>,
3676}
3677
3678type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3679type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3680
3681#[derive(Debug, Default)]
3682struct DocumentColorData {
3683 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3684 cache_version: usize,
3685 colors_update: Option<(Global, DocumentColorTask)>,
3686}
3687
3688#[derive(Debug, Default)]
3689struct CodeLensData {
3690 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3691 update: Option<(Global, CodeLensTask)>,
3692}
3693
3694#[derive(Debug)]
3695pub enum LspStoreEvent {
3696 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3697 LanguageServerRemoved(LanguageServerId),
3698 LanguageServerUpdate {
3699 language_server_id: LanguageServerId,
3700 name: Option<LanguageServerName>,
3701 message: proto::update_language_server::Variant,
3702 },
3703 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3704 LanguageServerPrompt(LanguageServerPromptRequest),
3705 LanguageDetected {
3706 buffer: Entity<Buffer>,
3707 new_language: Option<Arc<Language>>,
3708 },
3709 Notification(String),
3710 RefreshInlayHints {
3711 server_id: LanguageServerId,
3712 request_id: Option<usize>,
3713 },
3714 RefreshCodeLens,
3715 DiagnosticsUpdated {
3716 server_id: LanguageServerId,
3717 paths: Vec<ProjectPath>,
3718 },
3719 DiskBasedDiagnosticsStarted {
3720 language_server_id: LanguageServerId,
3721 },
3722 DiskBasedDiagnosticsFinished {
3723 language_server_id: LanguageServerId,
3724 },
3725 SnippetEdit {
3726 buffer_id: BufferId,
3727 edits: Vec<(lsp::Range, Snippet)>,
3728 most_recent_edit: clock::Lamport,
3729 },
3730}
3731
3732#[derive(Clone, Debug, Serialize)]
3733pub struct LanguageServerStatus {
3734 pub name: LanguageServerName,
3735 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3736 pub has_pending_diagnostic_updates: bool,
3737 pub progress_tokens: HashSet<ProgressToken>,
3738 pub worktree: Option<WorktreeId>,
3739 pub binary: Option<LanguageServerBinary>,
3740 pub configuration: Option<Value>,
3741 pub workspace_folders: BTreeSet<Uri>,
3742}
3743
3744#[derive(Clone, Debug)]
3745struct CoreSymbol {
3746 pub language_server_name: LanguageServerName,
3747 pub source_worktree_id: WorktreeId,
3748 pub source_language_server_id: LanguageServerId,
3749 pub path: SymbolLocation,
3750 pub name: String,
3751 pub kind: lsp::SymbolKind,
3752 pub range: Range<Unclipped<PointUtf16>>,
3753}
3754
3755#[derive(Clone, Debug, PartialEq, Eq)]
3756pub enum SymbolLocation {
3757 InProject(ProjectPath),
3758 OutsideProject {
3759 abs_path: Arc<Path>,
3760 signature: [u8; 32],
3761 },
3762}
3763
3764impl SymbolLocation {
3765 fn file_name(&self) -> Option<&str> {
3766 match self {
3767 Self::InProject(path) => path.path.file_name(),
3768 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3769 }
3770 }
3771}
3772
3773impl LspStore {
3774 pub fn init(client: &AnyProtoClient) {
3775 client.add_entity_request_handler(Self::handle_lsp_query);
3776 client.add_entity_message_handler(Self::handle_lsp_query_response);
3777 client.add_entity_request_handler(Self::handle_restart_language_servers);
3778 client.add_entity_request_handler(Self::handle_stop_language_servers);
3779 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3780 client.add_entity_message_handler(Self::handle_start_language_server);
3781 client.add_entity_message_handler(Self::handle_update_language_server);
3782 client.add_entity_message_handler(Self::handle_language_server_log);
3783 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3784 client.add_entity_request_handler(Self::handle_format_buffers);
3785 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3786 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3787 client.add_entity_request_handler(Self::handle_apply_code_action);
3788 client.add_entity_request_handler(Self::handle_get_project_symbols);
3789 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3790 client.add_entity_request_handler(Self::handle_get_color_presentation);
3791 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3792 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3793 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3794 client.add_entity_request_handler(Self::handle_on_type_formatting);
3795 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3796 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3797 client.add_entity_request_handler(Self::handle_rename_project_entry);
3798 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3799 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3800 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3801 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3802 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3803 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3804 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3805
3806 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3807 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3808 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3809 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3810 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3811 client.add_entity_request_handler(
3812 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3813 );
3814 client.add_entity_request_handler(
3815 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3816 );
3817 client.add_entity_request_handler(
3818 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3819 );
3820 }
3821
3822 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3823 match &self.mode {
3824 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3825 _ => None,
3826 }
3827 }
3828
3829 pub fn as_local(&self) -> Option<&LocalLspStore> {
3830 match &self.mode {
3831 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3832 _ => None,
3833 }
3834 }
3835
3836 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3837 match &mut self.mode {
3838 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3839 _ => None,
3840 }
3841 }
3842
3843 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3844 match &self.mode {
3845 LspStoreMode::Remote(RemoteLspStore {
3846 upstream_client: Some(upstream_client),
3847 upstream_project_id,
3848 ..
3849 }) => Some((upstream_client.clone(), *upstream_project_id)),
3850
3851 LspStoreMode::Remote(RemoteLspStore {
3852 upstream_client: None,
3853 ..
3854 }) => None,
3855 LspStoreMode::Local(_) => None,
3856 }
3857 }
3858
3859 pub fn new_local(
3860 buffer_store: Entity<BufferStore>,
3861 worktree_store: Entity<WorktreeStore>,
3862 prettier_store: Entity<PrettierStore>,
3863 toolchain_store: Entity<LocalToolchainStore>,
3864 environment: Entity<ProjectEnvironment>,
3865 manifest_tree: Entity<ManifestTree>,
3866 languages: Arc<LanguageRegistry>,
3867 http_client: Arc<dyn HttpClient>,
3868 fs: Arc<dyn Fs>,
3869 cx: &mut Context<Self>,
3870 ) -> Self {
3871 let yarn = YarnPathStore::new(fs.clone(), cx);
3872 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3873 .detach();
3874 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3875 .detach();
3876 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3877 .detach();
3878 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3879 .detach();
3880 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3881 .detach();
3882 subscribe_to_binary_statuses(&languages, cx).detach();
3883
3884 let _maintain_workspace_config = {
3885 let (sender, receiver) = watch::channel();
3886 (Self::maintain_workspace_config(receiver, cx), sender)
3887 };
3888
3889 Self {
3890 mode: LspStoreMode::Local(LocalLspStore {
3891 weak: cx.weak_entity(),
3892 worktree_store: worktree_store.clone(),
3893
3894 supplementary_language_servers: Default::default(),
3895 languages: languages.clone(),
3896 language_server_ids: Default::default(),
3897 language_servers: Default::default(),
3898 last_workspace_edits_by_language_server: Default::default(),
3899 language_server_watched_paths: Default::default(),
3900 language_server_paths_watched_for_rename: Default::default(),
3901 language_server_dynamic_registrations: Default::default(),
3902 buffers_being_formatted: Default::default(),
3903 buffer_snapshots: Default::default(),
3904 prettier_store,
3905 environment,
3906 http_client,
3907 fs,
3908 yarn,
3909 next_diagnostic_group_id: Default::default(),
3910 diagnostics: Default::default(),
3911 _subscription: cx.on_app_quit(|this, cx| {
3912 this.as_local_mut()
3913 .unwrap()
3914 .shutdown_language_servers_on_quit(cx)
3915 }),
3916 lsp_tree: LanguageServerTree::new(
3917 manifest_tree,
3918 languages.clone(),
3919 toolchain_store.clone(),
3920 ),
3921 toolchain_store,
3922 registered_buffers: HashMap::default(),
3923 buffers_opened_in_servers: HashMap::default(),
3924 buffer_pull_diagnostics_result_ids: HashMap::default(),
3925 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3926 .manifest_file_names(),
3927 }),
3928 last_formatting_failure: None,
3929 downstream_client: None,
3930 buffer_store,
3931 worktree_store,
3932 languages: languages.clone(),
3933 language_server_statuses: Default::default(),
3934 nonce: StdRng::from_os_rng().random(),
3935 diagnostic_summaries: HashMap::default(),
3936 lsp_server_capabilities: HashMap::default(),
3937 lsp_data: HashMap::default(),
3938 next_hint_id: Arc::default(),
3939 active_entry: None,
3940 _maintain_workspace_config,
3941 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3942 }
3943 }
3944
3945 fn send_lsp_proto_request<R: LspCommand>(
3946 &self,
3947 buffer: Entity<Buffer>,
3948 client: AnyProtoClient,
3949 upstream_project_id: u64,
3950 request: R,
3951 cx: &mut Context<LspStore>,
3952 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3953 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3954 return Task::ready(Ok(R::Response::default()));
3955 }
3956 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3957 cx.spawn(async move |this, cx| {
3958 let response = client.request(message).await?;
3959 let this = this.upgrade().context("project dropped")?;
3960 request
3961 .response_from_proto(response, this, buffer, cx.clone())
3962 .await
3963 })
3964 }
3965
3966 pub(super) fn new_remote(
3967 buffer_store: Entity<BufferStore>,
3968 worktree_store: Entity<WorktreeStore>,
3969 languages: Arc<LanguageRegistry>,
3970 upstream_client: AnyProtoClient,
3971 project_id: u64,
3972 cx: &mut Context<Self>,
3973 ) -> Self {
3974 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3975 .detach();
3976 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3977 .detach();
3978 subscribe_to_binary_statuses(&languages, cx).detach();
3979 let _maintain_workspace_config = {
3980 let (sender, receiver) = watch::channel();
3981 (Self::maintain_workspace_config(receiver, cx), sender)
3982 };
3983 Self {
3984 mode: LspStoreMode::Remote(RemoteLspStore {
3985 upstream_client: Some(upstream_client),
3986 upstream_project_id: project_id,
3987 }),
3988 downstream_client: None,
3989 last_formatting_failure: None,
3990 buffer_store,
3991 worktree_store,
3992 languages: languages.clone(),
3993 language_server_statuses: Default::default(),
3994 nonce: StdRng::from_os_rng().random(),
3995 diagnostic_summaries: HashMap::default(),
3996 lsp_server_capabilities: HashMap::default(),
3997 next_hint_id: Arc::default(),
3998 lsp_data: HashMap::default(),
3999 active_entry: None,
4000
4001 _maintain_workspace_config,
4002 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4003 }
4004 }
4005
4006 fn on_buffer_store_event(
4007 &mut self,
4008 _: Entity<BufferStore>,
4009 event: &BufferStoreEvent,
4010 cx: &mut Context<Self>,
4011 ) {
4012 match event {
4013 BufferStoreEvent::BufferAdded(buffer) => {
4014 self.on_buffer_added(buffer, cx).log_err();
4015 }
4016 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4017 let buffer_id = buffer.read(cx).remote_id();
4018 if let Some(local) = self.as_local_mut()
4019 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4020 {
4021 local.reset_buffer(buffer, old_file, cx);
4022
4023 if local.registered_buffers.contains_key(&buffer_id) {
4024 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4025 }
4026 }
4027
4028 self.detect_language_for_buffer(buffer, cx);
4029 if let Some(local) = self.as_local_mut() {
4030 local.initialize_buffer(buffer, cx);
4031 if local.registered_buffers.contains_key(&buffer_id) {
4032 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4033 }
4034 }
4035 }
4036 _ => {}
4037 }
4038 }
4039
4040 fn on_worktree_store_event(
4041 &mut self,
4042 _: Entity<WorktreeStore>,
4043 event: &WorktreeStoreEvent,
4044 cx: &mut Context<Self>,
4045 ) {
4046 match event {
4047 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4048 if !worktree.read(cx).is_local() {
4049 return;
4050 }
4051 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4052 worktree::Event::UpdatedEntries(changes) => {
4053 this.update_local_worktree_language_servers(&worktree, changes, cx);
4054 }
4055 worktree::Event::UpdatedGitRepositories(_)
4056 | worktree::Event::DeletedEntry(_) => {}
4057 })
4058 .detach()
4059 }
4060 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4061 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4062 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4063 }
4064 WorktreeStoreEvent::WorktreeReleased(..)
4065 | WorktreeStoreEvent::WorktreeOrderChanged
4066 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4067 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4068 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4069 }
4070 }
4071
4072 fn on_prettier_store_event(
4073 &mut self,
4074 _: Entity<PrettierStore>,
4075 event: &PrettierStoreEvent,
4076 cx: &mut Context<Self>,
4077 ) {
4078 match event {
4079 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4080 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4081 }
4082 PrettierStoreEvent::LanguageServerAdded {
4083 new_server_id,
4084 name,
4085 prettier_server,
4086 } => {
4087 self.register_supplementary_language_server(
4088 *new_server_id,
4089 name.clone(),
4090 prettier_server.clone(),
4091 cx,
4092 );
4093 }
4094 }
4095 }
4096
4097 fn on_toolchain_store_event(
4098 &mut self,
4099 _: Entity<LocalToolchainStore>,
4100 event: &ToolchainStoreEvent,
4101 _: &mut Context<Self>,
4102 ) {
4103 if let ToolchainStoreEvent::ToolchainActivated = event {
4104 self.request_workspace_config_refresh()
4105 }
4106 }
4107
4108 fn request_workspace_config_refresh(&mut self) {
4109 *self._maintain_workspace_config.1.borrow_mut() = ();
4110 }
4111
4112 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4113 self.as_local().map(|local| local.prettier_store.clone())
4114 }
4115
4116 fn on_buffer_event(
4117 &mut self,
4118 buffer: Entity<Buffer>,
4119 event: &language::BufferEvent,
4120 cx: &mut Context<Self>,
4121 ) {
4122 match event {
4123 language::BufferEvent::Edited => {
4124 self.on_buffer_edited(buffer, cx);
4125 }
4126
4127 language::BufferEvent::Saved => {
4128 self.on_buffer_saved(buffer, cx);
4129 }
4130
4131 _ => {}
4132 }
4133 }
4134
4135 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4136 buffer
4137 .read(cx)
4138 .set_language_registry(self.languages.clone());
4139
4140 cx.subscribe(buffer, |this, buffer, event, cx| {
4141 this.on_buffer_event(buffer, event, cx);
4142 })
4143 .detach();
4144
4145 self.detect_language_for_buffer(buffer, cx);
4146 if let Some(local) = self.as_local_mut() {
4147 local.initialize_buffer(buffer, cx);
4148 }
4149
4150 Ok(())
4151 }
4152
4153 pub(crate) fn register_buffer_with_language_servers(
4154 &mut self,
4155 buffer: &Entity<Buffer>,
4156 only_register_servers: HashSet<LanguageServerSelector>,
4157 ignore_refcounts: bool,
4158 cx: &mut Context<Self>,
4159 ) -> OpenLspBufferHandle {
4160 let buffer_id = buffer.read(cx).remote_id();
4161 let handle = cx.new(|_| buffer.clone());
4162 if let Some(local) = self.as_local_mut() {
4163 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4164 if !ignore_refcounts {
4165 *refcount += 1;
4166 }
4167
4168 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4169 // 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
4170 // 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
4171 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4172 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4173 return handle;
4174 };
4175 if !file.is_local() {
4176 return handle;
4177 }
4178
4179 if ignore_refcounts || *refcount == 1 {
4180 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4181 }
4182 if !ignore_refcounts {
4183 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4184 let refcount = {
4185 let local = lsp_store.as_local_mut().unwrap();
4186 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4187 debug_panic!("bad refcounting");
4188 return;
4189 };
4190
4191 *refcount -= 1;
4192 *refcount
4193 };
4194 if refcount == 0 {
4195 lsp_store.lsp_data.remove(&buffer_id);
4196 let local = lsp_store.as_local_mut().unwrap();
4197 local.registered_buffers.remove(&buffer_id);
4198 local.buffers_opened_in_servers.remove(&buffer_id);
4199 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4200 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4201 }
4202 }
4203 })
4204 .detach();
4205 }
4206 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4207 let buffer_id = buffer.read(cx).remote_id().to_proto();
4208 cx.background_spawn(async move {
4209 upstream_client
4210 .request(proto::RegisterBufferWithLanguageServers {
4211 project_id: upstream_project_id,
4212 buffer_id,
4213 only_servers: only_register_servers
4214 .into_iter()
4215 .map(|selector| {
4216 let selector = match selector {
4217 LanguageServerSelector::Id(language_server_id) => {
4218 proto::language_server_selector::Selector::ServerId(
4219 language_server_id.to_proto(),
4220 )
4221 }
4222 LanguageServerSelector::Name(language_server_name) => {
4223 proto::language_server_selector::Selector::Name(
4224 language_server_name.to_string(),
4225 )
4226 }
4227 };
4228 proto::LanguageServerSelector {
4229 selector: Some(selector),
4230 }
4231 })
4232 .collect(),
4233 })
4234 .await
4235 })
4236 .detach();
4237 } else {
4238 // Our remote connection got closed
4239 }
4240 handle
4241 }
4242
4243 fn maintain_buffer_languages(
4244 languages: Arc<LanguageRegistry>,
4245 cx: &mut Context<Self>,
4246 ) -> Task<()> {
4247 let mut subscription = languages.subscribe();
4248 let mut prev_reload_count = languages.reload_count();
4249 cx.spawn(async move |this, cx| {
4250 while let Some(()) = subscription.next().await {
4251 if let Some(this) = this.upgrade() {
4252 // If the language registry has been reloaded, then remove and
4253 // re-assign the languages on all open buffers.
4254 let reload_count = languages.reload_count();
4255 if reload_count > prev_reload_count {
4256 prev_reload_count = reload_count;
4257 this.update(cx, |this, cx| {
4258 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4259 for buffer in buffer_store.buffers() {
4260 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4261 {
4262 buffer
4263 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4264 if let Some(local) = this.as_local_mut() {
4265 local.reset_buffer(&buffer, &f, cx);
4266
4267 if local
4268 .registered_buffers
4269 .contains_key(&buffer.read(cx).remote_id())
4270 && let Some(file_url) =
4271 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4272 {
4273 local.unregister_buffer_from_language_servers(
4274 &buffer, &file_url, cx,
4275 );
4276 }
4277 }
4278 }
4279 }
4280 });
4281 })
4282 .ok();
4283 }
4284
4285 this.update(cx, |this, cx| {
4286 let mut plain_text_buffers = Vec::new();
4287 let mut buffers_with_unknown_injections = Vec::new();
4288 for handle in this.buffer_store.read(cx).buffers() {
4289 let buffer = handle.read(cx);
4290 if buffer.language().is_none()
4291 || buffer.language() == Some(&*language::PLAIN_TEXT)
4292 {
4293 plain_text_buffers.push(handle);
4294 } else if buffer.contains_unknown_injections() {
4295 buffers_with_unknown_injections.push(handle);
4296 }
4297 }
4298
4299 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4300 // and reused later in the invisible worktrees.
4301 plain_text_buffers.sort_by_key(|buffer| {
4302 Reverse(
4303 File::from_dyn(buffer.read(cx).file())
4304 .map(|file| file.worktree.read(cx).is_visible()),
4305 )
4306 });
4307
4308 for buffer in plain_text_buffers {
4309 this.detect_language_for_buffer(&buffer, cx);
4310 if let Some(local) = this.as_local_mut() {
4311 local.initialize_buffer(&buffer, cx);
4312 if local
4313 .registered_buffers
4314 .contains_key(&buffer.read(cx).remote_id())
4315 {
4316 local.register_buffer_with_language_servers(
4317 &buffer,
4318 HashSet::default(),
4319 cx,
4320 );
4321 }
4322 }
4323 }
4324
4325 for buffer in buffers_with_unknown_injections {
4326 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4327 }
4328 })
4329 .ok();
4330 }
4331 }
4332 })
4333 }
4334
4335 fn detect_language_for_buffer(
4336 &mut self,
4337 buffer_handle: &Entity<Buffer>,
4338 cx: &mut Context<Self>,
4339 ) -> Option<language::AvailableLanguage> {
4340 // If the buffer has a language, set it and start the language server if we haven't already.
4341 let buffer = buffer_handle.read(cx);
4342 let file = buffer.file()?;
4343
4344 let content = buffer.as_rope();
4345 let available_language = self.languages.language_for_file(file, Some(content), cx);
4346 if let Some(available_language) = &available_language {
4347 if let Some(Ok(Ok(new_language))) = self
4348 .languages
4349 .load_language(available_language)
4350 .now_or_never()
4351 {
4352 self.set_language_for_buffer(buffer_handle, new_language, cx);
4353 }
4354 } else {
4355 cx.emit(LspStoreEvent::LanguageDetected {
4356 buffer: buffer_handle.clone(),
4357 new_language: None,
4358 });
4359 }
4360
4361 available_language
4362 }
4363
4364 pub(crate) fn set_language_for_buffer(
4365 &mut self,
4366 buffer_entity: &Entity<Buffer>,
4367 new_language: Arc<Language>,
4368 cx: &mut Context<Self>,
4369 ) {
4370 let buffer = buffer_entity.read(cx);
4371 let buffer_file = buffer.file().cloned();
4372 let buffer_id = buffer.remote_id();
4373 if let Some(local_store) = self.as_local_mut()
4374 && local_store.registered_buffers.contains_key(&buffer_id)
4375 && let Some(abs_path) =
4376 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4377 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4378 {
4379 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4380 }
4381 buffer_entity.update(cx, |buffer, cx| {
4382 if buffer
4383 .language()
4384 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4385 {
4386 buffer.set_language(Some(new_language.clone()), cx);
4387 }
4388 });
4389
4390 let settings =
4391 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4392 let buffer_file = File::from_dyn(buffer_file.as_ref());
4393
4394 let worktree_id = if let Some(file) = buffer_file {
4395 let worktree = file.worktree.clone();
4396
4397 if let Some(local) = self.as_local_mut()
4398 && local.registered_buffers.contains_key(&buffer_id)
4399 {
4400 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4401 }
4402 Some(worktree.read(cx).id())
4403 } else {
4404 None
4405 };
4406
4407 if settings.prettier.allowed
4408 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4409 {
4410 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4411 if let Some(prettier_store) = prettier_store {
4412 prettier_store.update(cx, |prettier_store, cx| {
4413 prettier_store.install_default_prettier(
4414 worktree_id,
4415 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4416 cx,
4417 )
4418 })
4419 }
4420 }
4421
4422 cx.emit(LspStoreEvent::LanguageDetected {
4423 buffer: buffer_entity.clone(),
4424 new_language: Some(new_language),
4425 })
4426 }
4427
4428 pub fn buffer_store(&self) -> Entity<BufferStore> {
4429 self.buffer_store.clone()
4430 }
4431
4432 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4433 self.active_entry = active_entry;
4434 }
4435
4436 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4437 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4438 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4439 {
4440 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4441 summaries
4442 .iter()
4443 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4444 });
4445 if let Some(summary) = summaries.next() {
4446 client
4447 .send(proto::UpdateDiagnosticSummary {
4448 project_id: downstream_project_id,
4449 worktree_id: worktree.id().to_proto(),
4450 summary: Some(summary),
4451 more_summaries: summaries.collect(),
4452 })
4453 .log_err();
4454 }
4455 }
4456 }
4457
4458 fn is_capable_for_proto_request<R>(
4459 &self,
4460 buffer: &Entity<Buffer>,
4461 request: &R,
4462 cx: &App,
4463 ) -> bool
4464 where
4465 R: LspCommand,
4466 {
4467 self.check_if_capable_for_proto_request(
4468 buffer,
4469 |capabilities| {
4470 request.check_capabilities(AdapterServerCapabilities {
4471 server_capabilities: capabilities.clone(),
4472 code_action_kinds: None,
4473 })
4474 },
4475 cx,
4476 )
4477 }
4478
4479 fn check_if_capable_for_proto_request<F>(
4480 &self,
4481 buffer: &Entity<Buffer>,
4482 check: F,
4483 cx: &App,
4484 ) -> bool
4485 where
4486 F: FnMut(&lsp::ServerCapabilities) -> bool,
4487 {
4488 let Some(language) = buffer.read(cx).language().cloned() else {
4489 return false;
4490 };
4491 let relevant_language_servers = self
4492 .languages
4493 .lsp_adapters(&language.name())
4494 .into_iter()
4495 .map(|lsp_adapter| lsp_adapter.name())
4496 .collect::<HashSet<_>>();
4497 self.language_server_statuses
4498 .iter()
4499 .filter_map(|(server_id, server_status)| {
4500 relevant_language_servers
4501 .contains(&server_status.name)
4502 .then_some(server_id)
4503 })
4504 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4505 .any(check)
4506 }
4507
4508 fn all_capable_for_proto_request<F>(
4509 &self,
4510 buffer: &Entity<Buffer>,
4511 mut check: F,
4512 cx: &App,
4513 ) -> Vec<lsp::LanguageServerId>
4514 where
4515 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4516 {
4517 let Some(language) = buffer.read(cx).language().cloned() else {
4518 return Vec::default();
4519 };
4520 let relevant_language_servers = self
4521 .languages
4522 .lsp_adapters(&language.name())
4523 .into_iter()
4524 .map(|lsp_adapter| lsp_adapter.name())
4525 .collect::<HashSet<_>>();
4526 self.language_server_statuses
4527 .iter()
4528 .filter_map(|(server_id, server_status)| {
4529 relevant_language_servers
4530 .contains(&server_status.name)
4531 .then_some((server_id, &server_status.name))
4532 })
4533 .filter_map(|(server_id, server_name)| {
4534 self.lsp_server_capabilities
4535 .get(server_id)
4536 .map(|c| (server_id, server_name, c))
4537 })
4538 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4539 .map(|(server_id, _, _)| *server_id)
4540 .collect()
4541 }
4542
4543 pub fn request_lsp<R>(
4544 &mut self,
4545 buffer: Entity<Buffer>,
4546 server: LanguageServerToQuery,
4547 request: R,
4548 cx: &mut Context<Self>,
4549 ) -> Task<Result<R::Response>>
4550 where
4551 R: LspCommand,
4552 <R::LspRequest as lsp::request::Request>::Result: Send,
4553 <R::LspRequest as lsp::request::Request>::Params: Send,
4554 {
4555 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4556 return self.send_lsp_proto_request(
4557 buffer,
4558 upstream_client,
4559 upstream_project_id,
4560 request,
4561 cx,
4562 );
4563 }
4564
4565 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4566 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4567 local
4568 .language_servers_for_buffer(buffer, cx)
4569 .find(|(_, server)| {
4570 request.check_capabilities(server.adapter_server_capabilities())
4571 })
4572 .map(|(_, server)| server.clone())
4573 }),
4574 LanguageServerToQuery::Other(id) => self
4575 .language_server_for_local_buffer(buffer, id, cx)
4576 .and_then(|(_, server)| {
4577 request
4578 .check_capabilities(server.adapter_server_capabilities())
4579 .then(|| Arc::clone(server))
4580 }),
4581 }) else {
4582 return Task::ready(Ok(Default::default()));
4583 };
4584
4585 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4586
4587 let Some(file) = file else {
4588 return Task::ready(Ok(Default::default()));
4589 };
4590
4591 let lsp_params = match request.to_lsp_params_or_response(
4592 &file.abs_path(cx),
4593 buffer.read(cx),
4594 &language_server,
4595 cx,
4596 ) {
4597 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4598 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4599 Err(err) => {
4600 let message = format!(
4601 "{} via {} failed: {}",
4602 request.display_name(),
4603 language_server.name(),
4604 err
4605 );
4606 // rust-analyzer likes to error with this when its still loading up
4607 if !message.ends_with("content modified") {
4608 log::warn!("{message}");
4609 }
4610 return Task::ready(Err(anyhow!(message)));
4611 }
4612 };
4613
4614 let status = request.status();
4615 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4616 return Task::ready(Ok(Default::default()));
4617 }
4618 cx.spawn(async move |this, cx| {
4619 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4620
4621 let id = lsp_request.id();
4622 let _cleanup = if status.is_some() {
4623 cx.update(|cx| {
4624 this.update(cx, |this, cx| {
4625 this.on_lsp_work_start(
4626 language_server.server_id(),
4627 ProgressToken::Number(id),
4628 LanguageServerProgress {
4629 is_disk_based_diagnostics_progress: false,
4630 is_cancellable: false,
4631 title: None,
4632 message: status.clone(),
4633 percentage: None,
4634 last_update_at: cx.background_executor().now(),
4635 },
4636 cx,
4637 );
4638 })
4639 })
4640 .log_err();
4641
4642 Some(defer(|| {
4643 cx.update(|cx| {
4644 this.update(cx, |this, cx| {
4645 this.on_lsp_work_end(
4646 language_server.server_id(),
4647 ProgressToken::Number(id),
4648 cx,
4649 );
4650 })
4651 })
4652 .log_err();
4653 }))
4654 } else {
4655 None
4656 };
4657
4658 let result = lsp_request.await.into_response();
4659
4660 let response = result.map_err(|err| {
4661 let message = format!(
4662 "{} via {} failed: {}",
4663 request.display_name(),
4664 language_server.name(),
4665 err
4666 );
4667 // rust-analyzer likes to error with this when its still loading up
4668 if !message.ends_with("content modified") {
4669 log::warn!("{message}");
4670 }
4671 anyhow::anyhow!(message)
4672 })?;
4673
4674 request
4675 .response_from_lsp(
4676 response,
4677 this.upgrade().context("no app context")?,
4678 buffer,
4679 language_server.server_id(),
4680 cx.clone(),
4681 )
4682 .await
4683 })
4684 }
4685
4686 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4687 let mut language_formatters_to_check = Vec::new();
4688 for buffer in self.buffer_store.read(cx).buffers() {
4689 let buffer = buffer.read(cx);
4690 let buffer_file = File::from_dyn(buffer.file());
4691 let buffer_language = buffer.language();
4692 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4693 if buffer_language.is_some() {
4694 language_formatters_to_check.push((
4695 buffer_file.map(|f| f.worktree_id(cx)),
4696 settings.into_owned(),
4697 ));
4698 }
4699 }
4700
4701 self.request_workspace_config_refresh();
4702
4703 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4704 prettier_store.update(cx, |prettier_store, cx| {
4705 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4706 })
4707 }
4708
4709 cx.notify();
4710 }
4711
4712 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4713 let buffer_store = self.buffer_store.clone();
4714 let Some(local) = self.as_local_mut() else {
4715 return;
4716 };
4717 let mut adapters = BTreeMap::default();
4718 let get_adapter = {
4719 let languages = local.languages.clone();
4720 let environment = local.environment.clone();
4721 let weak = local.weak.clone();
4722 let worktree_store = local.worktree_store.clone();
4723 let http_client = local.http_client.clone();
4724 let fs = local.fs.clone();
4725 move |worktree_id, cx: &mut App| {
4726 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4727 Some(LocalLspAdapterDelegate::new(
4728 languages.clone(),
4729 &environment,
4730 weak.clone(),
4731 &worktree,
4732 http_client.clone(),
4733 fs.clone(),
4734 cx,
4735 ))
4736 }
4737 };
4738
4739 let mut messages_to_report = Vec::new();
4740 let (new_tree, to_stop) = {
4741 let mut rebase = local.lsp_tree.rebase();
4742 let buffers = buffer_store
4743 .read(cx)
4744 .buffers()
4745 .filter_map(|buffer| {
4746 let raw_buffer = buffer.read(cx);
4747 if !local
4748 .registered_buffers
4749 .contains_key(&raw_buffer.remote_id())
4750 {
4751 return None;
4752 }
4753 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4754 let language = raw_buffer.language().cloned()?;
4755 Some((file, language, raw_buffer.remote_id()))
4756 })
4757 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4758 for (file, language, buffer_id) in buffers {
4759 let worktree_id = file.worktree_id(cx);
4760 let Some(worktree) = local
4761 .worktree_store
4762 .read(cx)
4763 .worktree_for_id(worktree_id, cx)
4764 else {
4765 continue;
4766 };
4767
4768 if let Some((_, apply)) = local.reuse_existing_language_server(
4769 rebase.server_tree(),
4770 &worktree,
4771 &language.name(),
4772 cx,
4773 ) {
4774 (apply)(rebase.server_tree());
4775 } else if let Some(lsp_delegate) = adapters
4776 .entry(worktree_id)
4777 .or_insert_with(|| get_adapter(worktree_id, cx))
4778 .clone()
4779 {
4780 let delegate =
4781 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4782 let path = file
4783 .path()
4784 .parent()
4785 .map(Arc::from)
4786 .unwrap_or_else(|| file.path().clone());
4787 let worktree_path = ProjectPath { worktree_id, path };
4788 let abs_path = file.abs_path(cx);
4789 let nodes = rebase
4790 .walk(
4791 worktree_path,
4792 language.name(),
4793 language.manifest(),
4794 delegate.clone(),
4795 cx,
4796 )
4797 .collect::<Vec<_>>();
4798 for node in nodes {
4799 let server_id = node.server_id_or_init(|disposition| {
4800 let path = &disposition.path;
4801 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4802 let key = LanguageServerSeed {
4803 worktree_id,
4804 name: disposition.server_name.clone(),
4805 settings: disposition.settings.clone(),
4806 toolchain: local.toolchain_store.read(cx).active_toolchain(
4807 path.worktree_id,
4808 &path.path,
4809 language.name(),
4810 ),
4811 };
4812 local.language_server_ids.remove(&key);
4813
4814 let server_id = local.get_or_insert_language_server(
4815 &worktree,
4816 lsp_delegate.clone(),
4817 disposition,
4818 &language.name(),
4819 cx,
4820 );
4821 if let Some(state) = local.language_servers.get(&server_id)
4822 && let Ok(uri) = uri
4823 {
4824 state.add_workspace_folder(uri);
4825 };
4826 server_id
4827 });
4828
4829 if let Some(language_server_id) = server_id {
4830 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4831 language_server_id,
4832 name: node.name(),
4833 message:
4834 proto::update_language_server::Variant::RegisteredForBuffer(
4835 proto::RegisteredForBuffer {
4836 buffer_abs_path: abs_path
4837 .to_string_lossy()
4838 .into_owned(),
4839 buffer_id: buffer_id.to_proto(),
4840 },
4841 ),
4842 });
4843 }
4844 }
4845 } else {
4846 continue;
4847 }
4848 }
4849 rebase.finish()
4850 };
4851 for message in messages_to_report {
4852 cx.emit(message);
4853 }
4854 local.lsp_tree = new_tree;
4855 for (id, _) in to_stop {
4856 self.stop_local_language_server(id, cx).detach();
4857 }
4858 }
4859
4860 pub fn apply_code_action(
4861 &self,
4862 buffer_handle: Entity<Buffer>,
4863 mut action: CodeAction,
4864 push_to_history: bool,
4865 cx: &mut Context<Self>,
4866 ) -> Task<Result<ProjectTransaction>> {
4867 if let Some((upstream_client, project_id)) = self.upstream_client() {
4868 let request = proto::ApplyCodeAction {
4869 project_id,
4870 buffer_id: buffer_handle.read(cx).remote_id().into(),
4871 action: Some(Self::serialize_code_action(&action)),
4872 };
4873 let buffer_store = self.buffer_store();
4874 cx.spawn(async move |_, cx| {
4875 let response = upstream_client
4876 .request(request)
4877 .await?
4878 .transaction
4879 .context("missing transaction")?;
4880
4881 buffer_store
4882 .update(cx, |buffer_store, cx| {
4883 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4884 })?
4885 .await
4886 })
4887 } else if self.mode.is_local() {
4888 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4889 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4890 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4891 }) else {
4892 return Task::ready(Ok(ProjectTransaction::default()));
4893 };
4894 cx.spawn(async move |this, cx| {
4895 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4896 .await
4897 .context("resolving a code action")?;
4898 if let Some(edit) = action.lsp_action.edit()
4899 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4900 return LocalLspStore::deserialize_workspace_edit(
4901 this.upgrade().context("no app present")?,
4902 edit.clone(),
4903 push_to_history,
4904
4905 lang_server.clone(),
4906 cx,
4907 )
4908 .await;
4909 }
4910
4911 if let Some(command) = action.lsp_action.command() {
4912 let server_capabilities = lang_server.capabilities();
4913 let available_commands = server_capabilities
4914 .execute_command_provider
4915 .as_ref()
4916 .map(|options| options.commands.as_slice())
4917 .unwrap_or_default();
4918 if available_commands.contains(&command.command) {
4919 this.update(cx, |this, _| {
4920 this.as_local_mut()
4921 .unwrap()
4922 .last_workspace_edits_by_language_server
4923 .remove(&lang_server.server_id());
4924 })?;
4925
4926 let _result = lang_server
4927 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4928 command: command.command.clone(),
4929 arguments: command.arguments.clone().unwrap_or_default(),
4930 ..lsp::ExecuteCommandParams::default()
4931 })
4932 .await.into_response()
4933 .context("execute command")?;
4934
4935 return this.update(cx, |this, _| {
4936 this.as_local_mut()
4937 .unwrap()
4938 .last_workspace_edits_by_language_server
4939 .remove(&lang_server.server_id())
4940 .unwrap_or_default()
4941 });
4942 } else {
4943 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4944 }
4945 }
4946
4947 Ok(ProjectTransaction::default())
4948 })
4949 } else {
4950 Task::ready(Err(anyhow!("no upstream client and not local")))
4951 }
4952 }
4953
4954 pub fn apply_code_action_kind(
4955 &mut self,
4956 buffers: HashSet<Entity<Buffer>>,
4957 kind: CodeActionKind,
4958 push_to_history: bool,
4959 cx: &mut Context<Self>,
4960 ) -> Task<anyhow::Result<ProjectTransaction>> {
4961 if self.as_local().is_some() {
4962 cx.spawn(async move |lsp_store, cx| {
4963 let buffers = buffers.into_iter().collect::<Vec<_>>();
4964 let result = LocalLspStore::execute_code_action_kind_locally(
4965 lsp_store.clone(),
4966 buffers,
4967 kind,
4968 push_to_history,
4969 cx,
4970 )
4971 .await;
4972 lsp_store.update(cx, |lsp_store, _| {
4973 lsp_store.update_last_formatting_failure(&result);
4974 })?;
4975 result
4976 })
4977 } else if let Some((client, project_id)) = self.upstream_client() {
4978 let buffer_store = self.buffer_store();
4979 cx.spawn(async move |lsp_store, cx| {
4980 let result = client
4981 .request(proto::ApplyCodeActionKind {
4982 project_id,
4983 kind: kind.as_str().to_owned(),
4984 buffer_ids: buffers
4985 .iter()
4986 .map(|buffer| {
4987 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4988 })
4989 .collect::<Result<_>>()?,
4990 })
4991 .await
4992 .and_then(|result| result.transaction.context("missing transaction"));
4993 lsp_store.update(cx, |lsp_store, _| {
4994 lsp_store.update_last_formatting_failure(&result);
4995 })?;
4996
4997 let transaction_response = result?;
4998 buffer_store
4999 .update(cx, |buffer_store, cx| {
5000 buffer_store.deserialize_project_transaction(
5001 transaction_response,
5002 push_to_history,
5003 cx,
5004 )
5005 })?
5006 .await
5007 })
5008 } else {
5009 Task::ready(Ok(ProjectTransaction::default()))
5010 }
5011 }
5012
5013 pub fn resolved_hint(
5014 &mut self,
5015 buffer_id: BufferId,
5016 id: InlayId,
5017 cx: &mut Context<Self>,
5018 ) -> Option<ResolvedHint> {
5019 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5020
5021 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5022 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5023 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5024 let (server_id, resolve_data) = match &hint.resolve_state {
5025 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5026 ResolveState::Resolving => {
5027 return Some(ResolvedHint::Resolving(
5028 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5029 ));
5030 }
5031 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5032 };
5033
5034 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5035 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5036 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5037 id,
5038 cx.spawn(async move |lsp_store, cx| {
5039 let resolved_hint = resolve_task.await;
5040 lsp_store
5041 .update(cx, |lsp_store, _| {
5042 if let Some(old_inlay_hint) = lsp_store
5043 .lsp_data
5044 .get_mut(&buffer_id)
5045 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5046 {
5047 match resolved_hint {
5048 Ok(resolved_hint) => {
5049 *old_inlay_hint = resolved_hint;
5050 }
5051 Err(e) => {
5052 old_inlay_hint.resolve_state =
5053 ResolveState::CanResolve(server_id, resolve_data);
5054 log::error!("Inlay hint resolve failed: {e:#}");
5055 }
5056 }
5057 }
5058 })
5059 .ok();
5060 })
5061 .shared(),
5062 );
5063 debug_assert!(
5064 previous_task.is_none(),
5065 "Did not change hint's resolve state after spawning its resolve"
5066 );
5067 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5068 None
5069 }
5070
5071 fn resolve_inlay_hint(
5072 &self,
5073 mut hint: InlayHint,
5074 buffer: Entity<Buffer>,
5075 server_id: LanguageServerId,
5076 cx: &mut Context<Self>,
5077 ) -> Task<anyhow::Result<InlayHint>> {
5078 if let Some((upstream_client, project_id)) = self.upstream_client() {
5079 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5080 {
5081 hint.resolve_state = ResolveState::Resolved;
5082 return Task::ready(Ok(hint));
5083 }
5084 let request = proto::ResolveInlayHint {
5085 project_id,
5086 buffer_id: buffer.read(cx).remote_id().into(),
5087 language_server_id: server_id.0 as u64,
5088 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5089 };
5090 cx.background_spawn(async move {
5091 let response = upstream_client
5092 .request(request)
5093 .await
5094 .context("inlay hints proto request")?;
5095 match response.hint {
5096 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5097 .context("inlay hints proto resolve response conversion"),
5098 None => Ok(hint),
5099 }
5100 })
5101 } else {
5102 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5103 self.language_server_for_local_buffer(buffer, server_id, cx)
5104 .map(|(_, server)| server.clone())
5105 }) else {
5106 return Task::ready(Ok(hint));
5107 };
5108 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5109 return Task::ready(Ok(hint));
5110 }
5111 let buffer_snapshot = buffer.read(cx).snapshot();
5112 cx.spawn(async move |_, cx| {
5113 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5114 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5115 );
5116 let resolved_hint = resolve_task
5117 .await
5118 .into_response()
5119 .context("inlay hint resolve LSP request")?;
5120 let resolved_hint = InlayHints::lsp_to_project_hint(
5121 resolved_hint,
5122 &buffer,
5123 server_id,
5124 ResolveState::Resolved,
5125 false,
5126 cx,
5127 )
5128 .await?;
5129 Ok(resolved_hint)
5130 })
5131 }
5132 }
5133
5134 pub fn resolve_color_presentation(
5135 &mut self,
5136 mut color: DocumentColor,
5137 buffer: Entity<Buffer>,
5138 server_id: LanguageServerId,
5139 cx: &mut Context<Self>,
5140 ) -> Task<Result<DocumentColor>> {
5141 if color.resolved {
5142 return Task::ready(Ok(color));
5143 }
5144
5145 if let Some((upstream_client, project_id)) = self.upstream_client() {
5146 let start = color.lsp_range.start;
5147 let end = color.lsp_range.end;
5148 let request = proto::GetColorPresentation {
5149 project_id,
5150 server_id: server_id.to_proto(),
5151 buffer_id: buffer.read(cx).remote_id().into(),
5152 color: Some(proto::ColorInformation {
5153 red: color.color.red,
5154 green: color.color.green,
5155 blue: color.color.blue,
5156 alpha: color.color.alpha,
5157 lsp_range_start: Some(proto::PointUtf16 {
5158 row: start.line,
5159 column: start.character,
5160 }),
5161 lsp_range_end: Some(proto::PointUtf16 {
5162 row: end.line,
5163 column: end.character,
5164 }),
5165 }),
5166 };
5167 cx.background_spawn(async move {
5168 let response = upstream_client
5169 .request(request)
5170 .await
5171 .context("color presentation proto request")?;
5172 color.resolved = true;
5173 color.color_presentations = response
5174 .presentations
5175 .into_iter()
5176 .map(|presentation| ColorPresentation {
5177 label: SharedString::from(presentation.label),
5178 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5179 additional_text_edits: presentation
5180 .additional_text_edits
5181 .into_iter()
5182 .filter_map(deserialize_lsp_edit)
5183 .collect(),
5184 })
5185 .collect();
5186 Ok(color)
5187 })
5188 } else {
5189 let path = match buffer
5190 .update(cx, |buffer, cx| {
5191 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5192 })
5193 .context("buffer with the missing path")
5194 {
5195 Ok(path) => path,
5196 Err(e) => return Task::ready(Err(e)),
5197 };
5198 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5199 self.language_server_for_local_buffer(buffer, server_id, cx)
5200 .map(|(_, server)| server.clone())
5201 }) else {
5202 return Task::ready(Ok(color));
5203 };
5204 cx.background_spawn(async move {
5205 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5206 lsp::ColorPresentationParams {
5207 text_document: make_text_document_identifier(&path)?,
5208 color: color.color,
5209 range: color.lsp_range,
5210 work_done_progress_params: Default::default(),
5211 partial_result_params: Default::default(),
5212 },
5213 );
5214 color.color_presentations = resolve_task
5215 .await
5216 .into_response()
5217 .context("color presentation resolve LSP request")?
5218 .into_iter()
5219 .map(|presentation| ColorPresentation {
5220 label: SharedString::from(presentation.label),
5221 text_edit: presentation.text_edit,
5222 additional_text_edits: presentation
5223 .additional_text_edits
5224 .unwrap_or_default(),
5225 })
5226 .collect();
5227 color.resolved = true;
5228 Ok(color)
5229 })
5230 }
5231 }
5232
5233 pub(crate) fn linked_edits(
5234 &mut self,
5235 buffer: &Entity<Buffer>,
5236 position: Anchor,
5237 cx: &mut Context<Self>,
5238 ) -> Task<Result<Vec<Range<Anchor>>>> {
5239 let snapshot = buffer.read(cx).snapshot();
5240 let scope = snapshot.language_scope_at(position);
5241 let Some(server_id) = self
5242 .as_local()
5243 .and_then(|local| {
5244 buffer.update(cx, |buffer, cx| {
5245 local
5246 .language_servers_for_buffer(buffer, cx)
5247 .filter(|(_, server)| {
5248 LinkedEditingRange::check_server_capabilities(server.capabilities())
5249 })
5250 .filter(|(adapter, _)| {
5251 scope
5252 .as_ref()
5253 .map(|scope| scope.language_allowed(&adapter.name))
5254 .unwrap_or(true)
5255 })
5256 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5257 .next()
5258 })
5259 })
5260 .or_else(|| {
5261 self.upstream_client()
5262 .is_some()
5263 .then_some(LanguageServerToQuery::FirstCapable)
5264 })
5265 .filter(|_| {
5266 maybe!({
5267 let language = buffer.read(cx).language_at(position)?;
5268 Some(
5269 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5270 .linked_edits,
5271 )
5272 }) == Some(true)
5273 })
5274 else {
5275 return Task::ready(Ok(Vec::new()));
5276 };
5277
5278 self.request_lsp(
5279 buffer.clone(),
5280 server_id,
5281 LinkedEditingRange { position },
5282 cx,
5283 )
5284 }
5285
5286 fn apply_on_type_formatting(
5287 &mut self,
5288 buffer: Entity<Buffer>,
5289 position: Anchor,
5290 trigger: String,
5291 cx: &mut Context<Self>,
5292 ) -> Task<Result<Option<Transaction>>> {
5293 if let Some((client, project_id)) = self.upstream_client() {
5294 if !self.check_if_capable_for_proto_request(
5295 &buffer,
5296 |capabilities| {
5297 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5298 },
5299 cx,
5300 ) {
5301 return Task::ready(Ok(None));
5302 }
5303 let request = proto::OnTypeFormatting {
5304 project_id,
5305 buffer_id: buffer.read(cx).remote_id().into(),
5306 position: Some(serialize_anchor(&position)),
5307 trigger,
5308 version: serialize_version(&buffer.read(cx).version()),
5309 };
5310 cx.background_spawn(async move {
5311 client
5312 .request(request)
5313 .await?
5314 .transaction
5315 .map(language::proto::deserialize_transaction)
5316 .transpose()
5317 })
5318 } else if let Some(local) = self.as_local_mut() {
5319 let buffer_id = buffer.read(cx).remote_id();
5320 local.buffers_being_formatted.insert(buffer_id);
5321 cx.spawn(async move |this, cx| {
5322 let _cleanup = defer({
5323 let this = this.clone();
5324 let mut cx = cx.clone();
5325 move || {
5326 this.update(&mut cx, |this, _| {
5327 if let Some(local) = this.as_local_mut() {
5328 local.buffers_being_formatted.remove(&buffer_id);
5329 }
5330 })
5331 .ok();
5332 }
5333 });
5334
5335 buffer
5336 .update(cx, |buffer, _| {
5337 buffer.wait_for_edits(Some(position.timestamp))
5338 })?
5339 .await?;
5340 this.update(cx, |this, cx| {
5341 let position = position.to_point_utf16(buffer.read(cx));
5342 this.on_type_format(buffer, position, trigger, false, cx)
5343 })?
5344 .await
5345 })
5346 } else {
5347 Task::ready(Err(anyhow!("No upstream client or local language server")))
5348 }
5349 }
5350
5351 pub fn on_type_format<T: ToPointUtf16>(
5352 &mut self,
5353 buffer: Entity<Buffer>,
5354 position: T,
5355 trigger: String,
5356 push_to_history: bool,
5357 cx: &mut Context<Self>,
5358 ) -> Task<Result<Option<Transaction>>> {
5359 let position = position.to_point_utf16(buffer.read(cx));
5360 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5361 }
5362
5363 fn on_type_format_impl(
5364 &mut self,
5365 buffer: Entity<Buffer>,
5366 position: PointUtf16,
5367 trigger: String,
5368 push_to_history: bool,
5369 cx: &mut Context<Self>,
5370 ) -> Task<Result<Option<Transaction>>> {
5371 let options = buffer.update(cx, |buffer, cx| {
5372 lsp_command::lsp_formatting_options(
5373 language_settings(
5374 buffer.language_at(position).map(|l| l.name()),
5375 buffer.file(),
5376 cx,
5377 )
5378 .as_ref(),
5379 )
5380 });
5381
5382 cx.spawn(async move |this, cx| {
5383 if let Some(waiter) =
5384 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5385 {
5386 waiter.await?;
5387 }
5388 cx.update(|cx| {
5389 this.update(cx, |this, cx| {
5390 this.request_lsp(
5391 buffer.clone(),
5392 LanguageServerToQuery::FirstCapable,
5393 OnTypeFormatting {
5394 position,
5395 trigger,
5396 options,
5397 push_to_history,
5398 },
5399 cx,
5400 )
5401 })
5402 })??
5403 .await
5404 })
5405 }
5406
5407 pub fn definitions(
5408 &mut self,
5409 buffer: &Entity<Buffer>,
5410 position: PointUtf16,
5411 cx: &mut Context<Self>,
5412 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5413 if let Some((upstream_client, project_id)) = self.upstream_client() {
5414 let request = GetDefinitions { position };
5415 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5416 return Task::ready(Ok(None));
5417 }
5418 let request_task = upstream_client.request_lsp(
5419 project_id,
5420 None,
5421 LSP_REQUEST_TIMEOUT,
5422 cx.background_executor().clone(),
5423 request.to_proto(project_id, buffer.read(cx)),
5424 );
5425 let buffer = buffer.clone();
5426 cx.spawn(async move |weak_lsp_store, cx| {
5427 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5428 return Ok(None);
5429 };
5430 let Some(responses) = request_task.await? else {
5431 return Ok(None);
5432 };
5433 let actions = join_all(responses.payload.into_iter().map(|response| {
5434 GetDefinitions { position }.response_from_proto(
5435 response.response,
5436 lsp_store.clone(),
5437 buffer.clone(),
5438 cx.clone(),
5439 )
5440 }))
5441 .await;
5442
5443 Ok(Some(
5444 actions
5445 .into_iter()
5446 .collect::<Result<Vec<Vec<_>>>>()?
5447 .into_iter()
5448 .flatten()
5449 .dedup()
5450 .collect(),
5451 ))
5452 })
5453 } else {
5454 let definitions_task = self.request_multiple_lsp_locally(
5455 buffer,
5456 Some(position),
5457 GetDefinitions { position },
5458 cx,
5459 );
5460 cx.background_spawn(async move {
5461 Ok(Some(
5462 definitions_task
5463 .await
5464 .into_iter()
5465 .flat_map(|(_, definitions)| definitions)
5466 .dedup()
5467 .collect(),
5468 ))
5469 })
5470 }
5471 }
5472
5473 pub fn declarations(
5474 &mut self,
5475 buffer: &Entity<Buffer>,
5476 position: PointUtf16,
5477 cx: &mut Context<Self>,
5478 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5479 if let Some((upstream_client, project_id)) = self.upstream_client() {
5480 let request = GetDeclarations { position };
5481 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5482 return Task::ready(Ok(None));
5483 }
5484 let request_task = upstream_client.request_lsp(
5485 project_id,
5486 None,
5487 LSP_REQUEST_TIMEOUT,
5488 cx.background_executor().clone(),
5489 request.to_proto(project_id, buffer.read(cx)),
5490 );
5491 let buffer = buffer.clone();
5492 cx.spawn(async move |weak_lsp_store, cx| {
5493 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5494 return Ok(None);
5495 };
5496 let Some(responses) = request_task.await? else {
5497 return Ok(None);
5498 };
5499 let actions = join_all(responses.payload.into_iter().map(|response| {
5500 GetDeclarations { position }.response_from_proto(
5501 response.response,
5502 lsp_store.clone(),
5503 buffer.clone(),
5504 cx.clone(),
5505 )
5506 }))
5507 .await;
5508
5509 Ok(Some(
5510 actions
5511 .into_iter()
5512 .collect::<Result<Vec<Vec<_>>>>()?
5513 .into_iter()
5514 .flatten()
5515 .dedup()
5516 .collect(),
5517 ))
5518 })
5519 } else {
5520 let declarations_task = self.request_multiple_lsp_locally(
5521 buffer,
5522 Some(position),
5523 GetDeclarations { position },
5524 cx,
5525 );
5526 cx.background_spawn(async move {
5527 Ok(Some(
5528 declarations_task
5529 .await
5530 .into_iter()
5531 .flat_map(|(_, declarations)| declarations)
5532 .dedup()
5533 .collect(),
5534 ))
5535 })
5536 }
5537 }
5538
5539 pub fn type_definitions(
5540 &mut self,
5541 buffer: &Entity<Buffer>,
5542 position: PointUtf16,
5543 cx: &mut Context<Self>,
5544 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5545 if let Some((upstream_client, project_id)) = self.upstream_client() {
5546 let request = GetTypeDefinitions { position };
5547 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5548 return Task::ready(Ok(None));
5549 }
5550 let request_task = upstream_client.request_lsp(
5551 project_id,
5552 None,
5553 LSP_REQUEST_TIMEOUT,
5554 cx.background_executor().clone(),
5555 request.to_proto(project_id, buffer.read(cx)),
5556 );
5557 let buffer = buffer.clone();
5558 cx.spawn(async move |weak_lsp_store, cx| {
5559 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5560 return Ok(None);
5561 };
5562 let Some(responses) = request_task.await? else {
5563 return Ok(None);
5564 };
5565 let actions = join_all(responses.payload.into_iter().map(|response| {
5566 GetTypeDefinitions { position }.response_from_proto(
5567 response.response,
5568 lsp_store.clone(),
5569 buffer.clone(),
5570 cx.clone(),
5571 )
5572 }))
5573 .await;
5574
5575 Ok(Some(
5576 actions
5577 .into_iter()
5578 .collect::<Result<Vec<Vec<_>>>>()?
5579 .into_iter()
5580 .flatten()
5581 .dedup()
5582 .collect(),
5583 ))
5584 })
5585 } else {
5586 let type_definitions_task = self.request_multiple_lsp_locally(
5587 buffer,
5588 Some(position),
5589 GetTypeDefinitions { position },
5590 cx,
5591 );
5592 cx.background_spawn(async move {
5593 Ok(Some(
5594 type_definitions_task
5595 .await
5596 .into_iter()
5597 .flat_map(|(_, type_definitions)| type_definitions)
5598 .dedup()
5599 .collect(),
5600 ))
5601 })
5602 }
5603 }
5604
5605 pub fn implementations(
5606 &mut self,
5607 buffer: &Entity<Buffer>,
5608 position: PointUtf16,
5609 cx: &mut Context<Self>,
5610 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5611 if let Some((upstream_client, project_id)) = self.upstream_client() {
5612 let request = GetImplementations { position };
5613 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5614 return Task::ready(Ok(None));
5615 }
5616 let request_task = upstream_client.request_lsp(
5617 project_id,
5618 None,
5619 LSP_REQUEST_TIMEOUT,
5620 cx.background_executor().clone(),
5621 request.to_proto(project_id, buffer.read(cx)),
5622 );
5623 let buffer = buffer.clone();
5624 cx.spawn(async move |weak_lsp_store, cx| {
5625 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5626 return Ok(None);
5627 };
5628 let Some(responses) = request_task.await? else {
5629 return Ok(None);
5630 };
5631 let actions = join_all(responses.payload.into_iter().map(|response| {
5632 GetImplementations { position }.response_from_proto(
5633 response.response,
5634 lsp_store.clone(),
5635 buffer.clone(),
5636 cx.clone(),
5637 )
5638 }))
5639 .await;
5640
5641 Ok(Some(
5642 actions
5643 .into_iter()
5644 .collect::<Result<Vec<Vec<_>>>>()?
5645 .into_iter()
5646 .flatten()
5647 .dedup()
5648 .collect(),
5649 ))
5650 })
5651 } else {
5652 let implementations_task = self.request_multiple_lsp_locally(
5653 buffer,
5654 Some(position),
5655 GetImplementations { position },
5656 cx,
5657 );
5658 cx.background_spawn(async move {
5659 Ok(Some(
5660 implementations_task
5661 .await
5662 .into_iter()
5663 .flat_map(|(_, implementations)| implementations)
5664 .dedup()
5665 .collect(),
5666 ))
5667 })
5668 }
5669 }
5670
5671 pub fn references(
5672 &mut self,
5673 buffer: &Entity<Buffer>,
5674 position: PointUtf16,
5675 cx: &mut Context<Self>,
5676 ) -> Task<Result<Option<Vec<Location>>>> {
5677 if let Some((upstream_client, project_id)) = self.upstream_client() {
5678 let request = GetReferences { position };
5679 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5680 return Task::ready(Ok(None));
5681 }
5682
5683 let request_task = upstream_client.request_lsp(
5684 project_id,
5685 None,
5686 LSP_REQUEST_TIMEOUT,
5687 cx.background_executor().clone(),
5688 request.to_proto(project_id, buffer.read(cx)),
5689 );
5690 let buffer = buffer.clone();
5691 cx.spawn(async move |weak_lsp_store, cx| {
5692 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5693 return Ok(None);
5694 };
5695 let Some(responses) = request_task.await? else {
5696 return Ok(None);
5697 };
5698
5699 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5700 GetReferences { position }.response_from_proto(
5701 lsp_response.response,
5702 lsp_store.clone(),
5703 buffer.clone(),
5704 cx.clone(),
5705 )
5706 }))
5707 .await
5708 .into_iter()
5709 .collect::<Result<Vec<Vec<_>>>>()?
5710 .into_iter()
5711 .flatten()
5712 .dedup()
5713 .collect();
5714 Ok(Some(locations))
5715 })
5716 } else {
5717 let references_task = self.request_multiple_lsp_locally(
5718 buffer,
5719 Some(position),
5720 GetReferences { position },
5721 cx,
5722 );
5723 cx.background_spawn(async move {
5724 Ok(Some(
5725 references_task
5726 .await
5727 .into_iter()
5728 .flat_map(|(_, references)| references)
5729 .dedup()
5730 .collect(),
5731 ))
5732 })
5733 }
5734 }
5735
5736 pub fn code_actions(
5737 &mut self,
5738 buffer: &Entity<Buffer>,
5739 range: Range<Anchor>,
5740 kinds: Option<Vec<CodeActionKind>>,
5741 cx: &mut Context<Self>,
5742 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5743 if let Some((upstream_client, project_id)) = self.upstream_client() {
5744 let request = GetCodeActions {
5745 range: range.clone(),
5746 kinds: kinds.clone(),
5747 };
5748 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5749 return Task::ready(Ok(None));
5750 }
5751 let request_task = upstream_client.request_lsp(
5752 project_id,
5753 None,
5754 LSP_REQUEST_TIMEOUT,
5755 cx.background_executor().clone(),
5756 request.to_proto(project_id, buffer.read(cx)),
5757 );
5758 let buffer = buffer.clone();
5759 cx.spawn(async move |weak_lsp_store, cx| {
5760 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5761 return Ok(None);
5762 };
5763 let Some(responses) = request_task.await? else {
5764 return Ok(None);
5765 };
5766 let actions = join_all(responses.payload.into_iter().map(|response| {
5767 GetCodeActions {
5768 range: range.clone(),
5769 kinds: kinds.clone(),
5770 }
5771 .response_from_proto(
5772 response.response,
5773 lsp_store.clone(),
5774 buffer.clone(),
5775 cx.clone(),
5776 )
5777 }))
5778 .await;
5779
5780 Ok(Some(
5781 actions
5782 .into_iter()
5783 .collect::<Result<Vec<Vec<_>>>>()?
5784 .into_iter()
5785 .flatten()
5786 .collect(),
5787 ))
5788 })
5789 } else {
5790 let all_actions_task = self.request_multiple_lsp_locally(
5791 buffer,
5792 Some(range.start),
5793 GetCodeActions { range, kinds },
5794 cx,
5795 );
5796 cx.background_spawn(async move {
5797 Ok(Some(
5798 all_actions_task
5799 .await
5800 .into_iter()
5801 .flat_map(|(_, actions)| actions)
5802 .collect(),
5803 ))
5804 })
5805 }
5806 }
5807
5808 pub fn code_lens_actions(
5809 &mut self,
5810 buffer: &Entity<Buffer>,
5811 cx: &mut Context<Self>,
5812 ) -> CodeLensTask {
5813 let version_queried_for = buffer.read(cx).version();
5814 let buffer_id = buffer.read(cx).remote_id();
5815 let existing_servers = self.as_local().map(|local| {
5816 local
5817 .buffers_opened_in_servers
5818 .get(&buffer_id)
5819 .cloned()
5820 .unwrap_or_default()
5821 });
5822
5823 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5824 if let Some(cached_lens) = &lsp_data.code_lens {
5825 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5826 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5827 existing_servers != cached_lens.lens.keys().copied().collect()
5828 });
5829 if !has_different_servers {
5830 return Task::ready(Ok(Some(
5831 cached_lens.lens.values().flatten().cloned().collect(),
5832 )))
5833 .shared();
5834 }
5835 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5836 if !version_queried_for.changed_since(updating_for) {
5837 return running_update.clone();
5838 }
5839 }
5840 }
5841 }
5842
5843 let lens_lsp_data = self
5844 .latest_lsp_data(buffer, cx)
5845 .code_lens
5846 .get_or_insert_default();
5847 let buffer = buffer.clone();
5848 let query_version_queried_for = version_queried_for.clone();
5849 let new_task = cx
5850 .spawn(async move |lsp_store, cx| {
5851 cx.background_executor()
5852 .timer(Duration::from_millis(30))
5853 .await;
5854 let fetched_lens = lsp_store
5855 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5856 .map_err(Arc::new)?
5857 .await
5858 .context("fetching code lens")
5859 .map_err(Arc::new);
5860 let fetched_lens = match fetched_lens {
5861 Ok(fetched_lens) => fetched_lens,
5862 Err(e) => {
5863 lsp_store
5864 .update(cx, |lsp_store, _| {
5865 if let Some(lens_lsp_data) = lsp_store
5866 .lsp_data
5867 .get_mut(&buffer_id)
5868 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5869 {
5870 lens_lsp_data.update = None;
5871 }
5872 })
5873 .ok();
5874 return Err(e);
5875 }
5876 };
5877
5878 lsp_store
5879 .update(cx, |lsp_store, _| {
5880 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5881 let code_lens = lsp_data.code_lens.as_mut()?;
5882 if let Some(fetched_lens) = fetched_lens {
5883 if lsp_data.buffer_version == query_version_queried_for {
5884 code_lens.lens.extend(fetched_lens);
5885 } else if !lsp_data
5886 .buffer_version
5887 .changed_since(&query_version_queried_for)
5888 {
5889 lsp_data.buffer_version = query_version_queried_for;
5890 code_lens.lens = fetched_lens;
5891 }
5892 }
5893 code_lens.update = None;
5894 Some(code_lens.lens.values().flatten().cloned().collect())
5895 })
5896 .map_err(Arc::new)
5897 })
5898 .shared();
5899 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5900 new_task
5901 }
5902
5903 fn fetch_code_lens(
5904 &mut self,
5905 buffer: &Entity<Buffer>,
5906 cx: &mut Context<Self>,
5907 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5908 if let Some((upstream_client, project_id)) = self.upstream_client() {
5909 let request = GetCodeLens;
5910 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5911 return Task::ready(Ok(None));
5912 }
5913 let request_task = upstream_client.request_lsp(
5914 project_id,
5915 None,
5916 LSP_REQUEST_TIMEOUT,
5917 cx.background_executor().clone(),
5918 request.to_proto(project_id, buffer.read(cx)),
5919 );
5920 let buffer = buffer.clone();
5921 cx.spawn(async move |weak_lsp_store, cx| {
5922 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5923 return Ok(None);
5924 };
5925 let Some(responses) = request_task.await? else {
5926 return Ok(None);
5927 };
5928
5929 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5930 let lsp_store = lsp_store.clone();
5931 let buffer = buffer.clone();
5932 let cx = cx.clone();
5933 async move {
5934 (
5935 LanguageServerId::from_proto(response.server_id),
5936 GetCodeLens
5937 .response_from_proto(response.response, lsp_store, buffer, cx)
5938 .await,
5939 )
5940 }
5941 }))
5942 .await;
5943
5944 let mut has_errors = false;
5945 let code_lens_actions = code_lens_actions
5946 .into_iter()
5947 .filter_map(|(server_id, code_lens)| match code_lens {
5948 Ok(code_lens) => Some((server_id, code_lens)),
5949 Err(e) => {
5950 has_errors = true;
5951 log::error!("{e:#}");
5952 None
5953 }
5954 })
5955 .collect::<HashMap<_, _>>();
5956 anyhow::ensure!(
5957 !has_errors || !code_lens_actions.is_empty(),
5958 "Failed to fetch code lens"
5959 );
5960 Ok(Some(code_lens_actions))
5961 })
5962 } else {
5963 let code_lens_actions_task =
5964 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5965 cx.background_spawn(async move {
5966 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5967 })
5968 }
5969 }
5970
5971 #[inline(never)]
5972 pub fn completions(
5973 &self,
5974 buffer: &Entity<Buffer>,
5975 position: PointUtf16,
5976 context: CompletionContext,
5977 cx: &mut Context<Self>,
5978 ) -> Task<Result<Vec<CompletionResponse>>> {
5979 let language_registry = self.languages.clone();
5980
5981 if let Some((upstream_client, project_id)) = self.upstream_client() {
5982 let snapshot = buffer.read(cx).snapshot();
5983 let offset = position.to_offset(&snapshot);
5984 let scope = snapshot.language_scope_at(offset);
5985 let capable_lsps = self.all_capable_for_proto_request(
5986 buffer,
5987 |server_name, capabilities| {
5988 capabilities.completion_provider.is_some()
5989 && scope
5990 .as_ref()
5991 .map(|scope| scope.language_allowed(server_name))
5992 .unwrap_or(true)
5993 },
5994 cx,
5995 );
5996 if capable_lsps.is_empty() {
5997 return Task::ready(Ok(Vec::new()));
5998 }
5999
6000 let language = buffer.read(cx).language().cloned();
6001
6002 // In the future, we should provide project guests with the names of LSP adapters,
6003 // so that they can use the correct LSP adapter when computing labels. For now,
6004 // guests just use the first LSP adapter associated with the buffer's language.
6005 let lsp_adapter = language.as_ref().and_then(|language| {
6006 language_registry
6007 .lsp_adapters(&language.name())
6008 .first()
6009 .cloned()
6010 });
6011
6012 let buffer = buffer.clone();
6013
6014 cx.spawn(async move |this, cx| {
6015 let requests = join_all(
6016 capable_lsps
6017 .into_iter()
6018 .map(|id| {
6019 let request = GetCompletions {
6020 position,
6021 context: context.clone(),
6022 server_id: Some(id),
6023 };
6024 let buffer = buffer.clone();
6025 let language = language.clone();
6026 let lsp_adapter = lsp_adapter.clone();
6027 let upstream_client = upstream_client.clone();
6028 let response = this
6029 .update(cx, |this, cx| {
6030 this.send_lsp_proto_request(
6031 buffer,
6032 upstream_client,
6033 project_id,
6034 request,
6035 cx,
6036 )
6037 })
6038 .log_err();
6039 async move {
6040 let response = response?.await.log_err()?;
6041
6042 let completions = populate_labels_for_completions(
6043 response.completions,
6044 language,
6045 lsp_adapter,
6046 )
6047 .await;
6048
6049 Some(CompletionResponse {
6050 completions,
6051 display_options: CompletionDisplayOptions::default(),
6052 is_incomplete: response.is_incomplete,
6053 })
6054 }
6055 })
6056 .collect::<Vec<_>>(),
6057 );
6058 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6059 })
6060 } else if let Some(local) = self.as_local() {
6061 let snapshot = buffer.read(cx).snapshot();
6062 let offset = position.to_offset(&snapshot);
6063 let scope = snapshot.language_scope_at(offset);
6064 let language = snapshot.language().cloned();
6065 let completion_settings = language_settings(
6066 language.as_ref().map(|language| language.name()),
6067 buffer.read(cx).file(),
6068 cx,
6069 )
6070 .completions
6071 .clone();
6072 if !completion_settings.lsp {
6073 return Task::ready(Ok(Vec::new()));
6074 }
6075
6076 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6077 local
6078 .language_servers_for_buffer(buffer, cx)
6079 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6080 .filter(|(adapter, _)| {
6081 scope
6082 .as_ref()
6083 .map(|scope| scope.language_allowed(&adapter.name))
6084 .unwrap_or(true)
6085 })
6086 .map(|(_, server)| server.server_id())
6087 .collect()
6088 });
6089
6090 let buffer = buffer.clone();
6091 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6092 let lsp_timeout = if lsp_timeout > 0 {
6093 Some(Duration::from_millis(lsp_timeout))
6094 } else {
6095 None
6096 };
6097 cx.spawn(async move |this, cx| {
6098 let mut tasks = Vec::with_capacity(server_ids.len());
6099 this.update(cx, |lsp_store, cx| {
6100 for server_id in server_ids {
6101 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6102 let lsp_timeout = lsp_timeout
6103 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6104 let mut timeout = cx.background_spawn(async move {
6105 match lsp_timeout {
6106 Some(lsp_timeout) => {
6107 lsp_timeout.await;
6108 true
6109 },
6110 None => false,
6111 }
6112 }).fuse();
6113 let mut lsp_request = lsp_store.request_lsp(
6114 buffer.clone(),
6115 LanguageServerToQuery::Other(server_id),
6116 GetCompletions {
6117 position,
6118 context: context.clone(),
6119 server_id: Some(server_id),
6120 },
6121 cx,
6122 ).fuse();
6123 let new_task = cx.background_spawn(async move {
6124 select_biased! {
6125 response = lsp_request => anyhow::Ok(Some(response?)),
6126 timeout_happened = timeout => {
6127 if timeout_happened {
6128 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6129 Ok(None)
6130 } else {
6131 let completions = lsp_request.await?;
6132 Ok(Some(completions))
6133 }
6134 },
6135 }
6136 });
6137 tasks.push((lsp_adapter, new_task));
6138 }
6139 })?;
6140
6141 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6142 let completion_response = task.await.ok()??;
6143 let completions = populate_labels_for_completions(
6144 completion_response.completions,
6145 language.clone(),
6146 lsp_adapter,
6147 )
6148 .await;
6149 Some(CompletionResponse {
6150 completions,
6151 display_options: CompletionDisplayOptions::default(),
6152 is_incomplete: completion_response.is_incomplete,
6153 })
6154 });
6155
6156 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6157
6158 Ok(responses.into_iter().flatten().collect())
6159 })
6160 } else {
6161 Task::ready(Err(anyhow!("No upstream client or local language server")))
6162 }
6163 }
6164
6165 pub fn resolve_completions(
6166 &self,
6167 buffer: Entity<Buffer>,
6168 completion_indices: Vec<usize>,
6169 completions: Rc<RefCell<Box<[Completion]>>>,
6170 cx: &mut Context<Self>,
6171 ) -> Task<Result<bool>> {
6172 let client = self.upstream_client();
6173 let buffer_id = buffer.read(cx).remote_id();
6174 let buffer_snapshot = buffer.read(cx).snapshot();
6175
6176 if !self.check_if_capable_for_proto_request(
6177 &buffer,
6178 GetCompletions::can_resolve_completions,
6179 cx,
6180 ) {
6181 return Task::ready(Ok(false));
6182 }
6183 cx.spawn(async move |lsp_store, cx| {
6184 let mut did_resolve = false;
6185 if let Some((client, project_id)) = client {
6186 for completion_index in completion_indices {
6187 let server_id = {
6188 let completion = &completions.borrow()[completion_index];
6189 completion.source.server_id()
6190 };
6191 if let Some(server_id) = server_id {
6192 if Self::resolve_completion_remote(
6193 project_id,
6194 server_id,
6195 buffer_id,
6196 completions.clone(),
6197 completion_index,
6198 client.clone(),
6199 )
6200 .await
6201 .log_err()
6202 .is_some()
6203 {
6204 did_resolve = true;
6205 }
6206 } else {
6207 resolve_word_completion(
6208 &buffer_snapshot,
6209 &mut completions.borrow_mut()[completion_index],
6210 );
6211 }
6212 }
6213 } else {
6214 for completion_index in completion_indices {
6215 let server_id = {
6216 let completion = &completions.borrow()[completion_index];
6217 completion.source.server_id()
6218 };
6219 if let Some(server_id) = server_id {
6220 let server_and_adapter = lsp_store
6221 .read_with(cx, |lsp_store, _| {
6222 let server = lsp_store.language_server_for_id(server_id)?;
6223 let adapter =
6224 lsp_store.language_server_adapter_for_id(server.server_id())?;
6225 Some((server, adapter))
6226 })
6227 .ok()
6228 .flatten();
6229 let Some((server, adapter)) = server_and_adapter else {
6230 continue;
6231 };
6232
6233 let resolved = Self::resolve_completion_local(
6234 server,
6235 completions.clone(),
6236 completion_index,
6237 )
6238 .await
6239 .log_err()
6240 .is_some();
6241 if resolved {
6242 Self::regenerate_completion_labels(
6243 adapter,
6244 &buffer_snapshot,
6245 completions.clone(),
6246 completion_index,
6247 )
6248 .await
6249 .log_err();
6250 did_resolve = true;
6251 }
6252 } else {
6253 resolve_word_completion(
6254 &buffer_snapshot,
6255 &mut completions.borrow_mut()[completion_index],
6256 );
6257 }
6258 }
6259 }
6260
6261 Ok(did_resolve)
6262 })
6263 }
6264
6265 async fn resolve_completion_local(
6266 server: Arc<lsp::LanguageServer>,
6267 completions: Rc<RefCell<Box<[Completion]>>>,
6268 completion_index: usize,
6269 ) -> Result<()> {
6270 let server_id = server.server_id();
6271 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6272 return Ok(());
6273 }
6274
6275 let request = {
6276 let completion = &completions.borrow()[completion_index];
6277 match &completion.source {
6278 CompletionSource::Lsp {
6279 lsp_completion,
6280 resolved,
6281 server_id: completion_server_id,
6282 ..
6283 } => {
6284 if *resolved {
6285 return Ok(());
6286 }
6287 anyhow::ensure!(
6288 server_id == *completion_server_id,
6289 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6290 );
6291 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6292 }
6293 CompletionSource::BufferWord { .. }
6294 | CompletionSource::Dap { .. }
6295 | CompletionSource::Custom => {
6296 return Ok(());
6297 }
6298 }
6299 };
6300 let resolved_completion = request
6301 .await
6302 .into_response()
6303 .context("resolve completion")?;
6304
6305 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6306 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6307
6308 let mut completions = completions.borrow_mut();
6309 let completion = &mut completions[completion_index];
6310 if let CompletionSource::Lsp {
6311 lsp_completion,
6312 resolved,
6313 server_id: completion_server_id,
6314 ..
6315 } = &mut completion.source
6316 {
6317 if *resolved {
6318 return Ok(());
6319 }
6320 anyhow::ensure!(
6321 server_id == *completion_server_id,
6322 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6323 );
6324 *lsp_completion = Box::new(resolved_completion);
6325 *resolved = true;
6326 }
6327 Ok(())
6328 }
6329
6330 async fn regenerate_completion_labels(
6331 adapter: Arc<CachedLspAdapter>,
6332 snapshot: &BufferSnapshot,
6333 completions: Rc<RefCell<Box<[Completion]>>>,
6334 completion_index: usize,
6335 ) -> Result<()> {
6336 let completion_item = completions.borrow()[completion_index]
6337 .source
6338 .lsp_completion(true)
6339 .map(Cow::into_owned);
6340 if let Some(lsp_documentation) = completion_item
6341 .as_ref()
6342 .and_then(|completion_item| completion_item.documentation.clone())
6343 {
6344 let mut completions = completions.borrow_mut();
6345 let completion = &mut completions[completion_index];
6346 completion.documentation = Some(lsp_documentation.into());
6347 } else {
6348 let mut completions = completions.borrow_mut();
6349 let completion = &mut completions[completion_index];
6350 completion.documentation = Some(CompletionDocumentation::Undocumented);
6351 }
6352
6353 let mut new_label = match completion_item {
6354 Some(completion_item) => {
6355 // 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
6356 // So we have to update the label here anyway...
6357 let language = snapshot.language();
6358 match language {
6359 Some(language) => {
6360 adapter
6361 .labels_for_completions(
6362 std::slice::from_ref(&completion_item),
6363 language,
6364 )
6365 .await?
6366 }
6367 None => Vec::new(),
6368 }
6369 .pop()
6370 .flatten()
6371 .unwrap_or_else(|| {
6372 CodeLabel::fallback_for_completion(
6373 &completion_item,
6374 language.map(|language| language.as_ref()),
6375 )
6376 })
6377 }
6378 None => CodeLabel::plain(
6379 completions.borrow()[completion_index].new_text.clone(),
6380 None,
6381 ),
6382 };
6383 ensure_uniform_list_compatible_label(&mut new_label);
6384
6385 let mut completions = completions.borrow_mut();
6386 let completion = &mut completions[completion_index];
6387 if completion.label.filter_text() == new_label.filter_text() {
6388 completion.label = new_label;
6389 } else {
6390 log::error!(
6391 "Resolved completion changed display label from {} to {}. \
6392 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6393 completion.label.text(),
6394 new_label.text(),
6395 completion.label.filter_text(),
6396 new_label.filter_text()
6397 );
6398 }
6399
6400 Ok(())
6401 }
6402
6403 async fn resolve_completion_remote(
6404 project_id: u64,
6405 server_id: LanguageServerId,
6406 buffer_id: BufferId,
6407 completions: Rc<RefCell<Box<[Completion]>>>,
6408 completion_index: usize,
6409 client: AnyProtoClient,
6410 ) -> Result<()> {
6411 let lsp_completion = {
6412 let completion = &completions.borrow()[completion_index];
6413 match &completion.source {
6414 CompletionSource::Lsp {
6415 lsp_completion,
6416 resolved,
6417 server_id: completion_server_id,
6418 ..
6419 } => {
6420 anyhow::ensure!(
6421 server_id == *completion_server_id,
6422 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6423 );
6424 if *resolved {
6425 return Ok(());
6426 }
6427 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6428 }
6429 CompletionSource::Custom
6430 | CompletionSource::Dap { .. }
6431 | CompletionSource::BufferWord { .. } => {
6432 return Ok(());
6433 }
6434 }
6435 };
6436 let request = proto::ResolveCompletionDocumentation {
6437 project_id,
6438 language_server_id: server_id.0 as u64,
6439 lsp_completion,
6440 buffer_id: buffer_id.into(),
6441 };
6442
6443 let response = client
6444 .request(request)
6445 .await
6446 .context("completion documentation resolve proto request")?;
6447 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6448
6449 let documentation = if response.documentation.is_empty() {
6450 CompletionDocumentation::Undocumented
6451 } else if response.documentation_is_markdown {
6452 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6453 } else if response.documentation.lines().count() <= 1 {
6454 CompletionDocumentation::SingleLine(response.documentation.into())
6455 } else {
6456 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6457 };
6458
6459 let mut completions = completions.borrow_mut();
6460 let completion = &mut completions[completion_index];
6461 completion.documentation = Some(documentation);
6462 if let CompletionSource::Lsp {
6463 insert_range,
6464 lsp_completion,
6465 resolved,
6466 server_id: completion_server_id,
6467 lsp_defaults: _,
6468 } = &mut completion.source
6469 {
6470 let completion_insert_range = response
6471 .old_insert_start
6472 .and_then(deserialize_anchor)
6473 .zip(response.old_insert_end.and_then(deserialize_anchor));
6474 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6475
6476 if *resolved {
6477 return Ok(());
6478 }
6479 anyhow::ensure!(
6480 server_id == *completion_server_id,
6481 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6482 );
6483 *lsp_completion = Box::new(resolved_lsp_completion);
6484 *resolved = true;
6485 }
6486
6487 let replace_range = response
6488 .old_replace_start
6489 .and_then(deserialize_anchor)
6490 .zip(response.old_replace_end.and_then(deserialize_anchor));
6491 if let Some((old_replace_start, old_replace_end)) = replace_range
6492 && !response.new_text.is_empty()
6493 {
6494 completion.new_text = response.new_text;
6495 completion.replace_range = old_replace_start..old_replace_end;
6496 }
6497
6498 Ok(())
6499 }
6500
6501 pub fn apply_additional_edits_for_completion(
6502 &self,
6503 buffer_handle: Entity<Buffer>,
6504 completions: Rc<RefCell<Box<[Completion]>>>,
6505 completion_index: usize,
6506 push_to_history: bool,
6507 cx: &mut Context<Self>,
6508 ) -> Task<Result<Option<Transaction>>> {
6509 if let Some((client, project_id)) = self.upstream_client() {
6510 let buffer = buffer_handle.read(cx);
6511 let buffer_id = buffer.remote_id();
6512 cx.spawn(async move |_, cx| {
6513 let request = {
6514 let completion = completions.borrow()[completion_index].clone();
6515 proto::ApplyCompletionAdditionalEdits {
6516 project_id,
6517 buffer_id: buffer_id.into(),
6518 completion: Some(Self::serialize_completion(&CoreCompletion {
6519 replace_range: completion.replace_range,
6520 new_text: completion.new_text,
6521 source: completion.source,
6522 })),
6523 }
6524 };
6525
6526 if let Some(transaction) = client.request(request).await?.transaction {
6527 let transaction = language::proto::deserialize_transaction(transaction)?;
6528 buffer_handle
6529 .update(cx, |buffer, _| {
6530 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6531 })?
6532 .await?;
6533 if push_to_history {
6534 buffer_handle.update(cx, |buffer, _| {
6535 buffer.push_transaction(transaction.clone(), Instant::now());
6536 buffer.finalize_last_transaction();
6537 })?;
6538 }
6539 Ok(Some(transaction))
6540 } else {
6541 Ok(None)
6542 }
6543 })
6544 } else {
6545 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6546 let completion = &completions.borrow()[completion_index];
6547 let server_id = completion.source.server_id()?;
6548 Some(
6549 self.language_server_for_local_buffer(buffer, server_id, cx)?
6550 .1
6551 .clone(),
6552 )
6553 }) else {
6554 return Task::ready(Ok(None));
6555 };
6556
6557 cx.spawn(async move |this, cx| {
6558 Self::resolve_completion_local(
6559 server.clone(),
6560 completions.clone(),
6561 completion_index,
6562 )
6563 .await
6564 .context("resolving completion")?;
6565 let completion = completions.borrow()[completion_index].clone();
6566 let additional_text_edits = completion
6567 .source
6568 .lsp_completion(true)
6569 .as_ref()
6570 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6571 if let Some(edits) = additional_text_edits {
6572 let edits = this
6573 .update(cx, |this, cx| {
6574 this.as_local_mut().unwrap().edits_from_lsp(
6575 &buffer_handle,
6576 edits,
6577 server.server_id(),
6578 None,
6579 cx,
6580 )
6581 })?
6582 .await?;
6583
6584 buffer_handle.update(cx, |buffer, cx| {
6585 buffer.finalize_last_transaction();
6586 buffer.start_transaction();
6587
6588 for (range, text) in edits {
6589 let primary = &completion.replace_range;
6590
6591 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6592 // and the primary completion is just an insertion (empty range), then this is likely
6593 // an auto-import scenario and should not be considered overlapping
6594 // https://github.com/zed-industries/zed/issues/26136
6595 let is_file_start_auto_import = {
6596 let snapshot = buffer.snapshot();
6597 let primary_start_point = primary.start.to_point(&snapshot);
6598 let range_start_point = range.start.to_point(&snapshot);
6599
6600 let result = primary_start_point.row == 0
6601 && primary_start_point.column == 0
6602 && range_start_point.row == 0
6603 && range_start_point.column == 0;
6604
6605 result
6606 };
6607
6608 let has_overlap = if is_file_start_auto_import {
6609 false
6610 } else {
6611 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6612 && primary.end.cmp(&range.start, buffer).is_ge();
6613 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6614 && range.end.cmp(&primary.end, buffer).is_ge();
6615 let result = start_within || end_within;
6616 result
6617 };
6618
6619 //Skip additional edits which overlap with the primary completion edit
6620 //https://github.com/zed-industries/zed/pull/1871
6621 if !has_overlap {
6622 buffer.edit([(range, text)], None, cx);
6623 }
6624 }
6625
6626 let transaction = if buffer.end_transaction(cx).is_some() {
6627 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6628 if !push_to_history {
6629 buffer.forget_transaction(transaction.id);
6630 }
6631 Some(transaction)
6632 } else {
6633 None
6634 };
6635 Ok(transaction)
6636 })?
6637 } else {
6638 Ok(None)
6639 }
6640 })
6641 }
6642 }
6643
6644 pub fn pull_diagnostics(
6645 &mut self,
6646 buffer: Entity<Buffer>,
6647 cx: &mut Context<Self>,
6648 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6649 let buffer_id = buffer.read(cx).remote_id();
6650
6651 if let Some((client, upstream_project_id)) = self.upstream_client() {
6652 let mut suitable_capabilities = None;
6653 // Are we capable for proto request?
6654 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6655 &buffer,
6656 |capabilities| {
6657 if let Some(caps) = &capabilities.diagnostic_provider {
6658 suitable_capabilities = Some(caps.clone());
6659 true
6660 } else {
6661 false
6662 }
6663 },
6664 cx,
6665 );
6666 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6667 let Some(dynamic_caps) = suitable_capabilities else {
6668 return Task::ready(Ok(None));
6669 };
6670 assert!(any_server_has_diagnostics_provider);
6671
6672 let request = GetDocumentDiagnostics {
6673 previous_result_id: None,
6674 dynamic_caps,
6675 };
6676 let request_task = client.request_lsp(
6677 upstream_project_id,
6678 None,
6679 LSP_REQUEST_TIMEOUT,
6680 cx.background_executor().clone(),
6681 request.to_proto(upstream_project_id, buffer.read(cx)),
6682 );
6683 cx.background_spawn(async move {
6684 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6685 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6686 // Do not attempt to further process the dummy responses here.
6687 let _response = request_task.await?;
6688 Ok(None)
6689 })
6690 } else {
6691 let servers = buffer.update(cx, |buffer, cx| {
6692 self.language_servers_for_local_buffer(buffer, cx)
6693 .map(|(_, server)| server.clone())
6694 .collect::<Vec<_>>()
6695 });
6696
6697 let pull_diagnostics = servers
6698 .into_iter()
6699 .flat_map(|server| {
6700 let result = maybe!({
6701 let local = self.as_local()?;
6702 let server_id = server.server_id();
6703 let providers_with_identifiers = local
6704 .language_server_dynamic_registrations
6705 .get(&server_id)
6706 .into_iter()
6707 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6708 .collect::<Vec<_>>();
6709 Some(
6710 providers_with_identifiers
6711 .into_iter()
6712 .map(|dynamic_caps| {
6713 let result_id = self.result_id(server_id, buffer_id, cx);
6714 self.request_lsp(
6715 buffer.clone(),
6716 LanguageServerToQuery::Other(server_id),
6717 GetDocumentDiagnostics {
6718 previous_result_id: result_id,
6719 dynamic_caps,
6720 },
6721 cx,
6722 )
6723 })
6724 .collect::<Vec<_>>(),
6725 )
6726 });
6727
6728 result.unwrap_or_default()
6729 })
6730 .collect::<Vec<_>>();
6731
6732 cx.background_spawn(async move {
6733 let mut responses = Vec::new();
6734 for diagnostics in join_all(pull_diagnostics).await {
6735 responses.extend(diagnostics?);
6736 }
6737 Ok(Some(responses))
6738 })
6739 }
6740 }
6741
6742 pub fn applicable_inlay_chunks(
6743 &mut self,
6744 buffer: &Entity<Buffer>,
6745 ranges: &[Range<text::Anchor>],
6746 cx: &mut Context<Self>,
6747 ) -> Vec<Range<BufferRow>> {
6748 self.latest_lsp_data(buffer, cx)
6749 .inlay_hints
6750 .applicable_chunks(ranges)
6751 .map(|chunk| chunk.row_range())
6752 .collect()
6753 }
6754
6755 pub fn invalidate_inlay_hints<'a>(
6756 &'a mut self,
6757 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6758 ) {
6759 for buffer_id in for_buffers {
6760 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6761 lsp_data.inlay_hints.clear();
6762 }
6763 }
6764 }
6765
6766 pub fn inlay_hints(
6767 &mut self,
6768 invalidate: InvalidationStrategy,
6769 buffer: Entity<Buffer>,
6770 ranges: Vec<Range<text::Anchor>>,
6771 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6772 cx: &mut Context<Self>,
6773 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6774 let next_hint_id = self.next_hint_id.clone();
6775 let lsp_data = self.latest_lsp_data(&buffer, cx);
6776 let query_version = lsp_data.buffer_version.clone();
6777 let mut lsp_refresh_requested = false;
6778 let for_server = if let InvalidationStrategy::RefreshRequested {
6779 server_id,
6780 request_id,
6781 } = invalidate
6782 {
6783 let invalidated = lsp_data
6784 .inlay_hints
6785 .invalidate_for_server_refresh(server_id, request_id);
6786 lsp_refresh_requested = invalidated;
6787 Some(server_id)
6788 } else {
6789 None
6790 };
6791 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6792 let known_chunks = known_chunks
6793 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6794 .map(|(_, known_chunks)| known_chunks)
6795 .unwrap_or_default();
6796
6797 let mut hint_fetch_tasks = Vec::new();
6798 let mut cached_inlay_hints = None;
6799 let mut ranges_to_query = None;
6800 let applicable_chunks = existing_inlay_hints
6801 .applicable_chunks(ranges.as_slice())
6802 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6803 .collect::<Vec<_>>();
6804 if applicable_chunks.is_empty() {
6805 return HashMap::default();
6806 }
6807
6808 for row_chunk in applicable_chunks {
6809 match (
6810 existing_inlay_hints
6811 .cached_hints(&row_chunk)
6812 .filter(|_| !lsp_refresh_requested)
6813 .cloned(),
6814 existing_inlay_hints
6815 .fetched_hints(&row_chunk)
6816 .as_ref()
6817 .filter(|_| !lsp_refresh_requested)
6818 .cloned(),
6819 ) {
6820 (None, None) => {
6821 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6822 continue;
6823 };
6824 ranges_to_query
6825 .get_or_insert_with(Vec::new)
6826 .push((row_chunk, chunk_range));
6827 }
6828 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6829 (Some(cached_hints), None) => {
6830 for (server_id, cached_hints) in cached_hints {
6831 if for_server.is_none_or(|for_server| for_server == server_id) {
6832 cached_inlay_hints
6833 .get_or_insert_with(HashMap::default)
6834 .entry(row_chunk.row_range())
6835 .or_insert_with(HashMap::default)
6836 .entry(server_id)
6837 .or_insert_with(Vec::new)
6838 .extend(cached_hints);
6839 }
6840 }
6841 }
6842 (Some(cached_hints), Some(fetched_hints)) => {
6843 hint_fetch_tasks.push((row_chunk, fetched_hints));
6844 for (server_id, cached_hints) in cached_hints {
6845 if for_server.is_none_or(|for_server| for_server == server_id) {
6846 cached_inlay_hints
6847 .get_or_insert_with(HashMap::default)
6848 .entry(row_chunk.row_range())
6849 .or_insert_with(HashMap::default)
6850 .entry(server_id)
6851 .or_insert_with(Vec::new)
6852 .extend(cached_hints);
6853 }
6854 }
6855 }
6856 }
6857 }
6858
6859 if hint_fetch_tasks.is_empty()
6860 && ranges_to_query
6861 .as_ref()
6862 .is_none_or(|ranges| ranges.is_empty())
6863 && let Some(cached_inlay_hints) = cached_inlay_hints
6864 {
6865 cached_inlay_hints
6866 .into_iter()
6867 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6868 .collect()
6869 } else {
6870 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6871 let next_hint_id = next_hint_id.clone();
6872 let buffer = buffer.clone();
6873 let query_version = query_version.clone();
6874 let new_inlay_hints = cx
6875 .spawn(async move |lsp_store, cx| {
6876 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6877 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6878 })?;
6879 new_fetch_task
6880 .await
6881 .and_then(|new_hints_by_server| {
6882 lsp_store.update(cx, |lsp_store, cx| {
6883 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6884 let update_cache = lsp_data.buffer_version == query_version;
6885 if new_hints_by_server.is_empty() {
6886 if update_cache {
6887 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6888 }
6889 HashMap::default()
6890 } else {
6891 new_hints_by_server
6892 .into_iter()
6893 .map(|(server_id, new_hints)| {
6894 let new_hints = new_hints
6895 .into_iter()
6896 .map(|new_hint| {
6897 (
6898 InlayId::Hint(next_hint_id.fetch_add(
6899 1,
6900 atomic::Ordering::AcqRel,
6901 )),
6902 new_hint,
6903 )
6904 })
6905 .collect::<Vec<_>>();
6906 if update_cache {
6907 lsp_data.inlay_hints.insert_new_hints(
6908 chunk,
6909 server_id,
6910 new_hints.clone(),
6911 );
6912 }
6913 (server_id, new_hints)
6914 })
6915 .collect()
6916 }
6917 })
6918 })
6919 .map_err(Arc::new)
6920 })
6921 .shared();
6922
6923 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6924 *fetch_task = Some(new_inlay_hints.clone());
6925 hint_fetch_tasks.push((chunk, new_inlay_hints));
6926 }
6927
6928 cached_inlay_hints
6929 .unwrap_or_default()
6930 .into_iter()
6931 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6932 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6933 (
6934 chunk.row_range(),
6935 cx.spawn(async move |_, _| {
6936 hints_fetch.await.map_err(|e| {
6937 if e.error_code() != ErrorCode::Internal {
6938 anyhow!(e.error_code())
6939 } else {
6940 anyhow!("{e:#}")
6941 }
6942 })
6943 }),
6944 )
6945 }))
6946 .collect()
6947 }
6948 }
6949
6950 fn fetch_inlay_hints(
6951 &mut self,
6952 for_server: Option<LanguageServerId>,
6953 buffer: &Entity<Buffer>,
6954 range: Range<Anchor>,
6955 cx: &mut Context<Self>,
6956 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6957 let request = InlayHints {
6958 range: range.clone(),
6959 };
6960 if let Some((upstream_client, project_id)) = self.upstream_client() {
6961 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6962 return Task::ready(Ok(HashMap::default()));
6963 }
6964 let request_task = upstream_client.request_lsp(
6965 project_id,
6966 for_server.map(|id| id.to_proto()),
6967 LSP_REQUEST_TIMEOUT,
6968 cx.background_executor().clone(),
6969 request.to_proto(project_id, buffer.read(cx)),
6970 );
6971 let buffer = buffer.clone();
6972 cx.spawn(async move |weak_lsp_store, cx| {
6973 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6974 return Ok(HashMap::default());
6975 };
6976 let Some(responses) = request_task.await? else {
6977 return Ok(HashMap::default());
6978 };
6979
6980 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6981 let lsp_store = lsp_store.clone();
6982 let buffer = buffer.clone();
6983 let cx = cx.clone();
6984 let request = request.clone();
6985 async move {
6986 (
6987 LanguageServerId::from_proto(response.server_id),
6988 request
6989 .response_from_proto(response.response, lsp_store, buffer, cx)
6990 .await,
6991 )
6992 }
6993 }))
6994 .await;
6995
6996 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
6997 let mut has_errors = false;
6998 let inlay_hints = inlay_hints
6999 .into_iter()
7000 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7001 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7002 Err(e) => {
7003 has_errors = true;
7004 log::error!("{e:#}");
7005 None
7006 }
7007 })
7008 .map(|(server_id, mut new_hints)| {
7009 new_hints.retain(|hint| {
7010 hint.position.is_valid(&buffer_snapshot)
7011 && range.start.is_valid(&buffer_snapshot)
7012 && range.end.is_valid(&buffer_snapshot)
7013 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7014 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7015 });
7016 (server_id, new_hints)
7017 })
7018 .collect::<HashMap<_, _>>();
7019 anyhow::ensure!(
7020 !has_errors || !inlay_hints.is_empty(),
7021 "Failed to fetch inlay hints"
7022 );
7023 Ok(inlay_hints)
7024 })
7025 } else {
7026 let inlay_hints_task = match for_server {
7027 Some(server_id) => {
7028 let server_task = self.request_lsp(
7029 buffer.clone(),
7030 LanguageServerToQuery::Other(server_id),
7031 request,
7032 cx,
7033 );
7034 cx.background_spawn(async move {
7035 let mut responses = Vec::new();
7036 match server_task.await {
7037 Ok(response) => responses.push((server_id, response)),
7038 // rust-analyzer likes to error with this when its still loading up
7039 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7040 Err(e) => log::error!(
7041 "Error handling response for inlay hints request: {e:#}"
7042 ),
7043 }
7044 responses
7045 })
7046 }
7047 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7048 };
7049 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7050 cx.background_spawn(async move {
7051 Ok(inlay_hints_task
7052 .await
7053 .into_iter()
7054 .map(|(server_id, mut new_hints)| {
7055 new_hints.retain(|hint| {
7056 hint.position.is_valid(&buffer_snapshot)
7057 && range.start.is_valid(&buffer_snapshot)
7058 && range.end.is_valid(&buffer_snapshot)
7059 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7060 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7061 });
7062 (server_id, new_hints)
7063 })
7064 .collect())
7065 })
7066 }
7067 }
7068
7069 pub fn pull_diagnostics_for_buffer(
7070 &mut self,
7071 buffer: Entity<Buffer>,
7072 cx: &mut Context<Self>,
7073 ) -> Task<anyhow::Result<()>> {
7074 let diagnostics = self.pull_diagnostics(buffer, cx);
7075 cx.spawn(async move |lsp_store, cx| {
7076 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7077 return Ok(());
7078 };
7079 lsp_store.update(cx, |lsp_store, cx| {
7080 if lsp_store.as_local().is_none() {
7081 return;
7082 }
7083
7084 let mut unchanged_buffers = HashSet::default();
7085 let mut changed_buffers = HashSet::default();
7086 let server_diagnostics_updates = diagnostics
7087 .into_iter()
7088 .filter_map(|diagnostics_set| match diagnostics_set {
7089 LspPullDiagnostics::Response {
7090 server_id,
7091 uri,
7092 diagnostics,
7093 } => Some((server_id, uri, diagnostics)),
7094 LspPullDiagnostics::Default => None,
7095 })
7096 .fold(
7097 HashMap::default(),
7098 |mut acc, (server_id, uri, diagnostics)| {
7099 let (result_id, diagnostics) = match diagnostics {
7100 PulledDiagnostics::Unchanged { result_id } => {
7101 unchanged_buffers.insert(uri.clone());
7102 (Some(result_id), Vec::new())
7103 }
7104 PulledDiagnostics::Changed {
7105 result_id,
7106 diagnostics,
7107 } => {
7108 changed_buffers.insert(uri.clone());
7109 (result_id, diagnostics)
7110 }
7111 };
7112 let disk_based_sources = Cow::Owned(
7113 lsp_store
7114 .language_server_adapter_for_id(server_id)
7115 .as_ref()
7116 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7117 .unwrap_or(&[])
7118 .to_vec(),
7119 );
7120 acc.entry(server_id).or_insert_with(Vec::new).push(
7121 DocumentDiagnosticsUpdate {
7122 server_id,
7123 diagnostics: lsp::PublishDiagnosticsParams {
7124 uri,
7125 diagnostics,
7126 version: None,
7127 },
7128 result_id,
7129 disk_based_sources,
7130 },
7131 );
7132 acc
7133 },
7134 );
7135
7136 for diagnostic_updates in server_diagnostics_updates.into_values() {
7137 lsp_store
7138 .merge_lsp_diagnostics(
7139 DiagnosticSourceKind::Pulled,
7140 diagnostic_updates,
7141 |buffer, old_diagnostic, cx| {
7142 File::from_dyn(buffer.file())
7143 .and_then(|file| {
7144 let abs_path = file.as_local()?.abs_path(cx);
7145 lsp::Uri::from_file_path(abs_path).ok()
7146 })
7147 .is_none_or(|buffer_uri| {
7148 unchanged_buffers.contains(&buffer_uri)
7149 || match old_diagnostic.source_kind {
7150 DiagnosticSourceKind::Pulled => {
7151 !changed_buffers.contains(&buffer_uri)
7152 }
7153 DiagnosticSourceKind::Other
7154 | DiagnosticSourceKind::Pushed => true,
7155 }
7156 })
7157 },
7158 cx,
7159 )
7160 .log_err();
7161 }
7162 })
7163 })
7164 }
7165
7166 pub fn document_colors(
7167 &mut self,
7168 known_cache_version: Option<usize>,
7169 buffer: Entity<Buffer>,
7170 cx: &mut Context<Self>,
7171 ) -> Option<DocumentColorTask> {
7172 let version_queried_for = buffer.read(cx).version();
7173 let buffer_id = buffer.read(cx).remote_id();
7174
7175 let current_language_servers = self.as_local().map(|local| {
7176 local
7177 .buffers_opened_in_servers
7178 .get(&buffer_id)
7179 .cloned()
7180 .unwrap_or_default()
7181 });
7182
7183 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7184 if let Some(cached_colors) = &lsp_data.document_colors {
7185 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7186 let has_different_servers =
7187 current_language_servers.is_some_and(|current_language_servers| {
7188 current_language_servers
7189 != cached_colors.colors.keys().copied().collect()
7190 });
7191 if !has_different_servers {
7192 let cache_version = cached_colors.cache_version;
7193 if Some(cache_version) == known_cache_version {
7194 return None;
7195 } else {
7196 return Some(
7197 Task::ready(Ok(DocumentColors {
7198 colors: cached_colors
7199 .colors
7200 .values()
7201 .flatten()
7202 .cloned()
7203 .collect(),
7204 cache_version: Some(cache_version),
7205 }))
7206 .shared(),
7207 );
7208 }
7209 }
7210 }
7211 }
7212 }
7213
7214 let color_lsp_data = self
7215 .latest_lsp_data(&buffer, cx)
7216 .document_colors
7217 .get_or_insert_default();
7218 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7219 && !version_queried_for.changed_since(updating_for)
7220 {
7221 return Some(running_update.clone());
7222 }
7223 let buffer_version_queried_for = version_queried_for.clone();
7224 let new_task = cx
7225 .spawn(async move |lsp_store, cx| {
7226 cx.background_executor()
7227 .timer(Duration::from_millis(30))
7228 .await;
7229 let fetched_colors = lsp_store
7230 .update(cx, |lsp_store, cx| {
7231 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7232 })?
7233 .await
7234 .context("fetching document colors")
7235 .map_err(Arc::new);
7236 let fetched_colors = match fetched_colors {
7237 Ok(fetched_colors) => {
7238 if Some(true)
7239 == buffer
7240 .update(cx, |buffer, _| {
7241 buffer.version() != buffer_version_queried_for
7242 })
7243 .ok()
7244 {
7245 return Ok(DocumentColors::default());
7246 }
7247 fetched_colors
7248 }
7249 Err(e) => {
7250 lsp_store
7251 .update(cx, |lsp_store, _| {
7252 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7253 if let Some(document_colors) = &mut lsp_data.document_colors {
7254 document_colors.colors_update = None;
7255 }
7256 }
7257 })
7258 .ok();
7259 return Err(e);
7260 }
7261 };
7262
7263 lsp_store
7264 .update(cx, |lsp_store, cx| {
7265 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7266 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7267
7268 if let Some(fetched_colors) = fetched_colors {
7269 if lsp_data.buffer_version == buffer_version_queried_for {
7270 lsp_colors.colors.extend(fetched_colors);
7271 lsp_colors.cache_version += 1;
7272 } else if !lsp_data
7273 .buffer_version
7274 .changed_since(&buffer_version_queried_for)
7275 {
7276 lsp_data.buffer_version = buffer_version_queried_for;
7277 lsp_colors.colors = fetched_colors;
7278 lsp_colors.cache_version += 1;
7279 }
7280 }
7281 lsp_colors.colors_update = None;
7282 let colors = lsp_colors
7283 .colors
7284 .values()
7285 .flatten()
7286 .cloned()
7287 .collect::<HashSet<_>>();
7288 DocumentColors {
7289 colors,
7290 cache_version: Some(lsp_colors.cache_version),
7291 }
7292 })
7293 .map_err(Arc::new)
7294 })
7295 .shared();
7296 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7297 Some(new_task)
7298 }
7299
7300 fn fetch_document_colors_for_buffer(
7301 &mut self,
7302 buffer: &Entity<Buffer>,
7303 cx: &mut Context<Self>,
7304 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7305 if let Some((client, project_id)) = self.upstream_client() {
7306 let request = GetDocumentColor {};
7307 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7308 return Task::ready(Ok(None));
7309 }
7310
7311 let request_task = client.request_lsp(
7312 project_id,
7313 None,
7314 LSP_REQUEST_TIMEOUT,
7315 cx.background_executor().clone(),
7316 request.to_proto(project_id, buffer.read(cx)),
7317 );
7318 let buffer = buffer.clone();
7319 cx.spawn(async move |lsp_store, cx| {
7320 let Some(lsp_store) = lsp_store.upgrade() else {
7321 return Ok(None);
7322 };
7323 let colors = join_all(
7324 request_task
7325 .await
7326 .log_err()
7327 .flatten()
7328 .map(|response| response.payload)
7329 .unwrap_or_default()
7330 .into_iter()
7331 .map(|color_response| {
7332 let response = request.response_from_proto(
7333 color_response.response,
7334 lsp_store.clone(),
7335 buffer.clone(),
7336 cx.clone(),
7337 );
7338 async move {
7339 (
7340 LanguageServerId::from_proto(color_response.server_id),
7341 response.await.log_err().unwrap_or_default(),
7342 )
7343 }
7344 }),
7345 )
7346 .await
7347 .into_iter()
7348 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7349 acc.entry(server_id)
7350 .or_insert_with(HashSet::default)
7351 .extend(colors);
7352 acc
7353 });
7354 Ok(Some(colors))
7355 })
7356 } else {
7357 let document_colors_task =
7358 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7359 cx.background_spawn(async move {
7360 Ok(Some(
7361 document_colors_task
7362 .await
7363 .into_iter()
7364 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7365 acc.entry(server_id)
7366 .or_insert_with(HashSet::default)
7367 .extend(colors);
7368 acc
7369 })
7370 .into_iter()
7371 .collect(),
7372 ))
7373 })
7374 }
7375 }
7376
7377 pub fn signature_help<T: ToPointUtf16>(
7378 &mut self,
7379 buffer: &Entity<Buffer>,
7380 position: T,
7381 cx: &mut Context<Self>,
7382 ) -> Task<Option<Vec<SignatureHelp>>> {
7383 let position = position.to_point_utf16(buffer.read(cx));
7384
7385 if let Some((client, upstream_project_id)) = self.upstream_client() {
7386 let request = GetSignatureHelp { position };
7387 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7388 return Task::ready(None);
7389 }
7390 let request_task = client.request_lsp(
7391 upstream_project_id,
7392 None,
7393 LSP_REQUEST_TIMEOUT,
7394 cx.background_executor().clone(),
7395 request.to_proto(upstream_project_id, buffer.read(cx)),
7396 );
7397 let buffer = buffer.clone();
7398 cx.spawn(async move |weak_lsp_store, cx| {
7399 let lsp_store = weak_lsp_store.upgrade()?;
7400 let signatures = join_all(
7401 request_task
7402 .await
7403 .log_err()
7404 .flatten()
7405 .map(|response| response.payload)
7406 .unwrap_or_default()
7407 .into_iter()
7408 .map(|response| {
7409 let response = GetSignatureHelp { position }.response_from_proto(
7410 response.response,
7411 lsp_store.clone(),
7412 buffer.clone(),
7413 cx.clone(),
7414 );
7415 async move { response.await.log_err().flatten() }
7416 }),
7417 )
7418 .await
7419 .into_iter()
7420 .flatten()
7421 .collect();
7422 Some(signatures)
7423 })
7424 } else {
7425 let all_actions_task = self.request_multiple_lsp_locally(
7426 buffer,
7427 Some(position),
7428 GetSignatureHelp { position },
7429 cx,
7430 );
7431 cx.background_spawn(async move {
7432 Some(
7433 all_actions_task
7434 .await
7435 .into_iter()
7436 .flat_map(|(_, actions)| actions)
7437 .collect::<Vec<_>>(),
7438 )
7439 })
7440 }
7441 }
7442
7443 pub fn hover(
7444 &mut self,
7445 buffer: &Entity<Buffer>,
7446 position: PointUtf16,
7447 cx: &mut Context<Self>,
7448 ) -> Task<Option<Vec<Hover>>> {
7449 if let Some((client, upstream_project_id)) = self.upstream_client() {
7450 let request = GetHover { position };
7451 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7452 return Task::ready(None);
7453 }
7454 let request_task = client.request_lsp(
7455 upstream_project_id,
7456 None,
7457 LSP_REQUEST_TIMEOUT,
7458 cx.background_executor().clone(),
7459 request.to_proto(upstream_project_id, buffer.read(cx)),
7460 );
7461 let buffer = buffer.clone();
7462 cx.spawn(async move |weak_lsp_store, cx| {
7463 let lsp_store = weak_lsp_store.upgrade()?;
7464 let hovers = join_all(
7465 request_task
7466 .await
7467 .log_err()
7468 .flatten()
7469 .map(|response| response.payload)
7470 .unwrap_or_default()
7471 .into_iter()
7472 .map(|response| {
7473 let response = GetHover { position }.response_from_proto(
7474 response.response,
7475 lsp_store.clone(),
7476 buffer.clone(),
7477 cx.clone(),
7478 );
7479 async move {
7480 response
7481 .await
7482 .log_err()
7483 .flatten()
7484 .and_then(remove_empty_hover_blocks)
7485 }
7486 }),
7487 )
7488 .await
7489 .into_iter()
7490 .flatten()
7491 .collect();
7492 Some(hovers)
7493 })
7494 } else {
7495 let all_actions_task = self.request_multiple_lsp_locally(
7496 buffer,
7497 Some(position),
7498 GetHover { position },
7499 cx,
7500 );
7501 cx.background_spawn(async move {
7502 Some(
7503 all_actions_task
7504 .await
7505 .into_iter()
7506 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7507 .collect::<Vec<Hover>>(),
7508 )
7509 })
7510 }
7511 }
7512
7513 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7514 let language_registry = self.languages.clone();
7515
7516 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7517 let request = upstream_client.request(proto::GetProjectSymbols {
7518 project_id: *project_id,
7519 query: query.to_string(),
7520 });
7521 cx.foreground_executor().spawn(async move {
7522 let response = request.await?;
7523 let mut symbols = Vec::new();
7524 let core_symbols = response
7525 .symbols
7526 .into_iter()
7527 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7528 .collect::<Vec<_>>();
7529 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7530 .await;
7531 Ok(symbols)
7532 })
7533 } else if let Some(local) = self.as_local() {
7534 struct WorkspaceSymbolsResult {
7535 server_id: LanguageServerId,
7536 lsp_adapter: Arc<CachedLspAdapter>,
7537 worktree: WeakEntity<Worktree>,
7538 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7539 }
7540
7541 let mut requests = Vec::new();
7542 let mut requested_servers = BTreeSet::new();
7543 for (seed, state) in local.language_server_ids.iter() {
7544 let Some(worktree_handle) = self
7545 .worktree_store
7546 .read(cx)
7547 .worktree_for_id(seed.worktree_id, cx)
7548 else {
7549 continue;
7550 };
7551 let worktree = worktree_handle.read(cx);
7552 if !worktree.is_visible() {
7553 continue;
7554 }
7555
7556 if !requested_servers.insert(state.id) {
7557 continue;
7558 }
7559
7560 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7561 Some(LanguageServerState::Running {
7562 adapter, server, ..
7563 }) => (adapter.clone(), server),
7564
7565 _ => continue,
7566 };
7567 let supports_workspace_symbol_request =
7568 match server.capabilities().workspace_symbol_provider {
7569 Some(OneOf::Left(supported)) => supported,
7570 Some(OneOf::Right(_)) => true,
7571 None => false,
7572 };
7573 if !supports_workspace_symbol_request {
7574 continue;
7575 }
7576 let worktree_handle = worktree_handle.clone();
7577 let server_id = server.server_id();
7578 requests.push(
7579 server
7580 .request::<lsp::request::WorkspaceSymbolRequest>(
7581 lsp::WorkspaceSymbolParams {
7582 query: query.to_string(),
7583 ..Default::default()
7584 },
7585 )
7586 .map(move |response| {
7587 let lsp_symbols = response.into_response()
7588 .context("workspace symbols request")
7589 .log_err()
7590 .flatten()
7591 .map(|symbol_response| match symbol_response {
7592 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7593 flat_responses.into_iter().map(|lsp_symbol| {
7594 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7595 }).collect::<Vec<_>>()
7596 }
7597 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7598 nested_responses.into_iter().filter_map(|lsp_symbol| {
7599 let location = match lsp_symbol.location {
7600 OneOf::Left(location) => location,
7601 OneOf::Right(_) => {
7602 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7603 return None
7604 }
7605 };
7606 Some((lsp_symbol.name, lsp_symbol.kind, location))
7607 }).collect::<Vec<_>>()
7608 }
7609 }).unwrap_or_default();
7610
7611 WorkspaceSymbolsResult {
7612 server_id,
7613 lsp_adapter,
7614 worktree: worktree_handle.downgrade(),
7615 lsp_symbols,
7616 }
7617 }),
7618 );
7619 }
7620
7621 cx.spawn(async move |this, cx| {
7622 let responses = futures::future::join_all(requests).await;
7623 let this = match this.upgrade() {
7624 Some(this) => this,
7625 None => return Ok(Vec::new()),
7626 };
7627
7628 let mut symbols = Vec::new();
7629 for result in responses {
7630 let core_symbols = this.update(cx, |this, cx| {
7631 result
7632 .lsp_symbols
7633 .into_iter()
7634 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7635 let abs_path = symbol_location.uri.to_file_path().ok()?;
7636 let source_worktree = result.worktree.upgrade()?;
7637 let source_worktree_id = source_worktree.read(cx).id();
7638
7639 let path = if let Some((tree, rel_path)) =
7640 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7641 {
7642 let worktree_id = tree.read(cx).id();
7643 SymbolLocation::InProject(ProjectPath {
7644 worktree_id,
7645 path: rel_path,
7646 })
7647 } else {
7648 SymbolLocation::OutsideProject {
7649 signature: this.symbol_signature(&abs_path),
7650 abs_path: abs_path.into(),
7651 }
7652 };
7653
7654 Some(CoreSymbol {
7655 source_language_server_id: result.server_id,
7656 language_server_name: result.lsp_adapter.name.clone(),
7657 source_worktree_id,
7658 path,
7659 kind: symbol_kind,
7660 name: symbol_name,
7661 range: range_from_lsp(symbol_location.range),
7662 })
7663 })
7664 .collect()
7665 })?;
7666
7667 populate_labels_for_symbols(
7668 core_symbols,
7669 &language_registry,
7670 Some(result.lsp_adapter),
7671 &mut symbols,
7672 )
7673 .await;
7674 }
7675
7676 Ok(symbols)
7677 })
7678 } else {
7679 Task::ready(Err(anyhow!("No upstream client or local language server")))
7680 }
7681 }
7682
7683 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7684 let mut summary = DiagnosticSummary::default();
7685 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7686 summary.error_count += path_summary.error_count;
7687 summary.warning_count += path_summary.warning_count;
7688 }
7689 summary
7690 }
7691
7692 /// Returns the diagnostic summary for a specific project path.
7693 pub fn diagnostic_summary_for_path(
7694 &self,
7695 project_path: &ProjectPath,
7696 _: &App,
7697 ) -> DiagnosticSummary {
7698 if let Some(summaries) = self
7699 .diagnostic_summaries
7700 .get(&project_path.worktree_id)
7701 .and_then(|map| map.get(&project_path.path))
7702 {
7703 let (error_count, warning_count) = summaries.iter().fold(
7704 (0, 0),
7705 |(error_count, warning_count), (_language_server_id, summary)| {
7706 (
7707 error_count + summary.error_count,
7708 warning_count + summary.warning_count,
7709 )
7710 },
7711 );
7712
7713 DiagnosticSummary {
7714 error_count,
7715 warning_count,
7716 }
7717 } else {
7718 DiagnosticSummary::default()
7719 }
7720 }
7721
7722 pub fn diagnostic_summaries<'a>(
7723 &'a self,
7724 include_ignored: bool,
7725 cx: &'a App,
7726 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7727 self.worktree_store
7728 .read(cx)
7729 .visible_worktrees(cx)
7730 .filter_map(|worktree| {
7731 let worktree = worktree.read(cx);
7732 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7733 })
7734 .flat_map(move |(worktree, summaries)| {
7735 let worktree_id = worktree.id();
7736 summaries
7737 .iter()
7738 .filter(move |(path, _)| {
7739 include_ignored
7740 || worktree
7741 .entry_for_path(path.as_ref())
7742 .is_some_and(|entry| !entry.is_ignored)
7743 })
7744 .flat_map(move |(path, summaries)| {
7745 summaries.iter().map(move |(server_id, summary)| {
7746 (
7747 ProjectPath {
7748 worktree_id,
7749 path: path.clone(),
7750 },
7751 *server_id,
7752 *summary,
7753 )
7754 })
7755 })
7756 })
7757 }
7758
7759 pub fn on_buffer_edited(
7760 &mut self,
7761 buffer: Entity<Buffer>,
7762 cx: &mut Context<Self>,
7763 ) -> Option<()> {
7764 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7765 Some(
7766 self.as_local()?
7767 .language_servers_for_buffer(buffer, cx)
7768 .map(|i| i.1.clone())
7769 .collect(),
7770 )
7771 })?;
7772
7773 let buffer = buffer.read(cx);
7774 let file = File::from_dyn(buffer.file())?;
7775 let abs_path = file.as_local()?.abs_path(cx);
7776 let uri = lsp::Uri::from_file_path(&abs_path)
7777 .ok()
7778 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7779 .log_err()?;
7780 let next_snapshot = buffer.text_snapshot();
7781 for language_server in language_servers {
7782 let language_server = language_server.clone();
7783
7784 let buffer_snapshots = self
7785 .as_local_mut()?
7786 .buffer_snapshots
7787 .get_mut(&buffer.remote_id())
7788 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7789 let previous_snapshot = buffer_snapshots.last()?;
7790
7791 let build_incremental_change = || {
7792 buffer
7793 .edits_since::<Dimensions<PointUtf16, usize>>(
7794 previous_snapshot.snapshot.version(),
7795 )
7796 .map(|edit| {
7797 let edit_start = edit.new.start.0;
7798 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7799 let new_text = next_snapshot
7800 .text_for_range(edit.new.start.1..edit.new.end.1)
7801 .collect();
7802 lsp::TextDocumentContentChangeEvent {
7803 range: Some(lsp::Range::new(
7804 point_to_lsp(edit_start),
7805 point_to_lsp(edit_end),
7806 )),
7807 range_length: None,
7808 text: new_text,
7809 }
7810 })
7811 .collect()
7812 };
7813
7814 let document_sync_kind = language_server
7815 .capabilities()
7816 .text_document_sync
7817 .as_ref()
7818 .and_then(|sync| match sync {
7819 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7820 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7821 });
7822
7823 let content_changes: Vec<_> = match document_sync_kind {
7824 Some(lsp::TextDocumentSyncKind::FULL) => {
7825 vec![lsp::TextDocumentContentChangeEvent {
7826 range: None,
7827 range_length: None,
7828 text: next_snapshot.text(),
7829 }]
7830 }
7831 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7832 _ => {
7833 #[cfg(any(test, feature = "test-support"))]
7834 {
7835 build_incremental_change()
7836 }
7837
7838 #[cfg(not(any(test, feature = "test-support")))]
7839 {
7840 continue;
7841 }
7842 }
7843 };
7844
7845 let next_version = previous_snapshot.version + 1;
7846 buffer_snapshots.push(LspBufferSnapshot {
7847 version: next_version,
7848 snapshot: next_snapshot.clone(),
7849 });
7850
7851 language_server
7852 .notify::<lsp::notification::DidChangeTextDocument>(
7853 lsp::DidChangeTextDocumentParams {
7854 text_document: lsp::VersionedTextDocumentIdentifier::new(
7855 uri.clone(),
7856 next_version,
7857 ),
7858 content_changes,
7859 },
7860 )
7861 .ok();
7862 self.pull_workspace_diagnostics(language_server.server_id());
7863 }
7864
7865 None
7866 }
7867
7868 pub fn on_buffer_saved(
7869 &mut self,
7870 buffer: Entity<Buffer>,
7871 cx: &mut Context<Self>,
7872 ) -> Option<()> {
7873 let file = File::from_dyn(buffer.read(cx).file())?;
7874 let worktree_id = file.worktree_id(cx);
7875 let abs_path = file.as_local()?.abs_path(cx);
7876 let text_document = lsp::TextDocumentIdentifier {
7877 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7878 };
7879 let local = self.as_local()?;
7880
7881 for server in local.language_servers_for_worktree(worktree_id) {
7882 if let Some(include_text) = include_text(server.as_ref()) {
7883 let text = if include_text {
7884 Some(buffer.read(cx).text())
7885 } else {
7886 None
7887 };
7888 server
7889 .notify::<lsp::notification::DidSaveTextDocument>(
7890 lsp::DidSaveTextDocumentParams {
7891 text_document: text_document.clone(),
7892 text,
7893 },
7894 )
7895 .ok();
7896 }
7897 }
7898
7899 let language_servers = buffer.update(cx, |buffer, cx| {
7900 local.language_server_ids_for_buffer(buffer, cx)
7901 });
7902 for language_server_id in language_servers {
7903 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7904 }
7905
7906 None
7907 }
7908
7909 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7910 maybe!(async move {
7911 let mut refreshed_servers = HashSet::default();
7912 let servers = lsp_store
7913 .update(cx, |lsp_store, cx| {
7914 let local = lsp_store.as_local()?;
7915
7916 let servers = local
7917 .language_server_ids
7918 .iter()
7919 .filter_map(|(seed, state)| {
7920 let worktree = lsp_store
7921 .worktree_store
7922 .read(cx)
7923 .worktree_for_id(seed.worktree_id, cx);
7924 let delegate: Arc<dyn LspAdapterDelegate> =
7925 worktree.map(|worktree| {
7926 LocalLspAdapterDelegate::new(
7927 local.languages.clone(),
7928 &local.environment,
7929 cx.weak_entity(),
7930 &worktree,
7931 local.http_client.clone(),
7932 local.fs.clone(),
7933 cx,
7934 )
7935 })?;
7936 let server_id = state.id;
7937
7938 let states = local.language_servers.get(&server_id)?;
7939
7940 match states {
7941 LanguageServerState::Starting { .. } => None,
7942 LanguageServerState::Running {
7943 adapter, server, ..
7944 } => {
7945 let adapter = adapter.clone();
7946 let server = server.clone();
7947 refreshed_servers.insert(server.name());
7948 let toolchain = seed.toolchain.clone();
7949 Some(cx.spawn(async move |_, cx| {
7950 let settings =
7951 LocalLspStore::workspace_configuration_for_adapter(
7952 adapter.adapter.clone(),
7953 &delegate,
7954 toolchain,
7955 cx,
7956 )
7957 .await
7958 .ok()?;
7959 server
7960 .notify::<lsp::notification::DidChangeConfiguration>(
7961 lsp::DidChangeConfigurationParams { settings },
7962 )
7963 .ok()?;
7964 Some(())
7965 }))
7966 }
7967 }
7968 })
7969 .collect::<Vec<_>>();
7970
7971 Some(servers)
7972 })
7973 .ok()
7974 .flatten()?;
7975
7976 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7977 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7978 // to stop and unregister its language server wrapper.
7979 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7980 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7981 let _: Vec<Option<()>> = join_all(servers).await;
7982
7983 Some(())
7984 })
7985 .await;
7986 }
7987
7988 fn maintain_workspace_config(
7989 external_refresh_requests: watch::Receiver<()>,
7990 cx: &mut Context<Self>,
7991 ) -> Task<Result<()>> {
7992 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7993 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7994
7995 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7996 *settings_changed_tx.borrow_mut() = ();
7997 });
7998
7999 let mut joint_future =
8000 futures::stream::select(settings_changed_rx, external_refresh_requests);
8001 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8002 // - 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).
8003 // - 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.
8004 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8005 // - 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,
8006 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8007 cx.spawn(async move |this, cx| {
8008 while let Some(()) = joint_future.next().await {
8009 this.update(cx, |this, cx| {
8010 this.refresh_server_tree(cx);
8011 })
8012 .ok();
8013
8014 Self::refresh_workspace_configurations(&this, cx).await;
8015 }
8016
8017 drop(settings_observation);
8018 anyhow::Ok(())
8019 })
8020 }
8021
8022 pub fn language_servers_for_local_buffer<'a>(
8023 &'a self,
8024 buffer: &Buffer,
8025 cx: &mut App,
8026 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8027 let local = self.as_local();
8028 let language_server_ids = local
8029 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8030 .unwrap_or_default();
8031
8032 language_server_ids
8033 .into_iter()
8034 .filter_map(
8035 move |server_id| match local?.language_servers.get(&server_id)? {
8036 LanguageServerState::Running {
8037 adapter, server, ..
8038 } => Some((adapter, server)),
8039 _ => None,
8040 },
8041 )
8042 }
8043
8044 pub fn language_server_for_local_buffer<'a>(
8045 &'a self,
8046 buffer: &'a Buffer,
8047 server_id: LanguageServerId,
8048 cx: &'a mut App,
8049 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8050 self.as_local()?
8051 .language_servers_for_buffer(buffer, cx)
8052 .find(|(_, s)| s.server_id() == server_id)
8053 }
8054
8055 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8056 self.diagnostic_summaries.remove(&id_to_remove);
8057 if let Some(local) = self.as_local_mut() {
8058 let to_remove = local.remove_worktree(id_to_remove, cx);
8059 for server in to_remove {
8060 self.language_server_statuses.remove(&server);
8061 }
8062 }
8063 }
8064
8065 pub fn shared(
8066 &mut self,
8067 project_id: u64,
8068 downstream_client: AnyProtoClient,
8069 _: &mut Context<Self>,
8070 ) {
8071 self.downstream_client = Some((downstream_client.clone(), project_id));
8072
8073 for (server_id, status) in &self.language_server_statuses {
8074 if let Some(server) = self.language_server_for_id(*server_id) {
8075 downstream_client
8076 .send(proto::StartLanguageServer {
8077 project_id,
8078 server: Some(proto::LanguageServer {
8079 id: server_id.to_proto(),
8080 name: status.name.to_string(),
8081 worktree_id: status.worktree.map(|id| id.to_proto()),
8082 }),
8083 capabilities: serde_json::to_string(&server.capabilities())
8084 .expect("serializing server LSP capabilities"),
8085 })
8086 .log_err();
8087 }
8088 }
8089 }
8090
8091 pub fn disconnected_from_host(&mut self) {
8092 self.downstream_client.take();
8093 }
8094
8095 pub fn disconnected_from_ssh_remote(&mut self) {
8096 if let LspStoreMode::Remote(RemoteLspStore {
8097 upstream_client, ..
8098 }) = &mut self.mode
8099 {
8100 upstream_client.take();
8101 }
8102 }
8103
8104 pub(crate) fn set_language_server_statuses_from_proto(
8105 &mut self,
8106 project: WeakEntity<Project>,
8107 language_servers: Vec<proto::LanguageServer>,
8108 server_capabilities: Vec<String>,
8109 cx: &mut Context<Self>,
8110 ) {
8111 let lsp_logs = cx
8112 .try_global::<GlobalLogStore>()
8113 .map(|lsp_store| lsp_store.0.clone());
8114
8115 self.language_server_statuses = language_servers
8116 .into_iter()
8117 .zip(server_capabilities)
8118 .map(|(server, server_capabilities)| {
8119 let server_id = LanguageServerId(server.id as usize);
8120 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8121 self.lsp_server_capabilities
8122 .insert(server_id, server_capabilities);
8123 }
8124
8125 let name = LanguageServerName::from_proto(server.name);
8126 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8127
8128 if let Some(lsp_logs) = &lsp_logs {
8129 lsp_logs.update(cx, |lsp_logs, cx| {
8130 lsp_logs.add_language_server(
8131 // Only remote clients get their language servers set from proto
8132 LanguageServerKind::Remote {
8133 project: project.clone(),
8134 },
8135 server_id,
8136 Some(name.clone()),
8137 worktree,
8138 None,
8139 cx,
8140 );
8141 });
8142 }
8143
8144 (
8145 server_id,
8146 LanguageServerStatus {
8147 name,
8148 pending_work: Default::default(),
8149 has_pending_diagnostic_updates: false,
8150 progress_tokens: Default::default(),
8151 worktree,
8152 binary: None,
8153 configuration: None,
8154 workspace_folders: BTreeSet::new(),
8155 },
8156 )
8157 })
8158 .collect();
8159 }
8160
8161 #[cfg(test)]
8162 pub fn update_diagnostic_entries(
8163 &mut self,
8164 server_id: LanguageServerId,
8165 abs_path: PathBuf,
8166 result_id: Option<String>,
8167 version: Option<i32>,
8168 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8169 cx: &mut Context<Self>,
8170 ) -> anyhow::Result<()> {
8171 self.merge_diagnostic_entries(
8172 vec![DocumentDiagnosticsUpdate {
8173 diagnostics: DocumentDiagnostics {
8174 diagnostics,
8175 document_abs_path: abs_path,
8176 version,
8177 },
8178 result_id,
8179 server_id,
8180 disk_based_sources: Cow::Borrowed(&[]),
8181 }],
8182 |_, _, _| false,
8183 cx,
8184 )?;
8185 Ok(())
8186 }
8187
8188 pub fn merge_diagnostic_entries<'a>(
8189 &mut self,
8190 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8191 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8192 cx: &mut Context<Self>,
8193 ) -> anyhow::Result<()> {
8194 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8195 let mut updated_diagnostics_paths = HashMap::default();
8196 for mut update in diagnostic_updates {
8197 let abs_path = &update.diagnostics.document_abs_path;
8198 let server_id = update.server_id;
8199 let Some((worktree, relative_path)) =
8200 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8201 else {
8202 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8203 return Ok(());
8204 };
8205
8206 let worktree_id = worktree.read(cx).id();
8207 let project_path = ProjectPath {
8208 worktree_id,
8209 path: relative_path,
8210 };
8211
8212 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8213 let snapshot = buffer_handle.read(cx).snapshot();
8214 let buffer = buffer_handle.read(cx);
8215 let reused_diagnostics = buffer
8216 .buffer_diagnostics(Some(server_id))
8217 .iter()
8218 .filter(|v| merge(buffer, &v.diagnostic, cx))
8219 .map(|v| {
8220 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8221 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8222 DiagnosticEntry {
8223 range: start..end,
8224 diagnostic: v.diagnostic.clone(),
8225 }
8226 })
8227 .collect::<Vec<_>>();
8228
8229 self.as_local_mut()
8230 .context("cannot merge diagnostics on a remote LspStore")?
8231 .update_buffer_diagnostics(
8232 &buffer_handle,
8233 server_id,
8234 update.result_id,
8235 update.diagnostics.version,
8236 update.diagnostics.diagnostics.clone(),
8237 reused_diagnostics.clone(),
8238 cx,
8239 )?;
8240
8241 update.diagnostics.diagnostics.extend(reused_diagnostics);
8242 }
8243
8244 let updated = worktree.update(cx, |worktree, cx| {
8245 self.update_worktree_diagnostics(
8246 worktree.id(),
8247 server_id,
8248 project_path.path.clone(),
8249 update.diagnostics.diagnostics,
8250 cx,
8251 )
8252 })?;
8253 match updated {
8254 ControlFlow::Continue(new_summary) => {
8255 if let Some((project_id, new_summary)) = new_summary {
8256 match &mut diagnostics_summary {
8257 Some(diagnostics_summary) => {
8258 diagnostics_summary
8259 .more_summaries
8260 .push(proto::DiagnosticSummary {
8261 path: project_path.path.as_ref().to_proto(),
8262 language_server_id: server_id.0 as u64,
8263 error_count: new_summary.error_count,
8264 warning_count: new_summary.warning_count,
8265 })
8266 }
8267 None => {
8268 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8269 project_id,
8270 worktree_id: worktree_id.to_proto(),
8271 summary: Some(proto::DiagnosticSummary {
8272 path: project_path.path.as_ref().to_proto(),
8273 language_server_id: server_id.0 as u64,
8274 error_count: new_summary.error_count,
8275 warning_count: new_summary.warning_count,
8276 }),
8277 more_summaries: Vec::new(),
8278 })
8279 }
8280 }
8281 }
8282 updated_diagnostics_paths
8283 .entry(server_id)
8284 .or_insert_with(Vec::new)
8285 .push(project_path);
8286 }
8287 ControlFlow::Break(()) => {}
8288 }
8289 }
8290
8291 if let Some((diagnostics_summary, (downstream_client, _))) =
8292 diagnostics_summary.zip(self.downstream_client.as_ref())
8293 {
8294 downstream_client.send(diagnostics_summary).log_err();
8295 }
8296 for (server_id, paths) in updated_diagnostics_paths {
8297 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8298 }
8299 Ok(())
8300 }
8301
8302 fn update_worktree_diagnostics(
8303 &mut self,
8304 worktree_id: WorktreeId,
8305 server_id: LanguageServerId,
8306 path_in_worktree: Arc<RelPath>,
8307 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8308 _: &mut Context<Worktree>,
8309 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8310 let local = match &mut self.mode {
8311 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8312 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8313 };
8314
8315 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8316 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8317 let summaries_by_server_id = summaries_for_tree
8318 .entry(path_in_worktree.clone())
8319 .or_default();
8320
8321 let old_summary = summaries_by_server_id
8322 .remove(&server_id)
8323 .unwrap_or_default();
8324
8325 let new_summary = DiagnosticSummary::new(&diagnostics);
8326 if new_summary.is_empty() {
8327 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8328 {
8329 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8330 diagnostics_by_server_id.remove(ix);
8331 }
8332 if diagnostics_by_server_id.is_empty() {
8333 diagnostics_for_tree.remove(&path_in_worktree);
8334 }
8335 }
8336 } else {
8337 summaries_by_server_id.insert(server_id, new_summary);
8338 let diagnostics_by_server_id = diagnostics_for_tree
8339 .entry(path_in_worktree.clone())
8340 .or_default();
8341 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8342 Ok(ix) => {
8343 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8344 }
8345 Err(ix) => {
8346 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8347 }
8348 }
8349 }
8350
8351 if !old_summary.is_empty() || !new_summary.is_empty() {
8352 if let Some((_, project_id)) = &self.downstream_client {
8353 Ok(ControlFlow::Continue(Some((
8354 *project_id,
8355 proto::DiagnosticSummary {
8356 path: path_in_worktree.to_proto(),
8357 language_server_id: server_id.0 as u64,
8358 error_count: new_summary.error_count as u32,
8359 warning_count: new_summary.warning_count as u32,
8360 },
8361 ))))
8362 } else {
8363 Ok(ControlFlow::Continue(None))
8364 }
8365 } else {
8366 Ok(ControlFlow::Break(()))
8367 }
8368 }
8369
8370 pub fn open_buffer_for_symbol(
8371 &mut self,
8372 symbol: &Symbol,
8373 cx: &mut Context<Self>,
8374 ) -> Task<Result<Entity<Buffer>>> {
8375 if let Some((client, project_id)) = self.upstream_client() {
8376 let request = client.request(proto::OpenBufferForSymbol {
8377 project_id,
8378 symbol: Some(Self::serialize_symbol(symbol)),
8379 });
8380 cx.spawn(async move |this, cx| {
8381 let response = request.await?;
8382 let buffer_id = BufferId::new(response.buffer_id)?;
8383 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8384 .await
8385 })
8386 } else if let Some(local) = self.as_local() {
8387 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8388 seed.worktree_id == symbol.source_worktree_id
8389 && state.id == symbol.source_language_server_id
8390 && symbol.language_server_name == seed.name
8391 });
8392 if !is_valid {
8393 return Task::ready(Err(anyhow!(
8394 "language server for worktree and language not found"
8395 )));
8396 };
8397
8398 let symbol_abs_path = match &symbol.path {
8399 SymbolLocation::InProject(project_path) => self
8400 .worktree_store
8401 .read(cx)
8402 .absolutize(&project_path, cx)
8403 .context("no such worktree"),
8404 SymbolLocation::OutsideProject {
8405 abs_path,
8406 signature: _,
8407 } => Ok(abs_path.to_path_buf()),
8408 };
8409 let symbol_abs_path = match symbol_abs_path {
8410 Ok(abs_path) => abs_path,
8411 Err(err) => return Task::ready(Err(err)),
8412 };
8413 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8414 uri
8415 } else {
8416 return Task::ready(Err(anyhow!("invalid symbol path")));
8417 };
8418
8419 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8420 } else {
8421 Task::ready(Err(anyhow!("no upstream client or local store")))
8422 }
8423 }
8424
8425 pub(crate) fn open_local_buffer_via_lsp(
8426 &mut self,
8427 abs_path: lsp::Uri,
8428 language_server_id: LanguageServerId,
8429 cx: &mut Context<Self>,
8430 ) -> Task<Result<Entity<Buffer>>> {
8431 cx.spawn(async move |lsp_store, cx| {
8432 // Escape percent-encoded string.
8433 let current_scheme = abs_path.scheme().to_owned();
8434 // Uri is immutable, so we can't modify the scheme
8435
8436 let abs_path = abs_path
8437 .to_file_path()
8438 .map_err(|()| anyhow!("can't convert URI to path"))?;
8439 let p = abs_path.clone();
8440 let yarn_worktree = lsp_store
8441 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8442 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8443 cx.spawn(async move |this, cx| {
8444 let t = this
8445 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8446 .ok()?;
8447 t.await
8448 })
8449 }),
8450 None => Task::ready(None),
8451 })?
8452 .await;
8453 let (worktree_root_target, known_relative_path) =
8454 if let Some((zip_root, relative_path)) = yarn_worktree {
8455 (zip_root, Some(relative_path))
8456 } else {
8457 (Arc::<Path>::from(abs_path.as_path()), None)
8458 };
8459 let (worktree, relative_path) = if let Some(result) =
8460 lsp_store.update(cx, |lsp_store, cx| {
8461 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8462 worktree_store.find_worktree(&worktree_root_target, cx)
8463 })
8464 })? {
8465 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8466 (result.0, relative_path)
8467 } else {
8468 let worktree = lsp_store
8469 .update(cx, |lsp_store, cx| {
8470 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8471 worktree_store.create_worktree(&worktree_root_target, false, cx)
8472 })
8473 })?
8474 .await?;
8475 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8476 lsp_store
8477 .update(cx, |lsp_store, cx| {
8478 if let Some(local) = lsp_store.as_local_mut() {
8479 local.register_language_server_for_invisible_worktree(
8480 &worktree,
8481 language_server_id,
8482 cx,
8483 )
8484 }
8485 })
8486 .ok();
8487 }
8488 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8489 let relative_path = if let Some(known_path) = known_relative_path {
8490 known_path
8491 } else {
8492 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8493 .into_arc()
8494 };
8495 (worktree, relative_path)
8496 };
8497 let project_path = ProjectPath {
8498 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8499 path: relative_path,
8500 };
8501 lsp_store
8502 .update(cx, |lsp_store, cx| {
8503 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8504 buffer_store.open_buffer(project_path, cx)
8505 })
8506 })?
8507 .await
8508 })
8509 }
8510
8511 fn request_multiple_lsp_locally<P, R>(
8512 &mut self,
8513 buffer: &Entity<Buffer>,
8514 position: Option<P>,
8515 request: R,
8516 cx: &mut Context<Self>,
8517 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8518 where
8519 P: ToOffset,
8520 R: LspCommand + Clone,
8521 <R::LspRequest as lsp::request::Request>::Result: Send,
8522 <R::LspRequest as lsp::request::Request>::Params: Send,
8523 {
8524 let Some(local) = self.as_local() else {
8525 return Task::ready(Vec::new());
8526 };
8527
8528 let snapshot = buffer.read(cx).snapshot();
8529 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8530
8531 let server_ids = buffer.update(cx, |buffer, cx| {
8532 local
8533 .language_servers_for_buffer(buffer, cx)
8534 .filter(|(adapter, _)| {
8535 scope
8536 .as_ref()
8537 .map(|scope| scope.language_allowed(&adapter.name))
8538 .unwrap_or(true)
8539 })
8540 .map(|(_, server)| server.server_id())
8541 .filter(|server_id| {
8542 self.as_local().is_none_or(|local| {
8543 local
8544 .buffers_opened_in_servers
8545 .get(&snapshot.remote_id())
8546 .is_some_and(|servers| servers.contains(server_id))
8547 })
8548 })
8549 .collect::<Vec<_>>()
8550 });
8551
8552 let mut response_results = server_ids
8553 .into_iter()
8554 .map(|server_id| {
8555 let task = self.request_lsp(
8556 buffer.clone(),
8557 LanguageServerToQuery::Other(server_id),
8558 request.clone(),
8559 cx,
8560 );
8561 async move { (server_id, task.await) }
8562 })
8563 .collect::<FuturesUnordered<_>>();
8564
8565 cx.background_spawn(async move {
8566 let mut responses = Vec::with_capacity(response_results.len());
8567 while let Some((server_id, response_result)) = response_results.next().await {
8568 match response_result {
8569 Ok(response) => responses.push((server_id, response)),
8570 // rust-analyzer likes to error with this when its still loading up
8571 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8572 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8573 }
8574 }
8575 responses
8576 })
8577 }
8578
8579 async fn handle_lsp_get_completions(
8580 this: Entity<Self>,
8581 envelope: TypedEnvelope<proto::GetCompletions>,
8582 mut cx: AsyncApp,
8583 ) -> Result<proto::GetCompletionsResponse> {
8584 let sender_id = envelope.original_sender_id().unwrap_or_default();
8585
8586 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8587 let buffer_handle = this.update(&mut cx, |this, cx| {
8588 this.buffer_store.read(cx).get_existing(buffer_id)
8589 })??;
8590 let request = GetCompletions::from_proto(
8591 envelope.payload,
8592 this.clone(),
8593 buffer_handle.clone(),
8594 cx.clone(),
8595 )
8596 .await?;
8597
8598 let server_to_query = match request.server_id {
8599 Some(server_id) => LanguageServerToQuery::Other(server_id),
8600 None => LanguageServerToQuery::FirstCapable,
8601 };
8602
8603 let response = this
8604 .update(&mut cx, |this, cx| {
8605 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8606 })?
8607 .await?;
8608 this.update(&mut cx, |this, cx| {
8609 Ok(GetCompletions::response_to_proto(
8610 response,
8611 this,
8612 sender_id,
8613 &buffer_handle.read(cx).version(),
8614 cx,
8615 ))
8616 })?
8617 }
8618
8619 async fn handle_lsp_command<T: LspCommand>(
8620 this: Entity<Self>,
8621 envelope: TypedEnvelope<T::ProtoRequest>,
8622 mut cx: AsyncApp,
8623 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8624 where
8625 <T::LspRequest as lsp::request::Request>::Params: Send,
8626 <T::LspRequest as lsp::request::Request>::Result: Send,
8627 {
8628 let sender_id = envelope.original_sender_id().unwrap_or_default();
8629 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8630 let buffer_handle = this.update(&mut cx, |this, cx| {
8631 this.buffer_store.read(cx).get_existing(buffer_id)
8632 })??;
8633 let request = T::from_proto(
8634 envelope.payload,
8635 this.clone(),
8636 buffer_handle.clone(),
8637 cx.clone(),
8638 )
8639 .await?;
8640 let response = this
8641 .update(&mut cx, |this, cx| {
8642 this.request_lsp(
8643 buffer_handle.clone(),
8644 LanguageServerToQuery::FirstCapable,
8645 request,
8646 cx,
8647 )
8648 })?
8649 .await?;
8650 this.update(&mut cx, |this, cx| {
8651 Ok(T::response_to_proto(
8652 response,
8653 this,
8654 sender_id,
8655 &buffer_handle.read(cx).version(),
8656 cx,
8657 ))
8658 })?
8659 }
8660
8661 async fn handle_lsp_query(
8662 lsp_store: Entity<Self>,
8663 envelope: TypedEnvelope<proto::LspQuery>,
8664 mut cx: AsyncApp,
8665 ) -> Result<proto::Ack> {
8666 use proto::lsp_query::Request;
8667 let sender_id = envelope.original_sender_id().unwrap_or_default();
8668 let lsp_query = envelope.payload;
8669 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8670 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8671 match lsp_query.request.context("invalid LSP query request")? {
8672 Request::GetReferences(get_references) => {
8673 let position = get_references.position.clone().and_then(deserialize_anchor);
8674 Self::query_lsp_locally::<GetReferences>(
8675 lsp_store,
8676 server_id,
8677 sender_id,
8678 lsp_request_id,
8679 get_references,
8680 position,
8681 &mut cx,
8682 )
8683 .await?;
8684 }
8685 Request::GetDocumentColor(get_document_color) => {
8686 Self::query_lsp_locally::<GetDocumentColor>(
8687 lsp_store,
8688 server_id,
8689 sender_id,
8690 lsp_request_id,
8691 get_document_color,
8692 None,
8693 &mut cx,
8694 )
8695 .await?;
8696 }
8697 Request::GetHover(get_hover) => {
8698 let position = get_hover.position.clone().and_then(deserialize_anchor);
8699 Self::query_lsp_locally::<GetHover>(
8700 lsp_store,
8701 server_id,
8702 sender_id,
8703 lsp_request_id,
8704 get_hover,
8705 position,
8706 &mut cx,
8707 )
8708 .await?;
8709 }
8710 Request::GetCodeActions(get_code_actions) => {
8711 Self::query_lsp_locally::<GetCodeActions>(
8712 lsp_store,
8713 server_id,
8714 sender_id,
8715 lsp_request_id,
8716 get_code_actions,
8717 None,
8718 &mut cx,
8719 )
8720 .await?;
8721 }
8722 Request::GetSignatureHelp(get_signature_help) => {
8723 let position = get_signature_help
8724 .position
8725 .clone()
8726 .and_then(deserialize_anchor);
8727 Self::query_lsp_locally::<GetSignatureHelp>(
8728 lsp_store,
8729 server_id,
8730 sender_id,
8731 lsp_request_id,
8732 get_signature_help,
8733 position,
8734 &mut cx,
8735 )
8736 .await?;
8737 }
8738 Request::GetCodeLens(get_code_lens) => {
8739 Self::query_lsp_locally::<GetCodeLens>(
8740 lsp_store,
8741 server_id,
8742 sender_id,
8743 lsp_request_id,
8744 get_code_lens,
8745 None,
8746 &mut cx,
8747 )
8748 .await?;
8749 }
8750 Request::GetDefinition(get_definition) => {
8751 let position = get_definition.position.clone().and_then(deserialize_anchor);
8752 Self::query_lsp_locally::<GetDefinitions>(
8753 lsp_store,
8754 server_id,
8755 sender_id,
8756 lsp_request_id,
8757 get_definition,
8758 position,
8759 &mut cx,
8760 )
8761 .await?;
8762 }
8763 Request::GetDeclaration(get_declaration) => {
8764 let position = get_declaration
8765 .position
8766 .clone()
8767 .and_then(deserialize_anchor);
8768 Self::query_lsp_locally::<GetDeclarations>(
8769 lsp_store,
8770 server_id,
8771 sender_id,
8772 lsp_request_id,
8773 get_declaration,
8774 position,
8775 &mut cx,
8776 )
8777 .await?;
8778 }
8779 Request::GetTypeDefinition(get_type_definition) => {
8780 let position = get_type_definition
8781 .position
8782 .clone()
8783 .and_then(deserialize_anchor);
8784 Self::query_lsp_locally::<GetTypeDefinitions>(
8785 lsp_store,
8786 server_id,
8787 sender_id,
8788 lsp_request_id,
8789 get_type_definition,
8790 position,
8791 &mut cx,
8792 )
8793 .await?;
8794 }
8795 Request::GetImplementation(get_implementation) => {
8796 let position = get_implementation
8797 .position
8798 .clone()
8799 .and_then(deserialize_anchor);
8800 Self::query_lsp_locally::<GetImplementations>(
8801 lsp_store,
8802 server_id,
8803 sender_id,
8804 lsp_request_id,
8805 get_implementation,
8806 position,
8807 &mut cx,
8808 )
8809 .await?;
8810 }
8811 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8812 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8813 let version = deserialize_version(get_document_diagnostics.buffer_version());
8814 let buffer = lsp_store.update(&mut cx, |this, cx| {
8815 this.buffer_store.read(cx).get_existing(buffer_id)
8816 })??;
8817 buffer
8818 .update(&mut cx, |buffer, _| {
8819 buffer.wait_for_version(version.clone())
8820 })?
8821 .await?;
8822 lsp_store.update(&mut cx, |lsp_store, cx| {
8823 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8824 let key = LspKey {
8825 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8826 server_queried: server_id,
8827 };
8828 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8829 ) {
8830 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8831 lsp_requests.clear();
8832 };
8833 }
8834
8835 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8836 existing_queries.insert(
8837 lsp_request_id,
8838 cx.spawn(async move |lsp_store, cx| {
8839 let diagnostics_pull = lsp_store
8840 .update(cx, |lsp_store, cx| {
8841 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8842 })
8843 .ok();
8844 if let Some(diagnostics_pull) = diagnostics_pull {
8845 match diagnostics_pull.await {
8846 Ok(()) => {}
8847 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8848 };
8849 }
8850 }),
8851 );
8852 })?;
8853 }
8854 Request::InlayHints(inlay_hints) => {
8855 let query_start = inlay_hints
8856 .start
8857 .clone()
8858 .and_then(deserialize_anchor)
8859 .context("invalid inlay hints range start")?;
8860 let query_end = inlay_hints
8861 .end
8862 .clone()
8863 .and_then(deserialize_anchor)
8864 .context("invalid inlay hints range end")?;
8865 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8866 &lsp_store,
8867 server_id,
8868 lsp_request_id,
8869 &inlay_hints,
8870 query_start..query_end,
8871 &mut cx,
8872 )
8873 .await
8874 .context("preparing inlay hints request")?;
8875 Self::query_lsp_locally::<InlayHints>(
8876 lsp_store,
8877 server_id,
8878 sender_id,
8879 lsp_request_id,
8880 inlay_hints,
8881 None,
8882 &mut cx,
8883 )
8884 .await
8885 .context("querying for inlay hints")?
8886 }
8887 }
8888 Ok(proto::Ack {})
8889 }
8890
8891 async fn handle_lsp_query_response(
8892 lsp_store: Entity<Self>,
8893 envelope: TypedEnvelope<proto::LspQueryResponse>,
8894 cx: AsyncApp,
8895 ) -> Result<()> {
8896 lsp_store.read_with(&cx, |lsp_store, _| {
8897 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8898 upstream_client.handle_lsp_response(envelope.clone());
8899 }
8900 })?;
8901 Ok(())
8902 }
8903
8904 async fn handle_apply_code_action(
8905 this: Entity<Self>,
8906 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8907 mut cx: AsyncApp,
8908 ) -> Result<proto::ApplyCodeActionResponse> {
8909 let sender_id = envelope.original_sender_id().unwrap_or_default();
8910 let action =
8911 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8912 let apply_code_action = this.update(&mut cx, |this, cx| {
8913 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8914 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8915 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8916 })??;
8917
8918 let project_transaction = apply_code_action.await?;
8919 let project_transaction = this.update(&mut cx, |this, cx| {
8920 this.buffer_store.update(cx, |buffer_store, cx| {
8921 buffer_store.serialize_project_transaction_for_peer(
8922 project_transaction,
8923 sender_id,
8924 cx,
8925 )
8926 })
8927 })?;
8928 Ok(proto::ApplyCodeActionResponse {
8929 transaction: Some(project_transaction),
8930 })
8931 }
8932
8933 async fn handle_register_buffer_with_language_servers(
8934 this: Entity<Self>,
8935 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8936 mut cx: AsyncApp,
8937 ) -> Result<proto::Ack> {
8938 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8939 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8940 this.update(&mut cx, |this, cx| {
8941 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8942 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8943 project_id: upstream_project_id,
8944 buffer_id: buffer_id.to_proto(),
8945 only_servers: envelope.payload.only_servers,
8946 });
8947 }
8948
8949 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8950 anyhow::bail!("buffer is not open");
8951 };
8952
8953 let handle = this.register_buffer_with_language_servers(
8954 &buffer,
8955 envelope
8956 .payload
8957 .only_servers
8958 .into_iter()
8959 .filter_map(|selector| {
8960 Some(match selector.selector? {
8961 proto::language_server_selector::Selector::ServerId(server_id) => {
8962 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8963 }
8964 proto::language_server_selector::Selector::Name(name) => {
8965 LanguageServerSelector::Name(LanguageServerName(
8966 SharedString::from(name),
8967 ))
8968 }
8969 })
8970 })
8971 .collect(),
8972 false,
8973 cx,
8974 );
8975 this.buffer_store().update(cx, |buffer_store, _| {
8976 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8977 });
8978
8979 Ok(())
8980 })??;
8981 Ok(proto::Ack {})
8982 }
8983
8984 async fn handle_rename_project_entry(
8985 this: Entity<Self>,
8986 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8987 mut cx: AsyncApp,
8988 ) -> Result<proto::ProjectEntryResponse> {
8989 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8990 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8991 let new_path =
8992 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8993
8994 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8995 .update(&mut cx, |this, cx| {
8996 let (worktree, entry) = this
8997 .worktree_store
8998 .read(cx)
8999 .worktree_and_entry_for_id(entry_id, cx)?;
9000 let new_worktree = this
9001 .worktree_store
9002 .read(cx)
9003 .worktree_for_id(new_worktree_id, cx)?;
9004 Some((
9005 this.worktree_store.clone(),
9006 worktree,
9007 new_worktree,
9008 entry.clone(),
9009 ))
9010 })?
9011 .context("worktree not found")?;
9012 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9013 (worktree.absolutize(&old_entry.path), worktree.id())
9014 })?;
9015 let new_abs_path =
9016 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9017
9018 let _transaction = Self::will_rename_entry(
9019 this.downgrade(),
9020 old_worktree_id,
9021 &old_abs_path,
9022 &new_abs_path,
9023 old_entry.is_dir(),
9024 cx.clone(),
9025 )
9026 .await;
9027 let response = WorktreeStore::handle_rename_project_entry(
9028 worktree_store,
9029 envelope.payload,
9030 cx.clone(),
9031 )
9032 .await;
9033 this.read_with(&cx, |this, _| {
9034 this.did_rename_entry(
9035 old_worktree_id,
9036 &old_abs_path,
9037 &new_abs_path,
9038 old_entry.is_dir(),
9039 );
9040 })
9041 .ok();
9042 response
9043 }
9044
9045 async fn handle_update_diagnostic_summary(
9046 this: Entity<Self>,
9047 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9048 mut cx: AsyncApp,
9049 ) -> Result<()> {
9050 this.update(&mut cx, |lsp_store, cx| {
9051 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9052 let mut updated_diagnostics_paths = HashMap::default();
9053 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9054 for message_summary in envelope
9055 .payload
9056 .summary
9057 .into_iter()
9058 .chain(envelope.payload.more_summaries)
9059 {
9060 let project_path = ProjectPath {
9061 worktree_id,
9062 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9063 };
9064 let path = project_path.path.clone();
9065 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9066 let summary = DiagnosticSummary {
9067 error_count: message_summary.error_count as usize,
9068 warning_count: message_summary.warning_count as usize,
9069 };
9070
9071 if summary.is_empty() {
9072 if let Some(worktree_summaries) =
9073 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9074 && let Some(summaries) = worktree_summaries.get_mut(&path)
9075 {
9076 summaries.remove(&server_id);
9077 if summaries.is_empty() {
9078 worktree_summaries.remove(&path);
9079 }
9080 }
9081 } else {
9082 lsp_store
9083 .diagnostic_summaries
9084 .entry(worktree_id)
9085 .or_default()
9086 .entry(path)
9087 .or_default()
9088 .insert(server_id, summary);
9089 }
9090
9091 if let Some((_, project_id)) = &lsp_store.downstream_client {
9092 match &mut diagnostics_summary {
9093 Some(diagnostics_summary) => {
9094 diagnostics_summary
9095 .more_summaries
9096 .push(proto::DiagnosticSummary {
9097 path: project_path.path.as_ref().to_proto(),
9098 language_server_id: server_id.0 as u64,
9099 error_count: summary.error_count as u32,
9100 warning_count: summary.warning_count as u32,
9101 })
9102 }
9103 None => {
9104 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9105 project_id: *project_id,
9106 worktree_id: worktree_id.to_proto(),
9107 summary: Some(proto::DiagnosticSummary {
9108 path: project_path.path.as_ref().to_proto(),
9109 language_server_id: server_id.0 as u64,
9110 error_count: summary.error_count as u32,
9111 warning_count: summary.warning_count as u32,
9112 }),
9113 more_summaries: Vec::new(),
9114 })
9115 }
9116 }
9117 }
9118 updated_diagnostics_paths
9119 .entry(server_id)
9120 .or_insert_with(Vec::new)
9121 .push(project_path);
9122 }
9123
9124 if let Some((diagnostics_summary, (downstream_client, _))) =
9125 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9126 {
9127 downstream_client.send(diagnostics_summary).log_err();
9128 }
9129 for (server_id, paths) in updated_diagnostics_paths {
9130 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9131 }
9132 Ok(())
9133 })?
9134 }
9135
9136 async fn handle_start_language_server(
9137 lsp_store: Entity<Self>,
9138 envelope: TypedEnvelope<proto::StartLanguageServer>,
9139 mut cx: AsyncApp,
9140 ) -> Result<()> {
9141 let server = envelope.payload.server.context("invalid server")?;
9142 let server_capabilities =
9143 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9144 .with_context(|| {
9145 format!(
9146 "incorrect server capabilities {}",
9147 envelope.payload.capabilities
9148 )
9149 })?;
9150 lsp_store.update(&mut cx, |lsp_store, cx| {
9151 let server_id = LanguageServerId(server.id as usize);
9152 let server_name = LanguageServerName::from_proto(server.name.clone());
9153 lsp_store
9154 .lsp_server_capabilities
9155 .insert(server_id, server_capabilities);
9156 lsp_store.language_server_statuses.insert(
9157 server_id,
9158 LanguageServerStatus {
9159 name: server_name.clone(),
9160 pending_work: Default::default(),
9161 has_pending_diagnostic_updates: false,
9162 progress_tokens: Default::default(),
9163 worktree: server.worktree_id.map(WorktreeId::from_proto),
9164 binary: None,
9165 configuration: None,
9166 workspace_folders: BTreeSet::new(),
9167 },
9168 );
9169 cx.emit(LspStoreEvent::LanguageServerAdded(
9170 server_id,
9171 server_name,
9172 server.worktree_id.map(WorktreeId::from_proto),
9173 ));
9174 cx.notify();
9175 })?;
9176 Ok(())
9177 }
9178
9179 async fn handle_update_language_server(
9180 lsp_store: Entity<Self>,
9181 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9182 mut cx: AsyncApp,
9183 ) -> Result<()> {
9184 lsp_store.update(&mut cx, |lsp_store, cx| {
9185 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9186
9187 match envelope.payload.variant.context("invalid variant")? {
9188 proto::update_language_server::Variant::WorkStart(payload) => {
9189 lsp_store.on_lsp_work_start(
9190 language_server_id,
9191 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9192 .context("invalid progress token value")?,
9193 LanguageServerProgress {
9194 title: payload.title,
9195 is_disk_based_diagnostics_progress: false,
9196 is_cancellable: payload.is_cancellable.unwrap_or(false),
9197 message: payload.message,
9198 percentage: payload.percentage.map(|p| p as usize),
9199 last_update_at: cx.background_executor().now(),
9200 },
9201 cx,
9202 );
9203 }
9204 proto::update_language_server::Variant::WorkProgress(payload) => {
9205 lsp_store.on_lsp_work_progress(
9206 language_server_id,
9207 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9208 .context("invalid progress token value")?,
9209 LanguageServerProgress {
9210 title: None,
9211 is_disk_based_diagnostics_progress: false,
9212 is_cancellable: payload.is_cancellable.unwrap_or(false),
9213 message: payload.message,
9214 percentage: payload.percentage.map(|p| p as usize),
9215 last_update_at: cx.background_executor().now(),
9216 },
9217 cx,
9218 );
9219 }
9220
9221 proto::update_language_server::Variant::WorkEnd(payload) => {
9222 lsp_store.on_lsp_work_end(
9223 language_server_id,
9224 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9225 .context("invalid progress token value")?,
9226 cx,
9227 );
9228 }
9229
9230 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9231 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9232 }
9233
9234 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9235 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9236 }
9237
9238 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9239 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9240 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9241 cx.emit(LspStoreEvent::LanguageServerUpdate {
9242 language_server_id,
9243 name: envelope
9244 .payload
9245 .server_name
9246 .map(SharedString::new)
9247 .map(LanguageServerName),
9248 message: non_lsp,
9249 });
9250 }
9251 }
9252
9253 Ok(())
9254 })?
9255 }
9256
9257 async fn handle_language_server_log(
9258 this: Entity<Self>,
9259 envelope: TypedEnvelope<proto::LanguageServerLog>,
9260 mut cx: AsyncApp,
9261 ) -> Result<()> {
9262 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9263 let log_type = envelope
9264 .payload
9265 .log_type
9266 .map(LanguageServerLogType::from_proto)
9267 .context("invalid language server log type")?;
9268
9269 let message = envelope.payload.message;
9270
9271 this.update(&mut cx, |_, cx| {
9272 cx.emit(LspStoreEvent::LanguageServerLog(
9273 language_server_id,
9274 log_type,
9275 message,
9276 ));
9277 })
9278 }
9279
9280 async fn handle_lsp_ext_cancel_flycheck(
9281 lsp_store: Entity<Self>,
9282 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9283 cx: AsyncApp,
9284 ) -> Result<proto::Ack> {
9285 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9286 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9287 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9288 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9289 } else {
9290 None
9291 }
9292 })?;
9293 if let Some(task) = task {
9294 task.context("handling lsp ext cancel flycheck")?;
9295 }
9296
9297 Ok(proto::Ack {})
9298 }
9299
9300 async fn handle_lsp_ext_run_flycheck(
9301 lsp_store: Entity<Self>,
9302 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9303 mut cx: AsyncApp,
9304 ) -> Result<proto::Ack> {
9305 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9306 lsp_store.update(&mut cx, |lsp_store, cx| {
9307 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9308 let text_document = if envelope.payload.current_file_only {
9309 let buffer_id = envelope
9310 .payload
9311 .buffer_id
9312 .map(|id| BufferId::new(id))
9313 .transpose()?;
9314 buffer_id
9315 .and_then(|buffer_id| {
9316 lsp_store
9317 .buffer_store()
9318 .read(cx)
9319 .get(buffer_id)
9320 .and_then(|buffer| {
9321 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9322 })
9323 .map(|path| make_text_document_identifier(&path))
9324 })
9325 .transpose()?
9326 } else {
9327 None
9328 };
9329 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9330 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9331 )?;
9332 }
9333 anyhow::Ok(())
9334 })??;
9335
9336 Ok(proto::Ack {})
9337 }
9338
9339 async fn handle_lsp_ext_clear_flycheck(
9340 lsp_store: Entity<Self>,
9341 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9342 cx: AsyncApp,
9343 ) -> Result<proto::Ack> {
9344 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9345 lsp_store
9346 .read_with(&cx, |lsp_store, _| {
9347 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9348 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9349 } else {
9350 None
9351 }
9352 })
9353 .context("handling lsp ext clear flycheck")?;
9354
9355 Ok(proto::Ack {})
9356 }
9357
9358 pub fn disk_based_diagnostics_started(
9359 &mut self,
9360 language_server_id: LanguageServerId,
9361 cx: &mut Context<Self>,
9362 ) {
9363 if let Some(language_server_status) =
9364 self.language_server_statuses.get_mut(&language_server_id)
9365 {
9366 language_server_status.has_pending_diagnostic_updates = true;
9367 }
9368
9369 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9370 cx.emit(LspStoreEvent::LanguageServerUpdate {
9371 language_server_id,
9372 name: self
9373 .language_server_adapter_for_id(language_server_id)
9374 .map(|adapter| adapter.name()),
9375 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9376 Default::default(),
9377 ),
9378 })
9379 }
9380
9381 pub fn disk_based_diagnostics_finished(
9382 &mut self,
9383 language_server_id: LanguageServerId,
9384 cx: &mut Context<Self>,
9385 ) {
9386 if let Some(language_server_status) =
9387 self.language_server_statuses.get_mut(&language_server_id)
9388 {
9389 language_server_status.has_pending_diagnostic_updates = false;
9390 }
9391
9392 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9393 cx.emit(LspStoreEvent::LanguageServerUpdate {
9394 language_server_id,
9395 name: self
9396 .language_server_adapter_for_id(language_server_id)
9397 .map(|adapter| adapter.name()),
9398 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9399 Default::default(),
9400 ),
9401 })
9402 }
9403
9404 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9405 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9406 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9407 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9408 // the language server might take some time to publish diagnostics.
9409 fn simulate_disk_based_diagnostics_events_if_needed(
9410 &mut self,
9411 language_server_id: LanguageServerId,
9412 cx: &mut Context<Self>,
9413 ) {
9414 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9415
9416 let Some(LanguageServerState::Running {
9417 simulate_disk_based_diagnostics_completion,
9418 adapter,
9419 ..
9420 }) = self
9421 .as_local_mut()
9422 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9423 else {
9424 return;
9425 };
9426
9427 if adapter.disk_based_diagnostics_progress_token.is_some() {
9428 return;
9429 }
9430
9431 let prev_task =
9432 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9433 cx.background_executor()
9434 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9435 .await;
9436
9437 this.update(cx, |this, cx| {
9438 this.disk_based_diagnostics_finished(language_server_id, cx);
9439
9440 if let Some(LanguageServerState::Running {
9441 simulate_disk_based_diagnostics_completion,
9442 ..
9443 }) = this.as_local_mut().and_then(|local_store| {
9444 local_store.language_servers.get_mut(&language_server_id)
9445 }) {
9446 *simulate_disk_based_diagnostics_completion = None;
9447 }
9448 })
9449 .ok();
9450 }));
9451
9452 if prev_task.is_none() {
9453 self.disk_based_diagnostics_started(language_server_id, cx);
9454 }
9455 }
9456
9457 pub fn language_server_statuses(
9458 &self,
9459 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9460 self.language_server_statuses
9461 .iter()
9462 .map(|(key, value)| (*key, value))
9463 }
9464
9465 pub(super) fn did_rename_entry(
9466 &self,
9467 worktree_id: WorktreeId,
9468 old_path: &Path,
9469 new_path: &Path,
9470 is_dir: bool,
9471 ) {
9472 maybe!({
9473 let local_store = self.as_local()?;
9474
9475 let old_uri = lsp::Uri::from_file_path(old_path)
9476 .ok()
9477 .map(|uri| uri.to_string())?;
9478 let new_uri = lsp::Uri::from_file_path(new_path)
9479 .ok()
9480 .map(|uri| uri.to_string())?;
9481
9482 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9483 let Some(filter) = local_store
9484 .language_server_paths_watched_for_rename
9485 .get(&language_server.server_id())
9486 else {
9487 continue;
9488 };
9489
9490 if filter.should_send_did_rename(&old_uri, is_dir) {
9491 language_server
9492 .notify::<DidRenameFiles>(RenameFilesParams {
9493 files: vec![FileRename {
9494 old_uri: old_uri.clone(),
9495 new_uri: new_uri.clone(),
9496 }],
9497 })
9498 .ok();
9499 }
9500 }
9501 Some(())
9502 });
9503 }
9504
9505 pub(super) fn will_rename_entry(
9506 this: WeakEntity<Self>,
9507 worktree_id: WorktreeId,
9508 old_path: &Path,
9509 new_path: &Path,
9510 is_dir: bool,
9511 cx: AsyncApp,
9512 ) -> Task<ProjectTransaction> {
9513 let old_uri = lsp::Uri::from_file_path(old_path)
9514 .ok()
9515 .map(|uri| uri.to_string());
9516 let new_uri = lsp::Uri::from_file_path(new_path)
9517 .ok()
9518 .map(|uri| uri.to_string());
9519 cx.spawn(async move |cx| {
9520 let mut tasks = vec![];
9521 this.update(cx, |this, cx| {
9522 let local_store = this.as_local()?;
9523 let old_uri = old_uri?;
9524 let new_uri = new_uri?;
9525 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9526 let Some(filter) = local_store
9527 .language_server_paths_watched_for_rename
9528 .get(&language_server.server_id())
9529 else {
9530 continue;
9531 };
9532
9533 if filter.should_send_will_rename(&old_uri, is_dir) {
9534 let apply_edit = cx.spawn({
9535 let old_uri = old_uri.clone();
9536 let new_uri = new_uri.clone();
9537 let language_server = language_server.clone();
9538 async move |this, cx| {
9539 let edit = language_server
9540 .request::<WillRenameFiles>(RenameFilesParams {
9541 files: vec![FileRename { old_uri, new_uri }],
9542 })
9543 .await
9544 .into_response()
9545 .context("will rename files")
9546 .log_err()
9547 .flatten()?;
9548
9549 let transaction = LocalLspStore::deserialize_workspace_edit(
9550 this.upgrade()?,
9551 edit,
9552 false,
9553 language_server.clone(),
9554 cx,
9555 )
9556 .await
9557 .ok()?;
9558 Some(transaction)
9559 }
9560 });
9561 tasks.push(apply_edit);
9562 }
9563 }
9564 Some(())
9565 })
9566 .ok()
9567 .flatten();
9568 let mut merged_transaction = ProjectTransaction::default();
9569 for task in tasks {
9570 // Await on tasks sequentially so that the order of application of edits is deterministic
9571 // (at least with regards to the order of registration of language servers)
9572 if let Some(transaction) = task.await {
9573 for (buffer, buffer_transaction) in transaction.0 {
9574 merged_transaction.0.insert(buffer, buffer_transaction);
9575 }
9576 }
9577 }
9578 merged_transaction
9579 })
9580 }
9581
9582 fn lsp_notify_abs_paths_changed(
9583 &mut self,
9584 server_id: LanguageServerId,
9585 changes: Vec<PathEvent>,
9586 ) {
9587 maybe!({
9588 let server = self.language_server_for_id(server_id)?;
9589 let changes = changes
9590 .into_iter()
9591 .filter_map(|event| {
9592 let typ = match event.kind? {
9593 PathEventKind::Created => lsp::FileChangeType::CREATED,
9594 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9595 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9596 };
9597 Some(lsp::FileEvent {
9598 uri: file_path_to_lsp_url(&event.path).log_err()?,
9599 typ,
9600 })
9601 })
9602 .collect::<Vec<_>>();
9603 if !changes.is_empty() {
9604 server
9605 .notify::<lsp::notification::DidChangeWatchedFiles>(
9606 lsp::DidChangeWatchedFilesParams { changes },
9607 )
9608 .ok();
9609 }
9610 Some(())
9611 });
9612 }
9613
9614 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9615 self.as_local()?.language_server_for_id(id)
9616 }
9617
9618 fn on_lsp_progress(
9619 &mut self,
9620 progress_params: lsp::ProgressParams,
9621 language_server_id: LanguageServerId,
9622 disk_based_diagnostics_progress_token: Option<String>,
9623 cx: &mut Context<Self>,
9624 ) {
9625 match progress_params.value {
9626 lsp::ProgressParamsValue::WorkDone(progress) => {
9627 self.handle_work_done_progress(
9628 progress,
9629 language_server_id,
9630 disk_based_diagnostics_progress_token,
9631 ProgressToken::from_lsp(progress_params.token),
9632 cx,
9633 );
9634 }
9635 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9636 let identifier = match progress_params.token {
9637 lsp::NumberOrString::Number(_) => None,
9638 lsp::NumberOrString::String(token) => token
9639 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9640 .map(|(_, id)| id.to_owned()),
9641 };
9642 if let Some(LanguageServerState::Running {
9643 workspace_diagnostics_refresh_tasks,
9644 ..
9645 }) = self
9646 .as_local_mut()
9647 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9648 && let Some(workspace_diagnostics) =
9649 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9650 {
9651 workspace_diagnostics.progress_tx.try_send(()).ok();
9652 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9653 }
9654 }
9655 }
9656 }
9657
9658 fn handle_work_done_progress(
9659 &mut self,
9660 progress: lsp::WorkDoneProgress,
9661 language_server_id: LanguageServerId,
9662 disk_based_diagnostics_progress_token: Option<String>,
9663 token: ProgressToken,
9664 cx: &mut Context<Self>,
9665 ) {
9666 let language_server_status =
9667 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9668 status
9669 } else {
9670 return;
9671 };
9672
9673 if !language_server_status.progress_tokens.contains(&token) {
9674 return;
9675 }
9676
9677 let is_disk_based_diagnostics_progress =
9678 if let (Some(disk_based_token), ProgressToken::String(token)) =
9679 (&disk_based_diagnostics_progress_token, &token)
9680 {
9681 token.starts_with(disk_based_token)
9682 } else {
9683 false
9684 };
9685
9686 match progress {
9687 lsp::WorkDoneProgress::Begin(report) => {
9688 if is_disk_based_diagnostics_progress {
9689 self.disk_based_diagnostics_started(language_server_id, cx);
9690 }
9691 self.on_lsp_work_start(
9692 language_server_id,
9693 token.clone(),
9694 LanguageServerProgress {
9695 title: Some(report.title),
9696 is_disk_based_diagnostics_progress,
9697 is_cancellable: report.cancellable.unwrap_or(false),
9698 message: report.message.clone(),
9699 percentage: report.percentage.map(|p| p as usize),
9700 last_update_at: cx.background_executor().now(),
9701 },
9702 cx,
9703 );
9704 }
9705 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9706 language_server_id,
9707 token,
9708 LanguageServerProgress {
9709 title: None,
9710 is_disk_based_diagnostics_progress,
9711 is_cancellable: report.cancellable.unwrap_or(false),
9712 message: report.message,
9713 percentage: report.percentage.map(|p| p as usize),
9714 last_update_at: cx.background_executor().now(),
9715 },
9716 cx,
9717 ),
9718 lsp::WorkDoneProgress::End(_) => {
9719 language_server_status.progress_tokens.remove(&token);
9720 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9721 if is_disk_based_diagnostics_progress {
9722 self.disk_based_diagnostics_finished(language_server_id, cx);
9723 }
9724 }
9725 }
9726 }
9727
9728 fn on_lsp_work_start(
9729 &mut self,
9730 language_server_id: LanguageServerId,
9731 token: ProgressToken,
9732 progress: LanguageServerProgress,
9733 cx: &mut Context<Self>,
9734 ) {
9735 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9736 status.pending_work.insert(token.clone(), progress.clone());
9737 cx.notify();
9738 }
9739 cx.emit(LspStoreEvent::LanguageServerUpdate {
9740 language_server_id,
9741 name: self
9742 .language_server_adapter_for_id(language_server_id)
9743 .map(|adapter| adapter.name()),
9744 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9745 token: Some(token.to_proto()),
9746 title: progress.title,
9747 message: progress.message,
9748 percentage: progress.percentage.map(|p| p as u32),
9749 is_cancellable: Some(progress.is_cancellable),
9750 }),
9751 })
9752 }
9753
9754 fn on_lsp_work_progress(
9755 &mut self,
9756 language_server_id: LanguageServerId,
9757 token: ProgressToken,
9758 progress: LanguageServerProgress,
9759 cx: &mut Context<Self>,
9760 ) {
9761 let mut did_update = false;
9762 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9763 match status.pending_work.entry(token.clone()) {
9764 btree_map::Entry::Vacant(entry) => {
9765 entry.insert(progress.clone());
9766 did_update = true;
9767 }
9768 btree_map::Entry::Occupied(mut entry) => {
9769 let entry = entry.get_mut();
9770 if (progress.last_update_at - entry.last_update_at)
9771 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9772 {
9773 entry.last_update_at = progress.last_update_at;
9774 if progress.message.is_some() {
9775 entry.message = progress.message.clone();
9776 }
9777 if progress.percentage.is_some() {
9778 entry.percentage = progress.percentage;
9779 }
9780 if progress.is_cancellable != entry.is_cancellable {
9781 entry.is_cancellable = progress.is_cancellable;
9782 }
9783 did_update = true;
9784 }
9785 }
9786 }
9787 }
9788
9789 if did_update {
9790 cx.emit(LspStoreEvent::LanguageServerUpdate {
9791 language_server_id,
9792 name: self
9793 .language_server_adapter_for_id(language_server_id)
9794 .map(|adapter| adapter.name()),
9795 message: proto::update_language_server::Variant::WorkProgress(
9796 proto::LspWorkProgress {
9797 token: Some(token.to_proto()),
9798 message: progress.message,
9799 percentage: progress.percentage.map(|p| p as u32),
9800 is_cancellable: Some(progress.is_cancellable),
9801 },
9802 ),
9803 })
9804 }
9805 }
9806
9807 fn on_lsp_work_end(
9808 &mut self,
9809 language_server_id: LanguageServerId,
9810 token: ProgressToken,
9811 cx: &mut Context<Self>,
9812 ) {
9813 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9814 if let Some(work) = status.pending_work.remove(&token)
9815 && !work.is_disk_based_diagnostics_progress
9816 {
9817 cx.emit(LspStoreEvent::RefreshInlayHints {
9818 server_id: language_server_id,
9819 request_id: None,
9820 });
9821 }
9822 cx.notify();
9823 }
9824
9825 cx.emit(LspStoreEvent::LanguageServerUpdate {
9826 language_server_id,
9827 name: self
9828 .language_server_adapter_for_id(language_server_id)
9829 .map(|adapter| adapter.name()),
9830 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9831 token: Some(token.to_proto()),
9832 }),
9833 })
9834 }
9835
9836 pub async fn handle_resolve_completion_documentation(
9837 this: Entity<Self>,
9838 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9839 mut cx: AsyncApp,
9840 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9841 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9842
9843 let completion = this
9844 .read_with(&cx, |this, cx| {
9845 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9846 let server = this
9847 .language_server_for_id(id)
9848 .with_context(|| format!("No language server {id}"))?;
9849
9850 anyhow::Ok(cx.background_spawn(async move {
9851 let can_resolve = server
9852 .capabilities()
9853 .completion_provider
9854 .as_ref()
9855 .and_then(|options| options.resolve_provider)
9856 .unwrap_or(false);
9857 if can_resolve {
9858 server
9859 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9860 .await
9861 .into_response()
9862 .context("resolve completion item")
9863 } else {
9864 anyhow::Ok(lsp_completion)
9865 }
9866 }))
9867 })??
9868 .await?;
9869
9870 let mut documentation_is_markdown = false;
9871 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9872 let documentation = match completion.documentation {
9873 Some(lsp::Documentation::String(text)) => text,
9874
9875 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9876 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9877 value
9878 }
9879
9880 _ => String::new(),
9881 };
9882
9883 // If we have a new buffer_id, that means we're talking to a new client
9884 // and want to check for new text_edits in the completion too.
9885 let mut old_replace_start = None;
9886 let mut old_replace_end = None;
9887 let mut old_insert_start = None;
9888 let mut old_insert_end = None;
9889 let mut new_text = String::default();
9890 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9891 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9892 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9893 anyhow::Ok(buffer.read(cx).snapshot())
9894 })??;
9895
9896 if let Some(text_edit) = completion.text_edit.as_ref() {
9897 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9898
9899 if let Some(mut edit) = edit {
9900 LineEnding::normalize(&mut edit.new_text);
9901
9902 new_text = edit.new_text;
9903 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9904 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9905 if let Some(insert_range) = edit.insert_range {
9906 old_insert_start = Some(serialize_anchor(&insert_range.start));
9907 old_insert_end = Some(serialize_anchor(&insert_range.end));
9908 }
9909 }
9910 }
9911 }
9912
9913 Ok(proto::ResolveCompletionDocumentationResponse {
9914 documentation,
9915 documentation_is_markdown,
9916 old_replace_start,
9917 old_replace_end,
9918 new_text,
9919 lsp_completion,
9920 old_insert_start,
9921 old_insert_end,
9922 })
9923 }
9924
9925 async fn handle_on_type_formatting(
9926 this: Entity<Self>,
9927 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9928 mut cx: AsyncApp,
9929 ) -> Result<proto::OnTypeFormattingResponse> {
9930 let on_type_formatting = this.update(&mut cx, |this, cx| {
9931 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9932 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9933 let position = envelope
9934 .payload
9935 .position
9936 .and_then(deserialize_anchor)
9937 .context("invalid position")?;
9938 anyhow::Ok(this.apply_on_type_formatting(
9939 buffer,
9940 position,
9941 envelope.payload.trigger.clone(),
9942 cx,
9943 ))
9944 })??;
9945
9946 let transaction = on_type_formatting
9947 .await?
9948 .as_ref()
9949 .map(language::proto::serialize_transaction);
9950 Ok(proto::OnTypeFormattingResponse { transaction })
9951 }
9952
9953 async fn handle_refresh_inlay_hints(
9954 lsp_store: Entity<Self>,
9955 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9956 mut cx: AsyncApp,
9957 ) -> Result<proto::Ack> {
9958 lsp_store.update(&mut cx, |_, cx| {
9959 cx.emit(LspStoreEvent::RefreshInlayHints {
9960 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9961 request_id: envelope.payload.request_id.map(|id| id as usize),
9962 });
9963 })?;
9964 Ok(proto::Ack {})
9965 }
9966
9967 async fn handle_pull_workspace_diagnostics(
9968 lsp_store: Entity<Self>,
9969 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9970 mut cx: AsyncApp,
9971 ) -> Result<proto::Ack> {
9972 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9973 lsp_store.update(&mut cx, |lsp_store, _| {
9974 lsp_store.pull_workspace_diagnostics(server_id);
9975 })?;
9976 Ok(proto::Ack {})
9977 }
9978
9979 async fn handle_get_color_presentation(
9980 lsp_store: Entity<Self>,
9981 envelope: TypedEnvelope<proto::GetColorPresentation>,
9982 mut cx: AsyncApp,
9983 ) -> Result<proto::GetColorPresentationResponse> {
9984 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9985 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9986 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9987 })??;
9988
9989 let color = envelope
9990 .payload
9991 .color
9992 .context("invalid color resolve request")?;
9993 let start = color
9994 .lsp_range_start
9995 .context("invalid color resolve request")?;
9996 let end = color
9997 .lsp_range_end
9998 .context("invalid color resolve request")?;
9999
10000 let color = DocumentColor {
10001 lsp_range: lsp::Range {
10002 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10003 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10004 },
10005 color: lsp::Color {
10006 red: color.red,
10007 green: color.green,
10008 blue: color.blue,
10009 alpha: color.alpha,
10010 },
10011 resolved: false,
10012 color_presentations: Vec::new(),
10013 };
10014 let resolved_color = lsp_store
10015 .update(&mut cx, |lsp_store, cx| {
10016 lsp_store.resolve_color_presentation(
10017 color,
10018 buffer.clone(),
10019 LanguageServerId(envelope.payload.server_id as usize),
10020 cx,
10021 )
10022 })?
10023 .await
10024 .context("resolving color presentation")?;
10025
10026 Ok(proto::GetColorPresentationResponse {
10027 presentations: resolved_color
10028 .color_presentations
10029 .into_iter()
10030 .map(|presentation| proto::ColorPresentation {
10031 label: presentation.label.to_string(),
10032 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10033 additional_text_edits: presentation
10034 .additional_text_edits
10035 .into_iter()
10036 .map(serialize_lsp_edit)
10037 .collect(),
10038 })
10039 .collect(),
10040 })
10041 }
10042
10043 async fn handle_resolve_inlay_hint(
10044 lsp_store: Entity<Self>,
10045 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10046 mut cx: AsyncApp,
10047 ) -> Result<proto::ResolveInlayHintResponse> {
10048 let proto_hint = envelope
10049 .payload
10050 .hint
10051 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10052 let hint = InlayHints::proto_to_project_hint(proto_hint)
10053 .context("resolved proto inlay hint conversion")?;
10054 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10055 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10056 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10057 })??;
10058 let response_hint = lsp_store
10059 .update(&mut cx, |lsp_store, cx| {
10060 lsp_store.resolve_inlay_hint(
10061 hint,
10062 buffer,
10063 LanguageServerId(envelope.payload.language_server_id as usize),
10064 cx,
10065 )
10066 })?
10067 .await
10068 .context("inlay hints fetch")?;
10069 Ok(proto::ResolveInlayHintResponse {
10070 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10071 })
10072 }
10073
10074 async fn handle_refresh_code_lens(
10075 this: Entity<Self>,
10076 _: TypedEnvelope<proto::RefreshCodeLens>,
10077 mut cx: AsyncApp,
10078 ) -> Result<proto::Ack> {
10079 this.update(&mut cx, |_, cx| {
10080 cx.emit(LspStoreEvent::RefreshCodeLens);
10081 })?;
10082 Ok(proto::Ack {})
10083 }
10084
10085 async fn handle_open_buffer_for_symbol(
10086 this: Entity<Self>,
10087 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10088 mut cx: AsyncApp,
10089 ) -> Result<proto::OpenBufferForSymbolResponse> {
10090 let peer_id = envelope.original_sender_id().unwrap_or_default();
10091 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10092 let symbol = Self::deserialize_symbol(symbol)?;
10093 this.read_with(&cx, |this, _| {
10094 if let SymbolLocation::OutsideProject {
10095 abs_path,
10096 signature,
10097 } = &symbol.path
10098 {
10099 let new_signature = this.symbol_signature(&abs_path);
10100 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10101 }
10102 Ok(())
10103 })??;
10104 let buffer = this
10105 .update(&mut cx, |this, cx| {
10106 this.open_buffer_for_symbol(
10107 &Symbol {
10108 language_server_name: symbol.language_server_name,
10109 source_worktree_id: symbol.source_worktree_id,
10110 source_language_server_id: symbol.source_language_server_id,
10111 path: symbol.path,
10112 name: symbol.name,
10113 kind: symbol.kind,
10114 range: symbol.range,
10115 label: CodeLabel::default(),
10116 },
10117 cx,
10118 )
10119 })?
10120 .await?;
10121
10122 this.update(&mut cx, |this, cx| {
10123 let is_private = buffer
10124 .read(cx)
10125 .file()
10126 .map(|f| f.is_private())
10127 .unwrap_or_default();
10128 if is_private {
10129 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10130 } else {
10131 this.buffer_store
10132 .update(cx, |buffer_store, cx| {
10133 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10134 })
10135 .detach_and_log_err(cx);
10136 let buffer_id = buffer.read(cx).remote_id().to_proto();
10137 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10138 }
10139 })?
10140 }
10141
10142 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10143 let mut hasher = Sha256::new();
10144 hasher.update(abs_path.to_string_lossy().as_bytes());
10145 hasher.update(self.nonce.to_be_bytes());
10146 hasher.finalize().as_slice().try_into().unwrap()
10147 }
10148
10149 pub async fn handle_get_project_symbols(
10150 this: Entity<Self>,
10151 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10152 mut cx: AsyncApp,
10153 ) -> Result<proto::GetProjectSymbolsResponse> {
10154 let symbols = this
10155 .update(&mut cx, |this, cx| {
10156 this.symbols(&envelope.payload.query, cx)
10157 })?
10158 .await?;
10159
10160 Ok(proto::GetProjectSymbolsResponse {
10161 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10162 })
10163 }
10164
10165 pub async fn handle_restart_language_servers(
10166 this: Entity<Self>,
10167 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10168 mut cx: AsyncApp,
10169 ) -> Result<proto::Ack> {
10170 this.update(&mut cx, |lsp_store, cx| {
10171 let buffers =
10172 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10173 lsp_store.restart_language_servers_for_buffers(
10174 buffers,
10175 envelope
10176 .payload
10177 .only_servers
10178 .into_iter()
10179 .filter_map(|selector| {
10180 Some(match selector.selector? {
10181 proto::language_server_selector::Selector::ServerId(server_id) => {
10182 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10183 }
10184 proto::language_server_selector::Selector::Name(name) => {
10185 LanguageServerSelector::Name(LanguageServerName(
10186 SharedString::from(name),
10187 ))
10188 }
10189 })
10190 })
10191 .collect(),
10192 cx,
10193 );
10194 })?;
10195
10196 Ok(proto::Ack {})
10197 }
10198
10199 pub async fn handle_stop_language_servers(
10200 lsp_store: Entity<Self>,
10201 envelope: TypedEnvelope<proto::StopLanguageServers>,
10202 mut cx: AsyncApp,
10203 ) -> Result<proto::Ack> {
10204 lsp_store.update(&mut cx, |lsp_store, cx| {
10205 if envelope.payload.all
10206 && envelope.payload.also_servers.is_empty()
10207 && envelope.payload.buffer_ids.is_empty()
10208 {
10209 lsp_store.stop_all_language_servers(cx);
10210 } else {
10211 let buffers =
10212 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10213 lsp_store
10214 .stop_language_servers_for_buffers(
10215 buffers,
10216 envelope
10217 .payload
10218 .also_servers
10219 .into_iter()
10220 .filter_map(|selector| {
10221 Some(match selector.selector? {
10222 proto::language_server_selector::Selector::ServerId(
10223 server_id,
10224 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10225 server_id,
10226 )),
10227 proto::language_server_selector::Selector::Name(name) => {
10228 LanguageServerSelector::Name(LanguageServerName(
10229 SharedString::from(name),
10230 ))
10231 }
10232 })
10233 })
10234 .collect(),
10235 cx,
10236 )
10237 .detach_and_log_err(cx);
10238 }
10239 })?;
10240
10241 Ok(proto::Ack {})
10242 }
10243
10244 pub async fn handle_cancel_language_server_work(
10245 lsp_store: Entity<Self>,
10246 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10247 mut cx: AsyncApp,
10248 ) -> Result<proto::Ack> {
10249 lsp_store.update(&mut cx, |lsp_store, cx| {
10250 if let Some(work) = envelope.payload.work {
10251 match work {
10252 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10253 let buffers =
10254 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10255 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10256 }
10257 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10258 let server_id = LanguageServerId::from_proto(work.language_server_id);
10259 let token = work
10260 .token
10261 .map(|token| {
10262 ProgressToken::from_proto(token)
10263 .context("invalid work progress token")
10264 })
10265 .transpose()?;
10266 lsp_store.cancel_language_server_work(server_id, token, cx);
10267 }
10268 }
10269 }
10270 anyhow::Ok(())
10271 })??;
10272
10273 Ok(proto::Ack {})
10274 }
10275
10276 fn buffer_ids_to_buffers(
10277 &mut self,
10278 buffer_ids: impl Iterator<Item = u64>,
10279 cx: &mut Context<Self>,
10280 ) -> Vec<Entity<Buffer>> {
10281 buffer_ids
10282 .into_iter()
10283 .flat_map(|buffer_id| {
10284 self.buffer_store
10285 .read(cx)
10286 .get(BufferId::new(buffer_id).log_err()?)
10287 })
10288 .collect::<Vec<_>>()
10289 }
10290
10291 async fn handle_apply_additional_edits_for_completion(
10292 this: Entity<Self>,
10293 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10294 mut cx: AsyncApp,
10295 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10296 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10297 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10298 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10299 let completion = Self::deserialize_completion(
10300 envelope.payload.completion.context("invalid completion")?,
10301 )?;
10302 anyhow::Ok((buffer, completion))
10303 })??;
10304
10305 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10306 this.apply_additional_edits_for_completion(
10307 buffer,
10308 Rc::new(RefCell::new(Box::new([Completion {
10309 replace_range: completion.replace_range,
10310 new_text: completion.new_text,
10311 source: completion.source,
10312 documentation: None,
10313 label: CodeLabel::default(),
10314 match_start: None,
10315 snippet_deduplication_key: None,
10316 insert_text_mode: None,
10317 icon_path: None,
10318 confirm: None,
10319 }]))),
10320 0,
10321 false,
10322 cx,
10323 )
10324 })?;
10325
10326 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10327 transaction: apply_additional_edits
10328 .await?
10329 .as_ref()
10330 .map(language::proto::serialize_transaction),
10331 })
10332 }
10333
10334 pub fn last_formatting_failure(&self) -> Option<&str> {
10335 self.last_formatting_failure.as_deref()
10336 }
10337
10338 pub fn reset_last_formatting_failure(&mut self) {
10339 self.last_formatting_failure = None;
10340 }
10341
10342 pub fn environment_for_buffer(
10343 &self,
10344 buffer: &Entity<Buffer>,
10345 cx: &mut Context<Self>,
10346 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10347 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10348 environment.update(cx, |env, cx| {
10349 env.buffer_environment(buffer, &self.worktree_store, cx)
10350 })
10351 } else {
10352 Task::ready(None).shared()
10353 }
10354 }
10355
10356 pub fn format(
10357 &mut self,
10358 buffers: HashSet<Entity<Buffer>>,
10359 target: LspFormatTarget,
10360 push_to_history: bool,
10361 trigger: FormatTrigger,
10362 cx: &mut Context<Self>,
10363 ) -> Task<anyhow::Result<ProjectTransaction>> {
10364 let logger = zlog::scoped!("format");
10365 if self.as_local().is_some() {
10366 zlog::trace!(logger => "Formatting locally");
10367 let logger = zlog::scoped!(logger => "local");
10368 let buffers = buffers
10369 .into_iter()
10370 .map(|buffer_handle| {
10371 let buffer = buffer_handle.read(cx);
10372 let buffer_abs_path = File::from_dyn(buffer.file())
10373 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10374
10375 (buffer_handle, buffer_abs_path, buffer.remote_id())
10376 })
10377 .collect::<Vec<_>>();
10378
10379 cx.spawn(async move |lsp_store, cx| {
10380 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10381
10382 for (handle, abs_path, id) in buffers {
10383 let env = lsp_store
10384 .update(cx, |lsp_store, cx| {
10385 lsp_store.environment_for_buffer(&handle, cx)
10386 })?
10387 .await;
10388
10389 let ranges = match &target {
10390 LspFormatTarget::Buffers => None,
10391 LspFormatTarget::Ranges(ranges) => {
10392 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10393 }
10394 };
10395
10396 formattable_buffers.push(FormattableBuffer {
10397 handle,
10398 abs_path,
10399 env,
10400 ranges,
10401 });
10402 }
10403 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10404
10405 let format_timer = zlog::time!(logger => "Formatting buffers");
10406 let result = LocalLspStore::format_locally(
10407 lsp_store.clone(),
10408 formattable_buffers,
10409 push_to_history,
10410 trigger,
10411 logger,
10412 cx,
10413 )
10414 .await;
10415 format_timer.end();
10416
10417 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10418
10419 lsp_store.update(cx, |lsp_store, _| {
10420 lsp_store.update_last_formatting_failure(&result);
10421 })?;
10422
10423 result
10424 })
10425 } else if let Some((client, project_id)) = self.upstream_client() {
10426 zlog::trace!(logger => "Formatting remotely");
10427 let logger = zlog::scoped!(logger => "remote");
10428 // Don't support formatting ranges via remote
10429 match target {
10430 LspFormatTarget::Buffers => {}
10431 LspFormatTarget::Ranges(_) => {
10432 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10433 return Task::ready(Ok(ProjectTransaction::default()));
10434 }
10435 }
10436
10437 let buffer_store = self.buffer_store();
10438 cx.spawn(async move |lsp_store, cx| {
10439 zlog::trace!(logger => "Sending remote format request");
10440 let request_timer = zlog::time!(logger => "remote format request");
10441 let result = client
10442 .request(proto::FormatBuffers {
10443 project_id,
10444 trigger: trigger as i32,
10445 buffer_ids: buffers
10446 .iter()
10447 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10448 .collect::<Result<_>>()?,
10449 })
10450 .await
10451 .and_then(|result| result.transaction.context("missing transaction"));
10452 request_timer.end();
10453
10454 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10455
10456 lsp_store.update(cx, |lsp_store, _| {
10457 lsp_store.update_last_formatting_failure(&result);
10458 })?;
10459
10460 let transaction_response = result?;
10461 let _timer = zlog::time!(logger => "deserializing project transaction");
10462 buffer_store
10463 .update(cx, |buffer_store, cx| {
10464 buffer_store.deserialize_project_transaction(
10465 transaction_response,
10466 push_to_history,
10467 cx,
10468 )
10469 })?
10470 .await
10471 })
10472 } else {
10473 zlog::trace!(logger => "Not formatting");
10474 Task::ready(Ok(ProjectTransaction::default()))
10475 }
10476 }
10477
10478 async fn handle_format_buffers(
10479 this: Entity<Self>,
10480 envelope: TypedEnvelope<proto::FormatBuffers>,
10481 mut cx: AsyncApp,
10482 ) -> Result<proto::FormatBuffersResponse> {
10483 let sender_id = envelope.original_sender_id().unwrap_or_default();
10484 let format = this.update(&mut cx, |this, cx| {
10485 let mut buffers = HashSet::default();
10486 for buffer_id in &envelope.payload.buffer_ids {
10487 let buffer_id = BufferId::new(*buffer_id)?;
10488 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10489 }
10490 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10491 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10492 })??;
10493
10494 let project_transaction = format.await?;
10495 let project_transaction = this.update(&mut cx, |this, cx| {
10496 this.buffer_store.update(cx, |buffer_store, cx| {
10497 buffer_store.serialize_project_transaction_for_peer(
10498 project_transaction,
10499 sender_id,
10500 cx,
10501 )
10502 })
10503 })?;
10504 Ok(proto::FormatBuffersResponse {
10505 transaction: Some(project_transaction),
10506 })
10507 }
10508
10509 async fn handle_apply_code_action_kind(
10510 this: Entity<Self>,
10511 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10512 mut cx: AsyncApp,
10513 ) -> Result<proto::ApplyCodeActionKindResponse> {
10514 let sender_id = envelope.original_sender_id().unwrap_or_default();
10515 let format = this.update(&mut cx, |this, cx| {
10516 let mut buffers = HashSet::default();
10517 for buffer_id in &envelope.payload.buffer_ids {
10518 let buffer_id = BufferId::new(*buffer_id)?;
10519 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10520 }
10521 let kind = match envelope.payload.kind.as_str() {
10522 "" => CodeActionKind::EMPTY,
10523 "quickfix" => CodeActionKind::QUICKFIX,
10524 "refactor" => CodeActionKind::REFACTOR,
10525 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10526 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10527 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10528 "source" => CodeActionKind::SOURCE,
10529 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10530 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10531 _ => anyhow::bail!(
10532 "Invalid code action kind {}",
10533 envelope.payload.kind.as_str()
10534 ),
10535 };
10536 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10537 })??;
10538
10539 let project_transaction = format.await?;
10540 let project_transaction = this.update(&mut cx, |this, cx| {
10541 this.buffer_store.update(cx, |buffer_store, cx| {
10542 buffer_store.serialize_project_transaction_for_peer(
10543 project_transaction,
10544 sender_id,
10545 cx,
10546 )
10547 })
10548 })?;
10549 Ok(proto::ApplyCodeActionKindResponse {
10550 transaction: Some(project_transaction),
10551 })
10552 }
10553
10554 async fn shutdown_language_server(
10555 server_state: Option<LanguageServerState>,
10556 name: LanguageServerName,
10557 cx: &mut AsyncApp,
10558 ) {
10559 let server = match server_state {
10560 Some(LanguageServerState::Starting { startup, .. }) => {
10561 let mut timer = cx
10562 .background_executor()
10563 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10564 .fuse();
10565
10566 select! {
10567 server = startup.fuse() => server,
10568 () = timer => {
10569 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10570 None
10571 },
10572 }
10573 }
10574
10575 Some(LanguageServerState::Running { server, .. }) => Some(server),
10576
10577 None => None,
10578 };
10579
10580 if let Some(server) = server
10581 && let Some(shutdown) = server.shutdown()
10582 {
10583 shutdown.await;
10584 }
10585 }
10586
10587 // Returns a list of all of the worktrees which no longer have a language server and the root path
10588 // for the stopped server
10589 fn stop_local_language_server(
10590 &mut self,
10591 server_id: LanguageServerId,
10592 cx: &mut Context<Self>,
10593 ) -> Task<()> {
10594 let local = match &mut self.mode {
10595 LspStoreMode::Local(local) => local,
10596 _ => {
10597 return Task::ready(());
10598 }
10599 };
10600
10601 // Remove this server ID from all entries in the given worktree.
10602 local
10603 .language_server_ids
10604 .retain(|_, state| state.id != server_id);
10605 self.buffer_store.update(cx, |buffer_store, cx| {
10606 for buffer in buffer_store.buffers() {
10607 buffer.update(cx, |buffer, cx| {
10608 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10609 buffer.set_completion_triggers(server_id, Default::default(), cx);
10610 });
10611 }
10612 });
10613
10614 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10615 summaries.retain(|path, summaries_by_server_id| {
10616 if summaries_by_server_id.remove(&server_id).is_some() {
10617 if let Some((client, project_id)) = self.downstream_client.clone() {
10618 client
10619 .send(proto::UpdateDiagnosticSummary {
10620 project_id,
10621 worktree_id: worktree_id.to_proto(),
10622 summary: Some(proto::DiagnosticSummary {
10623 path: path.as_ref().to_proto(),
10624 language_server_id: server_id.0 as u64,
10625 error_count: 0,
10626 warning_count: 0,
10627 }),
10628 more_summaries: Vec::new(),
10629 })
10630 .log_err();
10631 }
10632 !summaries_by_server_id.is_empty()
10633 } else {
10634 true
10635 }
10636 });
10637 }
10638
10639 let local = self.as_local_mut().unwrap();
10640 for diagnostics in local.diagnostics.values_mut() {
10641 diagnostics.retain(|_, diagnostics_by_server_id| {
10642 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10643 diagnostics_by_server_id.remove(ix);
10644 !diagnostics_by_server_id.is_empty()
10645 } else {
10646 true
10647 }
10648 });
10649 }
10650 local.language_server_watched_paths.remove(&server_id);
10651
10652 let server_state = local.language_servers.remove(&server_id);
10653 self.cleanup_lsp_data(server_id);
10654 let name = self
10655 .language_server_statuses
10656 .remove(&server_id)
10657 .map(|status| status.name)
10658 .or_else(|| {
10659 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10660 Some(adapter.name())
10661 } else {
10662 None
10663 }
10664 });
10665
10666 if let Some(name) = name {
10667 log::info!("stopping language server {name}");
10668 self.languages
10669 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10670 cx.notify();
10671
10672 return cx.spawn(async move |lsp_store, cx| {
10673 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10674 lsp_store
10675 .update(cx, |lsp_store, cx| {
10676 lsp_store
10677 .languages
10678 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10679 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10680 cx.notify();
10681 })
10682 .ok();
10683 });
10684 }
10685
10686 if server_state.is_some() {
10687 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10688 }
10689 Task::ready(())
10690 }
10691
10692 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10693 if let Some((client, project_id)) = self.upstream_client() {
10694 let request = client.request(proto::StopLanguageServers {
10695 project_id,
10696 buffer_ids: Vec::new(),
10697 also_servers: Vec::new(),
10698 all: true,
10699 });
10700 cx.background_spawn(request).detach_and_log_err(cx);
10701 } else {
10702 let Some(local) = self.as_local_mut() else {
10703 return;
10704 };
10705 let language_servers_to_stop = local
10706 .language_server_ids
10707 .values()
10708 .map(|state| state.id)
10709 .collect();
10710 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10711 let tasks = language_servers_to_stop
10712 .into_iter()
10713 .map(|server| self.stop_local_language_server(server, cx))
10714 .collect::<Vec<_>>();
10715 cx.background_spawn(async move {
10716 futures::future::join_all(tasks).await;
10717 })
10718 .detach();
10719 }
10720 }
10721
10722 pub fn restart_language_servers_for_buffers(
10723 &mut self,
10724 buffers: Vec<Entity<Buffer>>,
10725 only_restart_servers: HashSet<LanguageServerSelector>,
10726 cx: &mut Context<Self>,
10727 ) {
10728 if let Some((client, project_id)) = self.upstream_client() {
10729 let request = client.request(proto::RestartLanguageServers {
10730 project_id,
10731 buffer_ids: buffers
10732 .into_iter()
10733 .map(|b| b.read(cx).remote_id().to_proto())
10734 .collect(),
10735 only_servers: only_restart_servers
10736 .into_iter()
10737 .map(|selector| {
10738 let selector = match selector {
10739 LanguageServerSelector::Id(language_server_id) => {
10740 proto::language_server_selector::Selector::ServerId(
10741 language_server_id.to_proto(),
10742 )
10743 }
10744 LanguageServerSelector::Name(language_server_name) => {
10745 proto::language_server_selector::Selector::Name(
10746 language_server_name.to_string(),
10747 )
10748 }
10749 };
10750 proto::LanguageServerSelector {
10751 selector: Some(selector),
10752 }
10753 })
10754 .collect(),
10755 all: false,
10756 });
10757 cx.background_spawn(request).detach_and_log_err(cx);
10758 } else {
10759 let stop_task = if only_restart_servers.is_empty() {
10760 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10761 } else {
10762 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10763 };
10764 cx.spawn(async move |lsp_store, cx| {
10765 stop_task.await;
10766 lsp_store
10767 .update(cx, |lsp_store, cx| {
10768 for buffer in buffers {
10769 lsp_store.register_buffer_with_language_servers(
10770 &buffer,
10771 only_restart_servers.clone(),
10772 true,
10773 cx,
10774 );
10775 }
10776 })
10777 .ok()
10778 })
10779 .detach();
10780 }
10781 }
10782
10783 pub fn stop_language_servers_for_buffers(
10784 &mut self,
10785 buffers: Vec<Entity<Buffer>>,
10786 also_stop_servers: HashSet<LanguageServerSelector>,
10787 cx: &mut Context<Self>,
10788 ) -> Task<Result<()>> {
10789 if let Some((client, project_id)) = self.upstream_client() {
10790 let request = client.request(proto::StopLanguageServers {
10791 project_id,
10792 buffer_ids: buffers
10793 .into_iter()
10794 .map(|b| b.read(cx).remote_id().to_proto())
10795 .collect(),
10796 also_servers: also_stop_servers
10797 .into_iter()
10798 .map(|selector| {
10799 let selector = match selector {
10800 LanguageServerSelector::Id(language_server_id) => {
10801 proto::language_server_selector::Selector::ServerId(
10802 language_server_id.to_proto(),
10803 )
10804 }
10805 LanguageServerSelector::Name(language_server_name) => {
10806 proto::language_server_selector::Selector::Name(
10807 language_server_name.to_string(),
10808 )
10809 }
10810 };
10811 proto::LanguageServerSelector {
10812 selector: Some(selector),
10813 }
10814 })
10815 .collect(),
10816 all: false,
10817 });
10818 cx.background_spawn(async move {
10819 let _ = request.await?;
10820 Ok(())
10821 })
10822 } else {
10823 let task =
10824 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10825 cx.background_spawn(async move {
10826 task.await;
10827 Ok(())
10828 })
10829 }
10830 }
10831
10832 fn stop_local_language_servers_for_buffers(
10833 &mut self,
10834 buffers: &[Entity<Buffer>],
10835 also_stop_servers: HashSet<LanguageServerSelector>,
10836 cx: &mut Context<Self>,
10837 ) -> Task<()> {
10838 let Some(local) = self.as_local_mut() else {
10839 return Task::ready(());
10840 };
10841 let mut language_server_names_to_stop = BTreeSet::default();
10842 let mut language_servers_to_stop = also_stop_servers
10843 .into_iter()
10844 .flat_map(|selector| match selector {
10845 LanguageServerSelector::Id(id) => Some(id),
10846 LanguageServerSelector::Name(name) => {
10847 language_server_names_to_stop.insert(name);
10848 None
10849 }
10850 })
10851 .collect::<BTreeSet<_>>();
10852
10853 let mut covered_worktrees = HashSet::default();
10854 for buffer in buffers {
10855 buffer.update(cx, |buffer, cx| {
10856 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10857 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10858 && covered_worktrees.insert(worktree_id)
10859 {
10860 language_server_names_to_stop.retain(|name| {
10861 let old_ids_count = language_servers_to_stop.len();
10862 let all_language_servers_with_this_name = local
10863 .language_server_ids
10864 .iter()
10865 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10866 language_servers_to_stop.extend(all_language_servers_with_this_name);
10867 old_ids_count == language_servers_to_stop.len()
10868 });
10869 }
10870 });
10871 }
10872 for name in language_server_names_to_stop {
10873 language_servers_to_stop.extend(
10874 local
10875 .language_server_ids
10876 .iter()
10877 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10878 );
10879 }
10880
10881 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10882 let tasks = language_servers_to_stop
10883 .into_iter()
10884 .map(|server| self.stop_local_language_server(server, cx))
10885 .collect::<Vec<_>>();
10886
10887 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10888 }
10889
10890 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10891 let (worktree, relative_path) =
10892 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10893
10894 let project_path = ProjectPath {
10895 worktree_id: worktree.read(cx).id(),
10896 path: relative_path,
10897 };
10898
10899 Some(
10900 self.buffer_store()
10901 .read(cx)
10902 .get_by_path(&project_path)?
10903 .read(cx),
10904 )
10905 }
10906
10907 #[cfg(any(test, feature = "test-support"))]
10908 pub fn update_diagnostics(
10909 &mut self,
10910 server_id: LanguageServerId,
10911 diagnostics: lsp::PublishDiagnosticsParams,
10912 result_id: Option<String>,
10913 source_kind: DiagnosticSourceKind,
10914 disk_based_sources: &[String],
10915 cx: &mut Context<Self>,
10916 ) -> Result<()> {
10917 self.merge_lsp_diagnostics(
10918 source_kind,
10919 vec![DocumentDiagnosticsUpdate {
10920 diagnostics,
10921 result_id,
10922 server_id,
10923 disk_based_sources: Cow::Borrowed(disk_based_sources),
10924 }],
10925 |_, _, _| false,
10926 cx,
10927 )
10928 }
10929
10930 pub fn merge_lsp_diagnostics(
10931 &mut self,
10932 source_kind: DiagnosticSourceKind,
10933 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10934 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10935 cx: &mut Context<Self>,
10936 ) -> Result<()> {
10937 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10938 let updates = lsp_diagnostics
10939 .into_iter()
10940 .filter_map(|update| {
10941 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10942 Some(DocumentDiagnosticsUpdate {
10943 diagnostics: self.lsp_to_document_diagnostics(
10944 abs_path,
10945 source_kind,
10946 update.server_id,
10947 update.diagnostics,
10948 &update.disk_based_sources,
10949 ),
10950 result_id: update.result_id,
10951 server_id: update.server_id,
10952 disk_based_sources: update.disk_based_sources,
10953 })
10954 })
10955 .collect();
10956 self.merge_diagnostic_entries(updates, merge, cx)?;
10957 Ok(())
10958 }
10959
10960 fn lsp_to_document_diagnostics(
10961 &mut self,
10962 document_abs_path: PathBuf,
10963 source_kind: DiagnosticSourceKind,
10964 server_id: LanguageServerId,
10965 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10966 disk_based_sources: &[String],
10967 ) -> DocumentDiagnostics {
10968 let mut diagnostics = Vec::default();
10969 let mut primary_diagnostic_group_ids = HashMap::default();
10970 let mut sources_by_group_id = HashMap::default();
10971 let mut supporting_diagnostics = HashMap::default();
10972
10973 let adapter = self.language_server_adapter_for_id(server_id);
10974
10975 // Ensure that primary diagnostics are always the most severe
10976 lsp_diagnostics
10977 .diagnostics
10978 .sort_by_key(|item| item.severity);
10979
10980 for diagnostic in &lsp_diagnostics.diagnostics {
10981 let source = diagnostic.source.as_ref();
10982 let range = range_from_lsp(diagnostic.range);
10983 let is_supporting = diagnostic
10984 .related_information
10985 .as_ref()
10986 .is_some_and(|infos| {
10987 infos.iter().any(|info| {
10988 primary_diagnostic_group_ids.contains_key(&(
10989 source,
10990 diagnostic.code.clone(),
10991 range_from_lsp(info.location.range),
10992 ))
10993 })
10994 });
10995
10996 let is_unnecessary = diagnostic
10997 .tags
10998 .as_ref()
10999 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11000
11001 let underline = self
11002 .language_server_adapter_for_id(server_id)
11003 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11004
11005 if is_supporting {
11006 supporting_diagnostics.insert(
11007 (source, diagnostic.code.clone(), range),
11008 (diagnostic.severity, is_unnecessary),
11009 );
11010 } else {
11011 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11012 let is_disk_based =
11013 source.is_some_and(|source| disk_based_sources.contains(source));
11014
11015 sources_by_group_id.insert(group_id, source);
11016 primary_diagnostic_group_ids
11017 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11018
11019 diagnostics.push(DiagnosticEntry {
11020 range,
11021 diagnostic: Diagnostic {
11022 source: diagnostic.source.clone(),
11023 source_kind,
11024 code: diagnostic.code.clone(),
11025 code_description: diagnostic
11026 .code_description
11027 .as_ref()
11028 .and_then(|d| d.href.clone()),
11029 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11030 markdown: adapter.as_ref().and_then(|adapter| {
11031 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11032 }),
11033 message: diagnostic.message.trim().to_string(),
11034 group_id,
11035 is_primary: true,
11036 is_disk_based,
11037 is_unnecessary,
11038 underline,
11039 data: diagnostic.data.clone(),
11040 },
11041 });
11042 if let Some(infos) = &diagnostic.related_information {
11043 for info in infos {
11044 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11045 let range = range_from_lsp(info.location.range);
11046 diagnostics.push(DiagnosticEntry {
11047 range,
11048 diagnostic: Diagnostic {
11049 source: diagnostic.source.clone(),
11050 source_kind,
11051 code: diagnostic.code.clone(),
11052 code_description: diagnostic
11053 .code_description
11054 .as_ref()
11055 .and_then(|d| d.href.clone()),
11056 severity: DiagnosticSeverity::INFORMATION,
11057 markdown: adapter.as_ref().and_then(|adapter| {
11058 adapter.diagnostic_message_to_markdown(&info.message)
11059 }),
11060 message: info.message.trim().to_string(),
11061 group_id,
11062 is_primary: false,
11063 is_disk_based,
11064 is_unnecessary: false,
11065 underline,
11066 data: diagnostic.data.clone(),
11067 },
11068 });
11069 }
11070 }
11071 }
11072 }
11073 }
11074
11075 for entry in &mut diagnostics {
11076 let diagnostic = &mut entry.diagnostic;
11077 if !diagnostic.is_primary {
11078 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11079 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11080 source,
11081 diagnostic.code.clone(),
11082 entry.range.clone(),
11083 )) {
11084 if let Some(severity) = severity {
11085 diagnostic.severity = severity;
11086 }
11087 diagnostic.is_unnecessary = is_unnecessary;
11088 }
11089 }
11090 }
11091
11092 DocumentDiagnostics {
11093 diagnostics,
11094 document_abs_path,
11095 version: lsp_diagnostics.version,
11096 }
11097 }
11098
11099 fn insert_newly_running_language_server(
11100 &mut self,
11101 adapter: Arc<CachedLspAdapter>,
11102 language_server: Arc<LanguageServer>,
11103 server_id: LanguageServerId,
11104 key: LanguageServerSeed,
11105 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11106 cx: &mut Context<Self>,
11107 ) {
11108 let Some(local) = self.as_local_mut() else {
11109 return;
11110 };
11111 // If the language server for this key doesn't match the server id, don't store the
11112 // server. Which will cause it to be dropped, killing the process
11113 if local
11114 .language_server_ids
11115 .get(&key)
11116 .map(|state| state.id != server_id)
11117 .unwrap_or(false)
11118 {
11119 return;
11120 }
11121
11122 // Update language_servers collection with Running variant of LanguageServerState
11123 // indicating that the server is up and running and ready
11124 let workspace_folders = workspace_folders.lock().clone();
11125 language_server.set_workspace_folders(workspace_folders);
11126
11127 let workspace_diagnostics_refresh_tasks = language_server
11128 .capabilities()
11129 .diagnostic_provider
11130 .and_then(|provider| {
11131 local
11132 .language_server_dynamic_registrations
11133 .entry(server_id)
11134 .or_default()
11135 .diagnostics
11136 .entry(None)
11137 .or_insert(provider.clone());
11138 let workspace_refresher =
11139 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11140
11141 Some((None, workspace_refresher))
11142 })
11143 .into_iter()
11144 .collect();
11145 local.language_servers.insert(
11146 server_id,
11147 LanguageServerState::Running {
11148 workspace_diagnostics_refresh_tasks,
11149 adapter: adapter.clone(),
11150 server: language_server.clone(),
11151 simulate_disk_based_diagnostics_completion: None,
11152 },
11153 );
11154 local
11155 .languages
11156 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11157 if let Some(file_ops_caps) = language_server
11158 .capabilities()
11159 .workspace
11160 .as_ref()
11161 .and_then(|ws| ws.file_operations.as_ref())
11162 {
11163 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11164 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11165 if did_rename_caps.or(will_rename_caps).is_some() {
11166 let watcher = RenamePathsWatchedForServer::default()
11167 .with_did_rename_patterns(did_rename_caps)
11168 .with_will_rename_patterns(will_rename_caps);
11169 local
11170 .language_server_paths_watched_for_rename
11171 .insert(server_id, watcher);
11172 }
11173 }
11174
11175 self.language_server_statuses.insert(
11176 server_id,
11177 LanguageServerStatus {
11178 name: language_server.name(),
11179 pending_work: Default::default(),
11180 has_pending_diagnostic_updates: false,
11181 progress_tokens: Default::default(),
11182 worktree: Some(key.worktree_id),
11183 binary: Some(language_server.binary().clone()),
11184 configuration: Some(language_server.configuration().clone()),
11185 workspace_folders: language_server.workspace_folders(),
11186 },
11187 );
11188
11189 cx.emit(LspStoreEvent::LanguageServerAdded(
11190 server_id,
11191 language_server.name(),
11192 Some(key.worktree_id),
11193 ));
11194
11195 let server_capabilities = language_server.capabilities();
11196 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11197 downstream_client
11198 .send(proto::StartLanguageServer {
11199 project_id: *project_id,
11200 server: Some(proto::LanguageServer {
11201 id: server_id.to_proto(),
11202 name: language_server.name().to_string(),
11203 worktree_id: Some(key.worktree_id.to_proto()),
11204 }),
11205 capabilities: serde_json::to_string(&server_capabilities)
11206 .expect("serializing server LSP capabilities"),
11207 })
11208 .log_err();
11209 }
11210 self.lsp_server_capabilities
11211 .insert(server_id, server_capabilities);
11212
11213 // Tell the language server about every open buffer in the worktree that matches the language.
11214 // Also check for buffers in worktrees that reused this server
11215 let mut worktrees_using_server = vec![key.worktree_id];
11216 if let Some(local) = self.as_local() {
11217 // Find all worktrees that have this server in their language server tree
11218 for (worktree_id, servers) in &local.lsp_tree.instances {
11219 if *worktree_id != key.worktree_id {
11220 for server_map in servers.roots.values() {
11221 if server_map
11222 .values()
11223 .any(|(node, _)| node.id() == Some(server_id))
11224 {
11225 worktrees_using_server.push(*worktree_id);
11226 }
11227 }
11228 }
11229 }
11230 }
11231
11232 let mut buffer_paths_registered = Vec::new();
11233 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11234 let mut lsp_adapters = HashMap::default();
11235 for buffer_handle in buffer_store.buffers() {
11236 let buffer = buffer_handle.read(cx);
11237 let file = match File::from_dyn(buffer.file()) {
11238 Some(file) => file,
11239 None => continue,
11240 };
11241 let language = match buffer.language() {
11242 Some(language) => language,
11243 None => continue,
11244 };
11245
11246 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11247 || !lsp_adapters
11248 .entry(language.name())
11249 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11250 .iter()
11251 .any(|a| a.name == key.name)
11252 {
11253 continue;
11254 }
11255 // didOpen
11256 let file = match file.as_local() {
11257 Some(file) => file,
11258 None => continue,
11259 };
11260
11261 let local = self.as_local_mut().unwrap();
11262
11263 let buffer_id = buffer.remote_id();
11264 if local.registered_buffers.contains_key(&buffer_id) {
11265 let versions = local
11266 .buffer_snapshots
11267 .entry(buffer_id)
11268 .or_default()
11269 .entry(server_id)
11270 .and_modify(|_| {
11271 assert!(
11272 false,
11273 "There should not be an existing snapshot for a newly inserted buffer"
11274 )
11275 })
11276 .or_insert_with(|| {
11277 vec![LspBufferSnapshot {
11278 version: 0,
11279 snapshot: buffer.text_snapshot(),
11280 }]
11281 });
11282
11283 let snapshot = versions.last().unwrap();
11284 let version = snapshot.version;
11285 let initial_snapshot = &snapshot.snapshot;
11286 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11287 language_server.register_buffer(
11288 uri,
11289 adapter.language_id(&language.name()),
11290 version,
11291 initial_snapshot.text(),
11292 );
11293 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11294 local
11295 .buffers_opened_in_servers
11296 .entry(buffer_id)
11297 .or_default()
11298 .insert(server_id);
11299 }
11300 buffer_handle.update(cx, |buffer, cx| {
11301 buffer.set_completion_triggers(
11302 server_id,
11303 language_server
11304 .capabilities()
11305 .completion_provider
11306 .as_ref()
11307 .and_then(|provider| {
11308 provider
11309 .trigger_characters
11310 .as_ref()
11311 .map(|characters| characters.iter().cloned().collect())
11312 })
11313 .unwrap_or_default(),
11314 cx,
11315 )
11316 });
11317 }
11318 });
11319
11320 for (buffer_id, abs_path) in buffer_paths_registered {
11321 cx.emit(LspStoreEvent::LanguageServerUpdate {
11322 language_server_id: server_id,
11323 name: Some(adapter.name()),
11324 message: proto::update_language_server::Variant::RegisteredForBuffer(
11325 proto::RegisteredForBuffer {
11326 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11327 buffer_id: buffer_id.to_proto(),
11328 },
11329 ),
11330 });
11331 }
11332
11333 cx.notify();
11334 }
11335
11336 pub fn language_servers_running_disk_based_diagnostics(
11337 &self,
11338 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11339 self.language_server_statuses
11340 .iter()
11341 .filter_map(|(id, status)| {
11342 if status.has_pending_diagnostic_updates {
11343 Some(*id)
11344 } else {
11345 None
11346 }
11347 })
11348 }
11349
11350 pub(crate) fn cancel_language_server_work_for_buffers(
11351 &mut self,
11352 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11353 cx: &mut Context<Self>,
11354 ) {
11355 if let Some((client, project_id)) = self.upstream_client() {
11356 let request = client.request(proto::CancelLanguageServerWork {
11357 project_id,
11358 work: Some(proto::cancel_language_server_work::Work::Buffers(
11359 proto::cancel_language_server_work::Buffers {
11360 buffer_ids: buffers
11361 .into_iter()
11362 .map(|b| b.read(cx).remote_id().to_proto())
11363 .collect(),
11364 },
11365 )),
11366 });
11367 cx.background_spawn(request).detach_and_log_err(cx);
11368 } else if let Some(local) = self.as_local() {
11369 let servers = buffers
11370 .into_iter()
11371 .flat_map(|buffer| {
11372 buffer.update(cx, |buffer, cx| {
11373 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11374 })
11375 })
11376 .collect::<HashSet<_>>();
11377 for server_id in servers {
11378 self.cancel_language_server_work(server_id, None, cx);
11379 }
11380 }
11381 }
11382
11383 pub(crate) fn cancel_language_server_work(
11384 &mut self,
11385 server_id: LanguageServerId,
11386 token_to_cancel: Option<ProgressToken>,
11387 cx: &mut Context<Self>,
11388 ) {
11389 if let Some(local) = self.as_local() {
11390 let status = self.language_server_statuses.get(&server_id);
11391 let server = local.language_servers.get(&server_id);
11392 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11393 {
11394 for (token, progress) in &status.pending_work {
11395 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11396 && token != token_to_cancel
11397 {
11398 continue;
11399 }
11400 if progress.is_cancellable {
11401 server
11402 .notify::<lsp::notification::WorkDoneProgressCancel>(
11403 WorkDoneProgressCancelParams {
11404 token: token.to_lsp(),
11405 },
11406 )
11407 .ok();
11408 }
11409 }
11410 }
11411 } else if let Some((client, project_id)) = self.upstream_client() {
11412 let request = client.request(proto::CancelLanguageServerWork {
11413 project_id,
11414 work: Some(
11415 proto::cancel_language_server_work::Work::LanguageServerWork(
11416 proto::cancel_language_server_work::LanguageServerWork {
11417 language_server_id: server_id.to_proto(),
11418 token: token_to_cancel.map(|token| token.to_proto()),
11419 },
11420 ),
11421 ),
11422 });
11423 cx.background_spawn(request).detach_and_log_err(cx);
11424 }
11425 }
11426
11427 fn register_supplementary_language_server(
11428 &mut self,
11429 id: LanguageServerId,
11430 name: LanguageServerName,
11431 server: Arc<LanguageServer>,
11432 cx: &mut Context<Self>,
11433 ) {
11434 if let Some(local) = self.as_local_mut() {
11435 local
11436 .supplementary_language_servers
11437 .insert(id, (name.clone(), server));
11438 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11439 }
11440 }
11441
11442 fn unregister_supplementary_language_server(
11443 &mut self,
11444 id: LanguageServerId,
11445 cx: &mut Context<Self>,
11446 ) {
11447 if let Some(local) = self.as_local_mut() {
11448 local.supplementary_language_servers.remove(&id);
11449 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11450 }
11451 }
11452
11453 pub(crate) fn supplementary_language_servers(
11454 &self,
11455 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11456 self.as_local().into_iter().flat_map(|local| {
11457 local
11458 .supplementary_language_servers
11459 .iter()
11460 .map(|(id, (name, _))| (*id, name.clone()))
11461 })
11462 }
11463
11464 pub fn language_server_adapter_for_id(
11465 &self,
11466 id: LanguageServerId,
11467 ) -> Option<Arc<CachedLspAdapter>> {
11468 self.as_local()
11469 .and_then(|local| local.language_servers.get(&id))
11470 .and_then(|language_server_state| match language_server_state {
11471 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11472 _ => None,
11473 })
11474 }
11475
11476 pub(super) fn update_local_worktree_language_servers(
11477 &mut self,
11478 worktree_handle: &Entity<Worktree>,
11479 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11480 cx: &mut Context<Self>,
11481 ) {
11482 if changes.is_empty() {
11483 return;
11484 }
11485
11486 let Some(local) = self.as_local() else { return };
11487
11488 local.prettier_store.update(cx, |prettier_store, cx| {
11489 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11490 });
11491
11492 let worktree_id = worktree_handle.read(cx).id();
11493 let mut language_server_ids = local
11494 .language_server_ids
11495 .iter()
11496 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11497 .collect::<Vec<_>>();
11498 language_server_ids.sort();
11499 language_server_ids.dedup();
11500
11501 // let abs_path = worktree_handle.read(cx).abs_path();
11502 for server_id in &language_server_ids {
11503 if let Some(LanguageServerState::Running { server, .. }) =
11504 local.language_servers.get(server_id)
11505 && let Some(watched_paths) = local
11506 .language_server_watched_paths
11507 .get(server_id)
11508 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11509 {
11510 let params = lsp::DidChangeWatchedFilesParams {
11511 changes: changes
11512 .iter()
11513 .filter_map(|(path, _, change)| {
11514 if !watched_paths.is_match(path.as_std_path()) {
11515 return None;
11516 }
11517 let typ = match change {
11518 PathChange::Loaded => return None,
11519 PathChange::Added => lsp::FileChangeType::CREATED,
11520 PathChange::Removed => lsp::FileChangeType::DELETED,
11521 PathChange::Updated => lsp::FileChangeType::CHANGED,
11522 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11523 };
11524 let uri = lsp::Uri::from_file_path(
11525 worktree_handle.read(cx).absolutize(&path),
11526 )
11527 .ok()?;
11528 Some(lsp::FileEvent { uri, typ })
11529 })
11530 .collect(),
11531 };
11532 if !params.changes.is_empty() {
11533 server
11534 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11535 .ok();
11536 }
11537 }
11538 }
11539 for (path, _, _) in changes {
11540 if let Some(file_name) = path.file_name()
11541 && local.watched_manifest_filenames.contains(file_name)
11542 {
11543 self.request_workspace_config_refresh();
11544 break;
11545 }
11546 }
11547 }
11548
11549 pub fn wait_for_remote_buffer(
11550 &mut self,
11551 id: BufferId,
11552 cx: &mut Context<Self>,
11553 ) -> Task<Result<Entity<Buffer>>> {
11554 self.buffer_store.update(cx, |buffer_store, cx| {
11555 buffer_store.wait_for_remote_buffer(id, cx)
11556 })
11557 }
11558
11559 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11560 let mut result = proto::Symbol {
11561 language_server_name: symbol.language_server_name.0.to_string(),
11562 source_worktree_id: symbol.source_worktree_id.to_proto(),
11563 language_server_id: symbol.source_language_server_id.to_proto(),
11564 name: symbol.name.clone(),
11565 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11566 start: Some(proto::PointUtf16 {
11567 row: symbol.range.start.0.row,
11568 column: symbol.range.start.0.column,
11569 }),
11570 end: Some(proto::PointUtf16 {
11571 row: symbol.range.end.0.row,
11572 column: symbol.range.end.0.column,
11573 }),
11574 worktree_id: Default::default(),
11575 path: Default::default(),
11576 signature: Default::default(),
11577 };
11578 match &symbol.path {
11579 SymbolLocation::InProject(path) => {
11580 result.worktree_id = path.worktree_id.to_proto();
11581 result.path = path.path.to_proto();
11582 }
11583 SymbolLocation::OutsideProject {
11584 abs_path,
11585 signature,
11586 } => {
11587 result.path = abs_path.to_string_lossy().into_owned();
11588 result.signature = signature.to_vec();
11589 }
11590 }
11591 result
11592 }
11593
11594 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11595 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11596 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11597 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11598
11599 let path = if serialized_symbol.signature.is_empty() {
11600 SymbolLocation::InProject(ProjectPath {
11601 worktree_id,
11602 path: RelPath::from_proto(&serialized_symbol.path)
11603 .context("invalid symbol path")?,
11604 })
11605 } else {
11606 SymbolLocation::OutsideProject {
11607 abs_path: Path::new(&serialized_symbol.path).into(),
11608 signature: serialized_symbol
11609 .signature
11610 .try_into()
11611 .map_err(|_| anyhow!("invalid signature"))?,
11612 }
11613 };
11614
11615 let start = serialized_symbol.start.context("invalid start")?;
11616 let end = serialized_symbol.end.context("invalid end")?;
11617 Ok(CoreSymbol {
11618 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11619 source_worktree_id,
11620 source_language_server_id: LanguageServerId::from_proto(
11621 serialized_symbol.language_server_id,
11622 ),
11623 path,
11624 name: serialized_symbol.name,
11625 range: Unclipped(PointUtf16::new(start.row, start.column))
11626 ..Unclipped(PointUtf16::new(end.row, end.column)),
11627 kind,
11628 })
11629 }
11630
11631 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11632 let mut serialized_completion = proto::Completion {
11633 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11634 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11635 new_text: completion.new_text.clone(),
11636 ..proto::Completion::default()
11637 };
11638 match &completion.source {
11639 CompletionSource::Lsp {
11640 insert_range,
11641 server_id,
11642 lsp_completion,
11643 lsp_defaults,
11644 resolved,
11645 } => {
11646 let (old_insert_start, old_insert_end) = insert_range
11647 .as_ref()
11648 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11649 .unzip();
11650
11651 serialized_completion.old_insert_start = old_insert_start;
11652 serialized_completion.old_insert_end = old_insert_end;
11653 serialized_completion.source = proto::completion::Source::Lsp as i32;
11654 serialized_completion.server_id = server_id.0 as u64;
11655 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11656 serialized_completion.lsp_defaults = lsp_defaults
11657 .as_deref()
11658 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11659 serialized_completion.resolved = *resolved;
11660 }
11661 CompletionSource::BufferWord {
11662 word_range,
11663 resolved,
11664 } => {
11665 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11666 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11667 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11668 serialized_completion.resolved = *resolved;
11669 }
11670 CompletionSource::Custom => {
11671 serialized_completion.source = proto::completion::Source::Custom as i32;
11672 serialized_completion.resolved = true;
11673 }
11674 CompletionSource::Dap { sort_text } => {
11675 serialized_completion.source = proto::completion::Source::Dap as i32;
11676 serialized_completion.sort_text = Some(sort_text.clone());
11677 }
11678 }
11679
11680 serialized_completion
11681 }
11682
11683 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11684 let old_replace_start = completion
11685 .old_replace_start
11686 .and_then(deserialize_anchor)
11687 .context("invalid old start")?;
11688 let old_replace_end = completion
11689 .old_replace_end
11690 .and_then(deserialize_anchor)
11691 .context("invalid old end")?;
11692 let insert_range = {
11693 match completion.old_insert_start.zip(completion.old_insert_end) {
11694 Some((start, end)) => {
11695 let start = deserialize_anchor(start).context("invalid insert old start")?;
11696 let end = deserialize_anchor(end).context("invalid insert old end")?;
11697 Some(start..end)
11698 }
11699 None => None,
11700 }
11701 };
11702 Ok(CoreCompletion {
11703 replace_range: old_replace_start..old_replace_end,
11704 new_text: completion.new_text,
11705 source: match proto::completion::Source::from_i32(completion.source) {
11706 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11707 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11708 insert_range,
11709 server_id: LanguageServerId::from_proto(completion.server_id),
11710 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11711 lsp_defaults: completion
11712 .lsp_defaults
11713 .as_deref()
11714 .map(serde_json::from_slice)
11715 .transpose()?,
11716 resolved: completion.resolved,
11717 },
11718 Some(proto::completion::Source::BufferWord) => {
11719 let word_range = completion
11720 .buffer_word_start
11721 .and_then(deserialize_anchor)
11722 .context("invalid buffer word start")?
11723 ..completion
11724 .buffer_word_end
11725 .and_then(deserialize_anchor)
11726 .context("invalid buffer word end")?;
11727 CompletionSource::BufferWord {
11728 word_range,
11729 resolved: completion.resolved,
11730 }
11731 }
11732 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11733 sort_text: completion
11734 .sort_text
11735 .context("expected sort text to exist")?,
11736 },
11737 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11738 },
11739 })
11740 }
11741
11742 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11743 let (kind, lsp_action) = match &action.lsp_action {
11744 LspAction::Action(code_action) => (
11745 proto::code_action::Kind::Action as i32,
11746 serde_json::to_vec(code_action).unwrap(),
11747 ),
11748 LspAction::Command(command) => (
11749 proto::code_action::Kind::Command as i32,
11750 serde_json::to_vec(command).unwrap(),
11751 ),
11752 LspAction::CodeLens(code_lens) => (
11753 proto::code_action::Kind::CodeLens as i32,
11754 serde_json::to_vec(code_lens).unwrap(),
11755 ),
11756 };
11757
11758 proto::CodeAction {
11759 server_id: action.server_id.0 as u64,
11760 start: Some(serialize_anchor(&action.range.start)),
11761 end: Some(serialize_anchor(&action.range.end)),
11762 lsp_action,
11763 kind,
11764 resolved: action.resolved,
11765 }
11766 }
11767
11768 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11769 let start = action
11770 .start
11771 .and_then(deserialize_anchor)
11772 .context("invalid start")?;
11773 let end = action
11774 .end
11775 .and_then(deserialize_anchor)
11776 .context("invalid end")?;
11777 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11778 Some(proto::code_action::Kind::Action) => {
11779 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11780 }
11781 Some(proto::code_action::Kind::Command) => {
11782 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11783 }
11784 Some(proto::code_action::Kind::CodeLens) => {
11785 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11786 }
11787 None => anyhow::bail!("Unknown action kind {}", action.kind),
11788 };
11789 Ok(CodeAction {
11790 server_id: LanguageServerId(action.server_id as usize),
11791 range: start..end,
11792 resolved: action.resolved,
11793 lsp_action,
11794 })
11795 }
11796
11797 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11798 match &formatting_result {
11799 Ok(_) => self.last_formatting_failure = None,
11800 Err(error) => {
11801 let error_string = format!("{error:#}");
11802 log::error!("Formatting failed: {error_string}");
11803 self.last_formatting_failure
11804 .replace(error_string.lines().join(" "));
11805 }
11806 }
11807 }
11808
11809 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11810 self.lsp_server_capabilities.remove(&for_server);
11811 for lsp_data in self.lsp_data.values_mut() {
11812 lsp_data.remove_server_data(for_server);
11813 }
11814 if let Some(local) = self.as_local_mut() {
11815 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11816 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11817 buffer_servers.remove(&for_server);
11818 }
11819 }
11820 }
11821
11822 pub fn result_id(
11823 &self,
11824 server_id: LanguageServerId,
11825 buffer_id: BufferId,
11826 cx: &App,
11827 ) -> Option<String> {
11828 let abs_path = self
11829 .buffer_store
11830 .read(cx)
11831 .get(buffer_id)
11832 .and_then(|b| File::from_dyn(b.read(cx).file()))
11833 .map(|f| f.abs_path(cx))?;
11834 self.as_local()?
11835 .buffer_pull_diagnostics_result_ids
11836 .get(&server_id)?
11837 .get(&abs_path)?
11838 .clone()
11839 }
11840
11841 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11842 let Some(local) = self.as_local() else {
11843 return HashMap::default();
11844 };
11845 local
11846 .buffer_pull_diagnostics_result_ids
11847 .get(&server_id)
11848 .into_iter()
11849 .flatten()
11850 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11851 .collect()
11852 }
11853
11854 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11855 if let Some(LanguageServerState::Running {
11856 workspace_diagnostics_refresh_tasks,
11857 ..
11858 }) = self
11859 .as_local_mut()
11860 .and_then(|local| local.language_servers.get_mut(&server_id))
11861 {
11862 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11863 diagnostics.refresh_tx.try_send(()).ok();
11864 }
11865 }
11866 }
11867
11868 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11869 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11870 return;
11871 };
11872 let Some(local) = self.as_local_mut() else {
11873 return;
11874 };
11875
11876 for server_id in buffer.update(cx, |buffer, cx| {
11877 local.language_server_ids_for_buffer(buffer, cx)
11878 }) {
11879 if let Some(LanguageServerState::Running {
11880 workspace_diagnostics_refresh_tasks,
11881 ..
11882 }) = local.language_servers.get_mut(&server_id)
11883 {
11884 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11885 diagnostics.refresh_tx.try_send(()).ok();
11886 }
11887 }
11888 }
11889 }
11890
11891 fn apply_workspace_diagnostic_report(
11892 &mut self,
11893 server_id: LanguageServerId,
11894 report: lsp::WorkspaceDiagnosticReportResult,
11895 cx: &mut Context<Self>,
11896 ) {
11897 let workspace_diagnostics =
11898 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11899 let mut unchanged_buffers = HashSet::default();
11900 let mut changed_buffers = HashSet::default();
11901 let workspace_diagnostics_updates = workspace_diagnostics
11902 .into_iter()
11903 .filter_map(
11904 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11905 LspPullDiagnostics::Response {
11906 server_id,
11907 uri,
11908 diagnostics,
11909 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11910 LspPullDiagnostics::Default => None,
11911 },
11912 )
11913 .fold(
11914 HashMap::default(),
11915 |mut acc, (server_id, uri, diagnostics, version)| {
11916 let (result_id, diagnostics) = match diagnostics {
11917 PulledDiagnostics::Unchanged { result_id } => {
11918 unchanged_buffers.insert(uri.clone());
11919 (Some(result_id), Vec::new())
11920 }
11921 PulledDiagnostics::Changed {
11922 result_id,
11923 diagnostics,
11924 } => {
11925 changed_buffers.insert(uri.clone());
11926 (result_id, diagnostics)
11927 }
11928 };
11929 let disk_based_sources = Cow::Owned(
11930 self.language_server_adapter_for_id(server_id)
11931 .as_ref()
11932 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11933 .unwrap_or(&[])
11934 .to_vec(),
11935 );
11936 acc.entry(server_id)
11937 .or_insert_with(Vec::new)
11938 .push(DocumentDiagnosticsUpdate {
11939 server_id,
11940 diagnostics: lsp::PublishDiagnosticsParams {
11941 uri,
11942 diagnostics,
11943 version,
11944 },
11945 result_id,
11946 disk_based_sources,
11947 });
11948 acc
11949 },
11950 );
11951
11952 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11953 self.merge_lsp_diagnostics(
11954 DiagnosticSourceKind::Pulled,
11955 diagnostic_updates,
11956 |buffer, old_diagnostic, cx| {
11957 File::from_dyn(buffer.file())
11958 .and_then(|file| {
11959 let abs_path = file.as_local()?.abs_path(cx);
11960 lsp::Uri::from_file_path(abs_path).ok()
11961 })
11962 .is_none_or(|buffer_uri| {
11963 unchanged_buffers.contains(&buffer_uri)
11964 || match old_diagnostic.source_kind {
11965 DiagnosticSourceKind::Pulled => {
11966 !changed_buffers.contains(&buffer_uri)
11967 }
11968 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11969 true
11970 }
11971 }
11972 })
11973 },
11974 cx,
11975 )
11976 .log_err();
11977 }
11978 }
11979
11980 fn register_server_capabilities(
11981 &mut self,
11982 server_id: LanguageServerId,
11983 params: lsp::RegistrationParams,
11984 cx: &mut Context<Self>,
11985 ) -> anyhow::Result<()> {
11986 let server = self
11987 .language_server_for_id(server_id)
11988 .with_context(|| format!("no server {server_id} found"))?;
11989 for reg in params.registrations {
11990 match reg.method.as_str() {
11991 "workspace/didChangeWatchedFiles" => {
11992 if let Some(options) = reg.register_options {
11993 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11994 let caps = serde_json::from_value(options)?;
11995 local_lsp_store
11996 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11997 true
11998 } else {
11999 false
12000 };
12001 if notify {
12002 notify_server_capabilities_updated(&server, cx);
12003 }
12004 }
12005 }
12006 "workspace/didChangeConfiguration" => {
12007 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12008 }
12009 "workspace/didChangeWorkspaceFolders" => {
12010 // In this case register options is an empty object, we can ignore it
12011 let caps = lsp::WorkspaceFoldersServerCapabilities {
12012 supported: Some(true),
12013 change_notifications: Some(OneOf::Right(reg.id)),
12014 };
12015 server.update_capabilities(|capabilities| {
12016 capabilities
12017 .workspace
12018 .get_or_insert_default()
12019 .workspace_folders = Some(caps);
12020 });
12021 notify_server_capabilities_updated(&server, cx);
12022 }
12023 "workspace/symbol" => {
12024 let options = parse_register_capabilities(reg)?;
12025 server.update_capabilities(|capabilities| {
12026 capabilities.workspace_symbol_provider = Some(options);
12027 });
12028 notify_server_capabilities_updated(&server, cx);
12029 }
12030 "workspace/fileOperations" => {
12031 if let Some(options) = reg.register_options {
12032 let caps = serde_json::from_value(options)?;
12033 server.update_capabilities(|capabilities| {
12034 capabilities
12035 .workspace
12036 .get_or_insert_default()
12037 .file_operations = Some(caps);
12038 });
12039 notify_server_capabilities_updated(&server, cx);
12040 }
12041 }
12042 "workspace/executeCommand" => {
12043 if let Some(options) = reg.register_options {
12044 let options = serde_json::from_value(options)?;
12045 server.update_capabilities(|capabilities| {
12046 capabilities.execute_command_provider = Some(options);
12047 });
12048 notify_server_capabilities_updated(&server, cx);
12049 }
12050 }
12051 "textDocument/rangeFormatting" => {
12052 let options = parse_register_capabilities(reg)?;
12053 server.update_capabilities(|capabilities| {
12054 capabilities.document_range_formatting_provider = Some(options);
12055 });
12056 notify_server_capabilities_updated(&server, cx);
12057 }
12058 "textDocument/onTypeFormatting" => {
12059 if let Some(options) = reg
12060 .register_options
12061 .map(serde_json::from_value)
12062 .transpose()?
12063 {
12064 server.update_capabilities(|capabilities| {
12065 capabilities.document_on_type_formatting_provider = Some(options);
12066 });
12067 notify_server_capabilities_updated(&server, cx);
12068 }
12069 }
12070 "textDocument/formatting" => {
12071 let options = parse_register_capabilities(reg)?;
12072 server.update_capabilities(|capabilities| {
12073 capabilities.document_formatting_provider = Some(options);
12074 });
12075 notify_server_capabilities_updated(&server, cx);
12076 }
12077 "textDocument/rename" => {
12078 let options = parse_register_capabilities(reg)?;
12079 server.update_capabilities(|capabilities| {
12080 capabilities.rename_provider = Some(options);
12081 });
12082 notify_server_capabilities_updated(&server, cx);
12083 }
12084 "textDocument/inlayHint" => {
12085 let options = parse_register_capabilities(reg)?;
12086 server.update_capabilities(|capabilities| {
12087 capabilities.inlay_hint_provider = Some(options);
12088 });
12089 notify_server_capabilities_updated(&server, cx);
12090 }
12091 "textDocument/documentSymbol" => {
12092 let options = parse_register_capabilities(reg)?;
12093 server.update_capabilities(|capabilities| {
12094 capabilities.document_symbol_provider = Some(options);
12095 });
12096 notify_server_capabilities_updated(&server, cx);
12097 }
12098 "textDocument/codeAction" => {
12099 let options = parse_register_capabilities(reg)?;
12100 let provider = match options {
12101 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12102 OneOf::Right(caps) => caps,
12103 };
12104 server.update_capabilities(|capabilities| {
12105 capabilities.code_action_provider = Some(provider);
12106 });
12107 notify_server_capabilities_updated(&server, cx);
12108 }
12109 "textDocument/definition" => {
12110 let options = parse_register_capabilities(reg)?;
12111 server.update_capabilities(|capabilities| {
12112 capabilities.definition_provider = Some(options);
12113 });
12114 notify_server_capabilities_updated(&server, cx);
12115 }
12116 "textDocument/completion" => {
12117 if let Some(caps) = reg
12118 .register_options
12119 .map(serde_json::from_value::<CompletionOptions>)
12120 .transpose()?
12121 {
12122 server.update_capabilities(|capabilities| {
12123 capabilities.completion_provider = Some(caps.clone());
12124 });
12125
12126 if let Some(local) = self.as_local() {
12127 let mut buffers_with_language_server = Vec::new();
12128 for handle in self.buffer_store.read(cx).buffers() {
12129 let buffer_id = handle.read(cx).remote_id();
12130 if local
12131 .buffers_opened_in_servers
12132 .get(&buffer_id)
12133 .filter(|s| s.contains(&server_id))
12134 .is_some()
12135 {
12136 buffers_with_language_server.push(handle);
12137 }
12138 }
12139 let triggers = caps
12140 .trigger_characters
12141 .unwrap_or_default()
12142 .into_iter()
12143 .collect::<BTreeSet<_>>();
12144 for handle in buffers_with_language_server {
12145 let triggers = triggers.clone();
12146 let _ = handle.update(cx, move |buffer, cx| {
12147 buffer.set_completion_triggers(server_id, triggers, cx);
12148 });
12149 }
12150 }
12151 notify_server_capabilities_updated(&server, cx);
12152 }
12153 }
12154 "textDocument/hover" => {
12155 let options = parse_register_capabilities(reg)?;
12156 let provider = match options {
12157 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12158 OneOf::Right(caps) => caps,
12159 };
12160 server.update_capabilities(|capabilities| {
12161 capabilities.hover_provider = Some(provider);
12162 });
12163 notify_server_capabilities_updated(&server, cx);
12164 }
12165 "textDocument/signatureHelp" => {
12166 if let Some(caps) = reg
12167 .register_options
12168 .map(serde_json::from_value)
12169 .transpose()?
12170 {
12171 server.update_capabilities(|capabilities| {
12172 capabilities.signature_help_provider = Some(caps);
12173 });
12174 notify_server_capabilities_updated(&server, cx);
12175 }
12176 }
12177 "textDocument/didChange" => {
12178 if let Some(sync_kind) = reg
12179 .register_options
12180 .and_then(|opts| opts.get("syncKind").cloned())
12181 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12182 .transpose()?
12183 {
12184 server.update_capabilities(|capabilities| {
12185 let mut sync_options =
12186 Self::take_text_document_sync_options(capabilities);
12187 sync_options.change = Some(sync_kind);
12188 capabilities.text_document_sync =
12189 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12190 });
12191 notify_server_capabilities_updated(&server, cx);
12192 }
12193 }
12194 "textDocument/didSave" => {
12195 if let Some(include_text) = reg
12196 .register_options
12197 .map(|opts| {
12198 let transpose = opts
12199 .get("includeText")
12200 .cloned()
12201 .map(serde_json::from_value::<Option<bool>>)
12202 .transpose();
12203 match transpose {
12204 Ok(value) => Ok(value.flatten()),
12205 Err(e) => Err(e),
12206 }
12207 })
12208 .transpose()?
12209 {
12210 server.update_capabilities(|capabilities| {
12211 let mut sync_options =
12212 Self::take_text_document_sync_options(capabilities);
12213 sync_options.save =
12214 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12215 include_text,
12216 }));
12217 capabilities.text_document_sync =
12218 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12219 });
12220 notify_server_capabilities_updated(&server, cx);
12221 }
12222 }
12223 "textDocument/codeLens" => {
12224 if let Some(caps) = reg
12225 .register_options
12226 .map(serde_json::from_value)
12227 .transpose()?
12228 {
12229 server.update_capabilities(|capabilities| {
12230 capabilities.code_lens_provider = Some(caps);
12231 });
12232 notify_server_capabilities_updated(&server, cx);
12233 }
12234 }
12235 "textDocument/diagnostic" => {
12236 if let Some(caps) = reg
12237 .register_options
12238 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12239 .transpose()?
12240 {
12241 let local = self
12242 .as_local_mut()
12243 .context("Expected LSP Store to be local")?;
12244 let state = local
12245 .language_servers
12246 .get_mut(&server_id)
12247 .context("Could not obtain Language Servers state")?;
12248 local
12249 .language_server_dynamic_registrations
12250 .entry(server_id)
12251 .or_default()
12252 .diagnostics
12253 .insert(Some(reg.id.clone()), caps.clone());
12254
12255 if let LanguageServerState::Running {
12256 workspace_diagnostics_refresh_tasks,
12257 ..
12258 } = state
12259 && let Some(task) = lsp_workspace_diagnostics_refresh(
12260 Some(reg.id.clone()),
12261 caps.clone(),
12262 server.clone(),
12263 cx,
12264 )
12265 {
12266 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12267 }
12268
12269 let mut did_update_caps = false;
12270 server.update_capabilities(|capabilities| {
12271 if capabilities.diagnostic_provider.as_ref().is_none_or(
12272 |current_caps| {
12273 let supports_workspace_diagnostics =
12274 |capabilities: &DiagnosticServerCapabilities| {
12275 match capabilities {
12276 DiagnosticServerCapabilities::Options(
12277 diagnostic_options,
12278 ) => diagnostic_options.workspace_diagnostics,
12279 DiagnosticServerCapabilities::RegistrationOptions(
12280 diagnostic_registration_options,
12281 ) => {
12282 diagnostic_registration_options
12283 .diagnostic_options
12284 .workspace_diagnostics
12285 }
12286 }
12287 };
12288 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12289 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12290 // as it'll think that they're not supported.
12291 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12292 !supports_workspace_diagnostics(current_caps)
12293 & supports_workspace_diagnostics(&caps)
12294 },
12295 ) {
12296 did_update_caps = true;
12297 capabilities.diagnostic_provider = Some(caps);
12298 }
12299 });
12300 if did_update_caps {
12301 notify_server_capabilities_updated(&server, cx);
12302 }
12303 }
12304 }
12305 "textDocument/documentColor" => {
12306 let options = parse_register_capabilities(reg)?;
12307 let provider = match options {
12308 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12309 OneOf::Right(caps) => caps,
12310 };
12311 server.update_capabilities(|capabilities| {
12312 capabilities.color_provider = Some(provider);
12313 });
12314 notify_server_capabilities_updated(&server, cx);
12315 }
12316 _ => log::warn!("unhandled capability registration: {reg:?}"),
12317 }
12318 }
12319
12320 Ok(())
12321 }
12322
12323 fn unregister_server_capabilities(
12324 &mut self,
12325 server_id: LanguageServerId,
12326 params: lsp::UnregistrationParams,
12327 cx: &mut Context<Self>,
12328 ) -> anyhow::Result<()> {
12329 let server = self
12330 .language_server_for_id(server_id)
12331 .with_context(|| format!("no server {server_id} found"))?;
12332 for unreg in params.unregisterations.iter() {
12333 match unreg.method.as_str() {
12334 "workspace/didChangeWatchedFiles" => {
12335 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12336 local_lsp_store
12337 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12338 true
12339 } else {
12340 false
12341 };
12342 if notify {
12343 notify_server_capabilities_updated(&server, cx);
12344 }
12345 }
12346 "workspace/didChangeConfiguration" => {
12347 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12348 }
12349 "workspace/didChangeWorkspaceFolders" => {
12350 server.update_capabilities(|capabilities| {
12351 capabilities
12352 .workspace
12353 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12354 workspace_folders: None,
12355 file_operations: None,
12356 })
12357 .workspace_folders = None;
12358 });
12359 notify_server_capabilities_updated(&server, cx);
12360 }
12361 "workspace/symbol" => {
12362 server.update_capabilities(|capabilities| {
12363 capabilities.workspace_symbol_provider = None
12364 });
12365 notify_server_capabilities_updated(&server, cx);
12366 }
12367 "workspace/fileOperations" => {
12368 server.update_capabilities(|capabilities| {
12369 capabilities
12370 .workspace
12371 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12372 workspace_folders: None,
12373 file_operations: None,
12374 })
12375 .file_operations = None;
12376 });
12377 notify_server_capabilities_updated(&server, cx);
12378 }
12379 "workspace/executeCommand" => {
12380 server.update_capabilities(|capabilities| {
12381 capabilities.execute_command_provider = None;
12382 });
12383 notify_server_capabilities_updated(&server, cx);
12384 }
12385 "textDocument/rangeFormatting" => {
12386 server.update_capabilities(|capabilities| {
12387 capabilities.document_range_formatting_provider = None
12388 });
12389 notify_server_capabilities_updated(&server, cx);
12390 }
12391 "textDocument/onTypeFormatting" => {
12392 server.update_capabilities(|capabilities| {
12393 capabilities.document_on_type_formatting_provider = None;
12394 });
12395 notify_server_capabilities_updated(&server, cx);
12396 }
12397 "textDocument/formatting" => {
12398 server.update_capabilities(|capabilities| {
12399 capabilities.document_formatting_provider = None;
12400 });
12401 notify_server_capabilities_updated(&server, cx);
12402 }
12403 "textDocument/rename" => {
12404 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12405 notify_server_capabilities_updated(&server, cx);
12406 }
12407 "textDocument/codeAction" => {
12408 server.update_capabilities(|capabilities| {
12409 capabilities.code_action_provider = None;
12410 });
12411 notify_server_capabilities_updated(&server, cx);
12412 }
12413 "textDocument/definition" => {
12414 server.update_capabilities(|capabilities| {
12415 capabilities.definition_provider = None;
12416 });
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 "textDocument/completion" => {
12420 server.update_capabilities(|capabilities| {
12421 capabilities.completion_provider = None;
12422 });
12423 notify_server_capabilities_updated(&server, cx);
12424 }
12425 "textDocument/hover" => {
12426 server.update_capabilities(|capabilities| {
12427 capabilities.hover_provider = None;
12428 });
12429 notify_server_capabilities_updated(&server, cx);
12430 }
12431 "textDocument/signatureHelp" => {
12432 server.update_capabilities(|capabilities| {
12433 capabilities.signature_help_provider = None;
12434 });
12435 notify_server_capabilities_updated(&server, cx);
12436 }
12437 "textDocument/didChange" => {
12438 server.update_capabilities(|capabilities| {
12439 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12440 sync_options.change = None;
12441 capabilities.text_document_sync =
12442 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12443 });
12444 notify_server_capabilities_updated(&server, cx);
12445 }
12446 "textDocument/didSave" => {
12447 server.update_capabilities(|capabilities| {
12448 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12449 sync_options.save = None;
12450 capabilities.text_document_sync =
12451 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12452 });
12453 notify_server_capabilities_updated(&server, cx);
12454 }
12455 "textDocument/codeLens" => {
12456 server.update_capabilities(|capabilities| {
12457 capabilities.code_lens_provider = None;
12458 });
12459 notify_server_capabilities_updated(&server, cx);
12460 }
12461 "textDocument/diagnostic" => {
12462 let local = self
12463 .as_local_mut()
12464 .context("Expected LSP Store to be local")?;
12465
12466 let state = local
12467 .language_servers
12468 .get_mut(&server_id)
12469 .context("Could not obtain Language Servers state")?;
12470 let options = local
12471 .language_server_dynamic_registrations
12472 .get_mut(&server_id)
12473 .with_context(|| {
12474 format!("Expected dynamic registration to exist for server {server_id}")
12475 })?.diagnostics
12476 .remove(&Some(unreg.id.clone()))
12477 .with_context(|| format!(
12478 "Attempted to unregister non-existent diagnostic registration with ID {}",
12479 unreg.id)
12480 )?;
12481
12482 let mut has_any_diagnostic_providers_still = true;
12483 if let Some(identifier) = diagnostic_identifier(&options)
12484 && let LanguageServerState::Running {
12485 workspace_diagnostics_refresh_tasks,
12486 ..
12487 } = state
12488 {
12489 workspace_diagnostics_refresh_tasks.remove(&identifier);
12490 has_any_diagnostic_providers_still =
12491 !workspace_diagnostics_refresh_tasks.is_empty();
12492 }
12493
12494 if !has_any_diagnostic_providers_still {
12495 server.update_capabilities(|capabilities| {
12496 debug_assert!(capabilities.diagnostic_provider.is_some());
12497 capabilities.diagnostic_provider = None;
12498 });
12499 }
12500
12501 notify_server_capabilities_updated(&server, cx);
12502 }
12503 "textDocument/documentColor" => {
12504 server.update_capabilities(|capabilities| {
12505 capabilities.color_provider = None;
12506 });
12507 notify_server_capabilities_updated(&server, cx);
12508 }
12509 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12510 }
12511 }
12512
12513 Ok(())
12514 }
12515
12516 async fn deduplicate_range_based_lsp_requests<T>(
12517 lsp_store: &Entity<Self>,
12518 server_id: Option<LanguageServerId>,
12519 lsp_request_id: LspRequestId,
12520 proto_request: &T::ProtoRequest,
12521 range: Range<Anchor>,
12522 cx: &mut AsyncApp,
12523 ) -> Result<()>
12524 where
12525 T: LspCommand,
12526 T::ProtoRequest: proto::LspRequestMessage,
12527 {
12528 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12529 let version = deserialize_version(proto_request.buffer_version());
12530 let buffer = lsp_store.update(cx, |this, cx| {
12531 this.buffer_store.read(cx).get_existing(buffer_id)
12532 })??;
12533 buffer
12534 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12535 .await?;
12536 lsp_store.update(cx, |lsp_store, cx| {
12537 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12538 let chunks_queried_for = lsp_data
12539 .inlay_hints
12540 .applicable_chunks(&[range])
12541 .collect::<Vec<_>>();
12542 match chunks_queried_for.as_slice() {
12543 &[chunk] => {
12544 let key = LspKey {
12545 request_type: TypeId::of::<T>(),
12546 server_queried: server_id,
12547 };
12548 let previous_request = lsp_data
12549 .chunk_lsp_requests
12550 .entry(key)
12551 .or_default()
12552 .insert(chunk, lsp_request_id);
12553 if let Some((previous_request, running_requests)) =
12554 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12555 {
12556 running_requests.remove(&previous_request);
12557 }
12558 }
12559 _ambiguous_chunks => {
12560 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12561 // there, a buffer version-based check will be performed and outdated requests discarded.
12562 }
12563 }
12564 anyhow::Ok(())
12565 })??;
12566
12567 Ok(())
12568 }
12569
12570 async fn query_lsp_locally<T>(
12571 lsp_store: Entity<Self>,
12572 for_server_id: Option<LanguageServerId>,
12573 sender_id: proto::PeerId,
12574 lsp_request_id: LspRequestId,
12575 proto_request: T::ProtoRequest,
12576 position: Option<Anchor>,
12577 cx: &mut AsyncApp,
12578 ) -> Result<()>
12579 where
12580 T: LspCommand + Clone,
12581 T::ProtoRequest: proto::LspRequestMessage,
12582 <T::ProtoRequest as proto::RequestMessage>::Response:
12583 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12584 {
12585 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12586 let version = deserialize_version(proto_request.buffer_version());
12587 let buffer = lsp_store.update(cx, |this, cx| {
12588 this.buffer_store.read(cx).get_existing(buffer_id)
12589 })??;
12590 buffer
12591 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12592 .await?;
12593 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12594 let request =
12595 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12596 let key = LspKey {
12597 request_type: TypeId::of::<T>(),
12598 server_queried: for_server_id,
12599 };
12600 lsp_store.update(cx, |lsp_store, cx| {
12601 let request_task = match for_server_id {
12602 Some(server_id) => {
12603 let server_task = lsp_store.request_lsp(
12604 buffer.clone(),
12605 LanguageServerToQuery::Other(server_id),
12606 request.clone(),
12607 cx,
12608 );
12609 cx.background_spawn(async move {
12610 let mut responses = Vec::new();
12611 match server_task.await {
12612 Ok(response) => responses.push((server_id, response)),
12613 // rust-analyzer likes to error with this when its still loading up
12614 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12615 Err(e) => log::error!(
12616 "Error handling response for request {request:?}: {e:#}"
12617 ),
12618 }
12619 responses
12620 })
12621 }
12622 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12623 };
12624 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12625 if T::ProtoRequest::stop_previous_requests() {
12626 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12627 lsp_requests.clear();
12628 }
12629 }
12630 lsp_data.lsp_requests.entry(key).or_default().insert(
12631 lsp_request_id,
12632 cx.spawn(async move |lsp_store, cx| {
12633 let response = request_task.await;
12634 lsp_store
12635 .update(cx, |lsp_store, cx| {
12636 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12637 {
12638 let response = response
12639 .into_iter()
12640 .map(|(server_id, response)| {
12641 (
12642 server_id.to_proto(),
12643 T::response_to_proto(
12644 response,
12645 lsp_store,
12646 sender_id,
12647 &buffer_version,
12648 cx,
12649 )
12650 .into(),
12651 )
12652 })
12653 .collect::<HashMap<_, _>>();
12654 match client.send_lsp_response::<T::ProtoRequest>(
12655 project_id,
12656 lsp_request_id,
12657 response,
12658 ) {
12659 Ok(()) => {}
12660 Err(e) => {
12661 log::error!("Failed to send LSP response: {e:#}",)
12662 }
12663 }
12664 }
12665 })
12666 .ok();
12667 }),
12668 );
12669 })?;
12670 Ok(())
12671 }
12672
12673 fn take_text_document_sync_options(
12674 capabilities: &mut lsp::ServerCapabilities,
12675 ) -> lsp::TextDocumentSyncOptions {
12676 match capabilities.text_document_sync.take() {
12677 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12678 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12679 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12680 sync_options.change = Some(sync_kind);
12681 sync_options
12682 }
12683 None => lsp::TextDocumentSyncOptions::default(),
12684 }
12685 }
12686
12687 #[cfg(any(test, feature = "test-support"))]
12688 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12689 Some(
12690 self.lsp_data
12691 .get_mut(&buffer_id)?
12692 .code_lens
12693 .take()?
12694 .update
12695 .take()?
12696 .1,
12697 )
12698 }
12699
12700 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12701 self.downstream_client.clone()
12702 }
12703
12704 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12705 self.worktree_store.clone()
12706 }
12707
12708 /// Gets what's stored in the LSP data for the given buffer.
12709 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12710 self.lsp_data.get_mut(&buffer_id)
12711 }
12712
12713 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12714 /// new [`BufferLspData`] will be created to replace the previous state.
12715 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12716 let (buffer_id, buffer_version) =
12717 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12718 let lsp_data = self
12719 .lsp_data
12720 .entry(buffer_id)
12721 .or_insert_with(|| BufferLspData::new(buffer, cx));
12722 if buffer_version.changed_since(&lsp_data.buffer_version) {
12723 *lsp_data = BufferLspData::new(buffer, cx);
12724 }
12725 lsp_data
12726 }
12727}
12728
12729// Registration with registerOptions as null, should fallback to true.
12730// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12731fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12732 reg: lsp::Registration,
12733) -> Result<OneOf<bool, T>> {
12734 Ok(match reg.register_options {
12735 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12736 None => OneOf::Left(true),
12737 })
12738}
12739
12740fn subscribe_to_binary_statuses(
12741 languages: &Arc<LanguageRegistry>,
12742 cx: &mut Context<'_, LspStore>,
12743) -> Task<()> {
12744 let mut server_statuses = languages.language_server_binary_statuses();
12745 cx.spawn(async move |lsp_store, cx| {
12746 while let Some((server_name, binary_status)) = server_statuses.next().await {
12747 if lsp_store
12748 .update(cx, |_, cx| {
12749 let mut message = None;
12750 let binary_status = match binary_status {
12751 BinaryStatus::None => proto::ServerBinaryStatus::None,
12752 BinaryStatus::CheckingForUpdate => {
12753 proto::ServerBinaryStatus::CheckingForUpdate
12754 }
12755 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12756 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12757 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12758 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12759 BinaryStatus::Failed { error } => {
12760 message = Some(error);
12761 proto::ServerBinaryStatus::Failed
12762 }
12763 };
12764 cx.emit(LspStoreEvent::LanguageServerUpdate {
12765 // Binary updates are about the binary that might not have any language server id at that point.
12766 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12767 language_server_id: LanguageServerId(0),
12768 name: Some(server_name),
12769 message: proto::update_language_server::Variant::StatusUpdate(
12770 proto::StatusUpdate {
12771 message,
12772 status: Some(proto::status_update::Status::Binary(
12773 binary_status as i32,
12774 )),
12775 },
12776 ),
12777 });
12778 })
12779 .is_err()
12780 {
12781 break;
12782 }
12783 }
12784 })
12785}
12786
12787fn lsp_workspace_diagnostics_refresh(
12788 registration_id: Option<String>,
12789 options: DiagnosticServerCapabilities,
12790 server: Arc<LanguageServer>,
12791 cx: &mut Context<'_, LspStore>,
12792) -> Option<WorkspaceRefreshTask> {
12793 let identifier = diagnostic_identifier(&options)?;
12794
12795 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12796 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12797 refresh_tx.try_send(()).ok();
12798
12799 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12800 let mut attempts = 0;
12801 let max_attempts = 50;
12802 let mut requests = 0;
12803
12804 loop {
12805 let Some(()) = refresh_rx.recv().await else {
12806 return;
12807 };
12808
12809 'request: loop {
12810 requests += 1;
12811 if attempts > max_attempts {
12812 log::error!(
12813 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12814 );
12815 return;
12816 }
12817 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12818 cx.background_executor()
12819 .timer(Duration::from_millis(backoff_millis))
12820 .await;
12821 attempts += 1;
12822
12823 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12824 lsp_store
12825 .all_result_ids(server.server_id())
12826 .into_iter()
12827 .filter_map(|(abs_path, result_id)| {
12828 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12829 Some(lsp::PreviousResultId {
12830 uri,
12831 value: result_id,
12832 })
12833 })
12834 .collect()
12835 }) else {
12836 return;
12837 };
12838
12839 let token = if let Some(identifier) = ®istration_id {
12840 format!(
12841 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12842 server.server_id(),
12843 )
12844 } else {
12845 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12846 };
12847
12848 progress_rx.try_recv().ok();
12849 let timer =
12850 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12851 let progress = pin!(progress_rx.recv().fuse());
12852 let response_result = server
12853 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12854 lsp::WorkspaceDiagnosticParams {
12855 previous_result_ids,
12856 identifier: identifier.clone(),
12857 work_done_progress_params: Default::default(),
12858 partial_result_params: lsp::PartialResultParams {
12859 partial_result_token: Some(lsp::ProgressToken::String(token)),
12860 },
12861 },
12862 select(timer, progress).then(|either| match either {
12863 Either::Left((message, ..)) => ready(message).left_future(),
12864 Either::Right(..) => pending::<String>().right_future(),
12865 }),
12866 )
12867 .await;
12868
12869 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12870 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12871 match response_result {
12872 ConnectionResult::Timeout => {
12873 log::error!("Timeout during workspace diagnostics pull");
12874 continue 'request;
12875 }
12876 ConnectionResult::ConnectionReset => {
12877 log::error!("Server closed a workspace diagnostics pull request");
12878 continue 'request;
12879 }
12880 ConnectionResult::Result(Err(e)) => {
12881 log::error!("Error during workspace diagnostics pull: {e:#}");
12882 break 'request;
12883 }
12884 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12885 attempts = 0;
12886 if lsp_store
12887 .update(cx, |lsp_store, cx| {
12888 lsp_store.apply_workspace_diagnostic_report(
12889 server.server_id(),
12890 pulled_diagnostics,
12891 cx,
12892 )
12893 })
12894 .is_err()
12895 {
12896 return;
12897 }
12898 break 'request;
12899 }
12900 }
12901 }
12902 }
12903 });
12904
12905 Some(WorkspaceRefreshTask {
12906 refresh_tx,
12907 progress_tx,
12908 task: workspace_query_language_server,
12909 })
12910}
12911
12912fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12913 match &options {
12914 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12915 if !diagnostic_options.workspace_diagnostics {
12916 return None;
12917 }
12918 Some(diagnostic_options.identifier.clone())
12919 }
12920 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12921 let diagnostic_options = ®istration_options.diagnostic_options;
12922 if !diagnostic_options.workspace_diagnostics {
12923 return None;
12924 }
12925 Some(diagnostic_options.identifier.clone())
12926 }
12927 }
12928}
12929
12930fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12931 let CompletionSource::BufferWord {
12932 word_range,
12933 resolved,
12934 } = &mut completion.source
12935 else {
12936 return;
12937 };
12938 if *resolved {
12939 return;
12940 }
12941
12942 if completion.new_text
12943 != snapshot
12944 .text_for_range(word_range.clone())
12945 .collect::<String>()
12946 {
12947 return;
12948 }
12949
12950 let mut offset = 0;
12951 for chunk in snapshot.chunks(word_range.clone(), true) {
12952 let end_offset = offset + chunk.text.len();
12953 if let Some(highlight_id) = chunk.syntax_highlight_id {
12954 completion
12955 .label
12956 .runs
12957 .push((offset..end_offset, highlight_id));
12958 }
12959 offset = end_offset;
12960 }
12961 *resolved = true;
12962}
12963
12964impl EventEmitter<LspStoreEvent> for LspStore {}
12965
12966fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12967 hover
12968 .contents
12969 .retain(|hover_block| !hover_block.text.trim().is_empty());
12970 if hover.contents.is_empty() {
12971 None
12972 } else {
12973 Some(hover)
12974 }
12975}
12976
12977async fn populate_labels_for_completions(
12978 new_completions: Vec<CoreCompletion>,
12979 language: Option<Arc<Language>>,
12980 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12981) -> Vec<Completion> {
12982 let lsp_completions = new_completions
12983 .iter()
12984 .filter_map(|new_completion| {
12985 new_completion
12986 .source
12987 .lsp_completion(true)
12988 .map(|lsp_completion| lsp_completion.into_owned())
12989 })
12990 .collect::<Vec<_>>();
12991
12992 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12993 lsp_adapter
12994 .labels_for_completions(&lsp_completions, language)
12995 .await
12996 .log_err()
12997 .unwrap_or_default()
12998 } else {
12999 Vec::new()
13000 }
13001 .into_iter()
13002 .fuse();
13003
13004 let mut completions = Vec::new();
13005 for completion in new_completions {
13006 match completion.source.lsp_completion(true) {
13007 Some(lsp_completion) => {
13008 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13009
13010 let mut label = labels.next().flatten().unwrap_or_else(|| {
13011 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13012 });
13013 ensure_uniform_list_compatible_label(&mut label);
13014 completions.push(Completion {
13015 label,
13016 documentation,
13017 replace_range: completion.replace_range,
13018 new_text: completion.new_text,
13019 insert_text_mode: lsp_completion.insert_text_mode,
13020 source: completion.source,
13021 icon_path: None,
13022 confirm: None,
13023 match_start: None,
13024 snippet_deduplication_key: None,
13025 });
13026 }
13027 None => {
13028 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13029 ensure_uniform_list_compatible_label(&mut label);
13030 completions.push(Completion {
13031 label,
13032 documentation: None,
13033 replace_range: completion.replace_range,
13034 new_text: completion.new_text,
13035 source: completion.source,
13036 insert_text_mode: None,
13037 icon_path: None,
13038 confirm: None,
13039 match_start: None,
13040 snippet_deduplication_key: None,
13041 });
13042 }
13043 }
13044 }
13045 completions
13046}
13047
13048#[derive(Debug)]
13049pub enum LanguageServerToQuery {
13050 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13051 FirstCapable,
13052 /// Query a specific language server.
13053 Other(LanguageServerId),
13054}
13055
13056#[derive(Default)]
13057struct RenamePathsWatchedForServer {
13058 did_rename: Vec<RenameActionPredicate>,
13059 will_rename: Vec<RenameActionPredicate>,
13060}
13061
13062impl RenamePathsWatchedForServer {
13063 fn with_did_rename_patterns(
13064 mut self,
13065 did_rename: Option<&FileOperationRegistrationOptions>,
13066 ) -> Self {
13067 if let Some(did_rename) = did_rename {
13068 self.did_rename = did_rename
13069 .filters
13070 .iter()
13071 .filter_map(|filter| filter.try_into().log_err())
13072 .collect();
13073 }
13074 self
13075 }
13076 fn with_will_rename_patterns(
13077 mut self,
13078 will_rename: Option<&FileOperationRegistrationOptions>,
13079 ) -> Self {
13080 if let Some(will_rename) = will_rename {
13081 self.will_rename = will_rename
13082 .filters
13083 .iter()
13084 .filter_map(|filter| filter.try_into().log_err())
13085 .collect();
13086 }
13087 self
13088 }
13089
13090 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13091 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13092 }
13093 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13094 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13095 }
13096}
13097
13098impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13099 type Error = globset::Error;
13100 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13101 Ok(Self {
13102 kind: ops.pattern.matches.clone(),
13103 glob: GlobBuilder::new(&ops.pattern.glob)
13104 .case_insensitive(
13105 ops.pattern
13106 .options
13107 .as_ref()
13108 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13109 )
13110 .build()?
13111 .compile_matcher(),
13112 })
13113 }
13114}
13115struct RenameActionPredicate {
13116 glob: GlobMatcher,
13117 kind: Option<FileOperationPatternKind>,
13118}
13119
13120impl RenameActionPredicate {
13121 // Returns true if language server should be notified
13122 fn eval(&self, path: &str, is_dir: bool) -> bool {
13123 self.kind.as_ref().is_none_or(|kind| {
13124 let expected_kind = if is_dir {
13125 FileOperationPatternKind::Folder
13126 } else {
13127 FileOperationPatternKind::File
13128 };
13129 kind == &expected_kind
13130 }) && self.glob.is_match(path)
13131 }
13132}
13133
13134#[derive(Default)]
13135struct LanguageServerWatchedPaths {
13136 worktree_paths: HashMap<WorktreeId, GlobSet>,
13137 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13138}
13139
13140#[derive(Default)]
13141struct LanguageServerWatchedPathsBuilder {
13142 worktree_paths: HashMap<WorktreeId, GlobSet>,
13143 abs_paths: HashMap<Arc<Path>, GlobSet>,
13144}
13145
13146impl LanguageServerWatchedPathsBuilder {
13147 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13148 self.worktree_paths.insert(worktree_id, glob_set);
13149 }
13150 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13151 self.abs_paths.insert(path, glob_set);
13152 }
13153 fn build(
13154 self,
13155 fs: Arc<dyn Fs>,
13156 language_server_id: LanguageServerId,
13157 cx: &mut Context<LspStore>,
13158 ) -> LanguageServerWatchedPaths {
13159 let lsp_store = cx.weak_entity();
13160
13161 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13162 let abs_paths = self
13163 .abs_paths
13164 .into_iter()
13165 .map(|(abs_path, globset)| {
13166 let task = cx.spawn({
13167 let abs_path = abs_path.clone();
13168 let fs = fs.clone();
13169
13170 let lsp_store = lsp_store.clone();
13171 async move |_, cx| {
13172 maybe!(async move {
13173 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13174 while let Some(update) = push_updates.0.next().await {
13175 let action = lsp_store
13176 .update(cx, |this, _| {
13177 let Some(local) = this.as_local() else {
13178 return ControlFlow::Break(());
13179 };
13180 let Some(watcher) = local
13181 .language_server_watched_paths
13182 .get(&language_server_id)
13183 else {
13184 return ControlFlow::Break(());
13185 };
13186 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13187 "Watched abs path is not registered with a watcher",
13188 );
13189 let matching_entries = update
13190 .into_iter()
13191 .filter(|event| globs.is_match(&event.path))
13192 .collect::<Vec<_>>();
13193 this.lsp_notify_abs_paths_changed(
13194 language_server_id,
13195 matching_entries,
13196 );
13197 ControlFlow::Continue(())
13198 })
13199 .ok()?;
13200
13201 if action.is_break() {
13202 break;
13203 }
13204 }
13205 Some(())
13206 })
13207 .await;
13208 }
13209 });
13210 (abs_path, (globset, task))
13211 })
13212 .collect();
13213 LanguageServerWatchedPaths {
13214 worktree_paths: self.worktree_paths,
13215 abs_paths,
13216 }
13217 }
13218}
13219
13220struct LspBufferSnapshot {
13221 version: i32,
13222 snapshot: TextBufferSnapshot,
13223}
13224
13225/// A prompt requested by LSP server.
13226#[derive(Clone, Debug)]
13227pub struct LanguageServerPromptRequest {
13228 pub level: PromptLevel,
13229 pub message: String,
13230 pub actions: Vec<MessageActionItem>,
13231 pub lsp_name: String,
13232 pub(crate) response_channel: Sender<MessageActionItem>,
13233}
13234
13235impl LanguageServerPromptRequest {
13236 pub async fn respond(self, index: usize) -> Option<()> {
13237 if let Some(response) = self.actions.into_iter().nth(index) {
13238 self.response_channel.send(response).await.ok()
13239 } else {
13240 None
13241 }
13242 }
13243}
13244impl PartialEq for LanguageServerPromptRequest {
13245 fn eq(&self, other: &Self) -> bool {
13246 self.message == other.message && self.actions == other.actions
13247 }
13248}
13249
13250#[derive(Clone, Debug, PartialEq)]
13251pub enum LanguageServerLogType {
13252 Log(MessageType),
13253 Trace { verbose_info: Option<String> },
13254 Rpc { received: bool },
13255}
13256
13257impl LanguageServerLogType {
13258 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13259 match self {
13260 Self::Log(log_type) => {
13261 use proto::log_message::LogLevel;
13262 let level = match *log_type {
13263 MessageType::ERROR => LogLevel::Error,
13264 MessageType::WARNING => LogLevel::Warning,
13265 MessageType::INFO => LogLevel::Info,
13266 MessageType::LOG => LogLevel::Log,
13267 other => {
13268 log::warn!("Unknown lsp log message type: {other:?}");
13269 LogLevel::Log
13270 }
13271 };
13272 proto::language_server_log::LogType::Log(proto::LogMessage {
13273 level: level as i32,
13274 })
13275 }
13276 Self::Trace { verbose_info } => {
13277 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13278 verbose_info: verbose_info.to_owned(),
13279 })
13280 }
13281 Self::Rpc { received } => {
13282 let kind = if *received {
13283 proto::rpc_message::Kind::Received
13284 } else {
13285 proto::rpc_message::Kind::Sent
13286 };
13287 let kind = kind as i32;
13288 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13289 }
13290 }
13291 }
13292
13293 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13294 use proto::log_message::LogLevel;
13295 use proto::rpc_message;
13296 match log_type {
13297 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13298 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13299 LogLevel::Error => MessageType::ERROR,
13300 LogLevel::Warning => MessageType::WARNING,
13301 LogLevel::Info => MessageType::INFO,
13302 LogLevel::Log => MessageType::LOG,
13303 },
13304 ),
13305 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13306 verbose_info: trace_message.verbose_info,
13307 },
13308 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13309 received: match rpc_message::Kind::from_i32(message.kind)
13310 .unwrap_or(rpc_message::Kind::Received)
13311 {
13312 rpc_message::Kind::Received => true,
13313 rpc_message::Kind::Sent => false,
13314 },
13315 },
13316 }
13317 }
13318}
13319
13320pub struct WorkspaceRefreshTask {
13321 refresh_tx: mpsc::Sender<()>,
13322 progress_tx: mpsc::Sender<()>,
13323 #[allow(dead_code)]
13324 task: Task<()>,
13325}
13326
13327pub enum LanguageServerState {
13328 Starting {
13329 startup: Task<Option<Arc<LanguageServer>>>,
13330 /// List of language servers that will be added to the workspace once it's initialization completes.
13331 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13332 },
13333
13334 Running {
13335 adapter: Arc<CachedLspAdapter>,
13336 server: Arc<LanguageServer>,
13337 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13338 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13339 },
13340}
13341
13342impl LanguageServerState {
13343 fn add_workspace_folder(&self, uri: Uri) {
13344 match self {
13345 LanguageServerState::Starting {
13346 pending_workspace_folders,
13347 ..
13348 } => {
13349 pending_workspace_folders.lock().insert(uri);
13350 }
13351 LanguageServerState::Running { server, .. } => {
13352 server.add_workspace_folder(uri);
13353 }
13354 }
13355 }
13356 fn _remove_workspace_folder(&self, uri: Uri) {
13357 match self {
13358 LanguageServerState::Starting {
13359 pending_workspace_folders,
13360 ..
13361 } => {
13362 pending_workspace_folders.lock().remove(&uri);
13363 }
13364 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13365 }
13366 }
13367}
13368
13369impl std::fmt::Debug for LanguageServerState {
13370 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13371 match self {
13372 LanguageServerState::Starting { .. } => {
13373 f.debug_struct("LanguageServerState::Starting").finish()
13374 }
13375 LanguageServerState::Running { .. } => {
13376 f.debug_struct("LanguageServerState::Running").finish()
13377 }
13378 }
13379 }
13380}
13381
13382#[derive(Clone, Debug, Serialize)]
13383pub struct LanguageServerProgress {
13384 pub is_disk_based_diagnostics_progress: bool,
13385 pub is_cancellable: bool,
13386 pub title: Option<String>,
13387 pub message: Option<String>,
13388 pub percentage: Option<usize>,
13389 #[serde(skip_serializing)]
13390 pub last_update_at: Instant,
13391}
13392
13393#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13394pub struct DiagnosticSummary {
13395 pub error_count: usize,
13396 pub warning_count: usize,
13397}
13398
13399impl DiagnosticSummary {
13400 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13401 let mut this = Self {
13402 error_count: 0,
13403 warning_count: 0,
13404 };
13405
13406 for entry in diagnostics {
13407 if entry.diagnostic.is_primary {
13408 match entry.diagnostic.severity {
13409 DiagnosticSeverity::ERROR => this.error_count += 1,
13410 DiagnosticSeverity::WARNING => this.warning_count += 1,
13411 _ => {}
13412 }
13413 }
13414 }
13415
13416 this
13417 }
13418
13419 pub fn is_empty(&self) -> bool {
13420 self.error_count == 0 && self.warning_count == 0
13421 }
13422
13423 pub fn to_proto(
13424 self,
13425 language_server_id: LanguageServerId,
13426 path: &RelPath,
13427 ) -> proto::DiagnosticSummary {
13428 proto::DiagnosticSummary {
13429 path: path.to_proto(),
13430 language_server_id: language_server_id.0 as u64,
13431 error_count: self.error_count as u32,
13432 warning_count: self.warning_count as u32,
13433 }
13434 }
13435}
13436
13437#[derive(Clone, Debug)]
13438pub enum CompletionDocumentation {
13439 /// There is no documentation for this completion.
13440 Undocumented,
13441 /// A single line of documentation.
13442 SingleLine(SharedString),
13443 /// Multiple lines of plain text documentation.
13444 MultiLinePlainText(SharedString),
13445 /// Markdown documentation.
13446 MultiLineMarkdown(SharedString),
13447 /// Both single line and multiple lines of plain text documentation.
13448 SingleLineAndMultiLinePlainText {
13449 single_line: SharedString,
13450 plain_text: Option<SharedString>,
13451 },
13452}
13453
13454impl CompletionDocumentation {
13455 #[cfg(any(test, feature = "test-support"))]
13456 pub fn text(&self) -> SharedString {
13457 match self {
13458 CompletionDocumentation::Undocumented => "".into(),
13459 CompletionDocumentation::SingleLine(s) => s.clone(),
13460 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13461 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13462 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13463 single_line.clone()
13464 }
13465 }
13466 }
13467}
13468
13469impl From<lsp::Documentation> for CompletionDocumentation {
13470 fn from(docs: lsp::Documentation) -> Self {
13471 match docs {
13472 lsp::Documentation::String(text) => {
13473 if text.lines().count() <= 1 {
13474 CompletionDocumentation::SingleLine(text.into())
13475 } else {
13476 CompletionDocumentation::MultiLinePlainText(text.into())
13477 }
13478 }
13479
13480 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13481 lsp::MarkupKind::PlainText => {
13482 if value.lines().count() <= 1 {
13483 CompletionDocumentation::SingleLine(value.into())
13484 } else {
13485 CompletionDocumentation::MultiLinePlainText(value.into())
13486 }
13487 }
13488
13489 lsp::MarkupKind::Markdown => {
13490 CompletionDocumentation::MultiLineMarkdown(value.into())
13491 }
13492 },
13493 }
13494 }
13495}
13496
13497pub enum ResolvedHint {
13498 Resolved(InlayHint),
13499 Resolving(Shared<Task<()>>),
13500}
13501
13502fn glob_literal_prefix(glob: &Path) -> PathBuf {
13503 glob.components()
13504 .take_while(|component| match component {
13505 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13506 _ => true,
13507 })
13508 .collect()
13509}
13510
13511pub struct SshLspAdapter {
13512 name: LanguageServerName,
13513 binary: LanguageServerBinary,
13514 initialization_options: Option<String>,
13515 code_action_kinds: Option<Vec<CodeActionKind>>,
13516}
13517
13518impl SshLspAdapter {
13519 pub fn new(
13520 name: LanguageServerName,
13521 binary: LanguageServerBinary,
13522 initialization_options: Option<String>,
13523 code_action_kinds: Option<String>,
13524 ) -> Self {
13525 Self {
13526 name,
13527 binary,
13528 initialization_options,
13529 code_action_kinds: code_action_kinds
13530 .as_ref()
13531 .and_then(|c| serde_json::from_str(c).ok()),
13532 }
13533 }
13534}
13535
13536impl LspInstaller for SshLspAdapter {
13537 type BinaryVersion = ();
13538 async fn check_if_user_installed(
13539 &self,
13540 _: &dyn LspAdapterDelegate,
13541 _: Option<Toolchain>,
13542 _: &AsyncApp,
13543 ) -> Option<LanguageServerBinary> {
13544 Some(self.binary.clone())
13545 }
13546
13547 async fn cached_server_binary(
13548 &self,
13549 _: PathBuf,
13550 _: &dyn LspAdapterDelegate,
13551 ) -> Option<LanguageServerBinary> {
13552 None
13553 }
13554
13555 async fn fetch_latest_server_version(
13556 &self,
13557 _: &dyn LspAdapterDelegate,
13558 _: bool,
13559 _: &mut AsyncApp,
13560 ) -> Result<()> {
13561 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13562 }
13563
13564 async fn fetch_server_binary(
13565 &self,
13566 _: (),
13567 _: PathBuf,
13568 _: &dyn LspAdapterDelegate,
13569 ) -> Result<LanguageServerBinary> {
13570 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13571 }
13572}
13573
13574#[async_trait(?Send)]
13575impl LspAdapter for SshLspAdapter {
13576 fn name(&self) -> LanguageServerName {
13577 self.name.clone()
13578 }
13579
13580 async fn initialization_options(
13581 self: Arc<Self>,
13582 _: &Arc<dyn LspAdapterDelegate>,
13583 ) -> Result<Option<serde_json::Value>> {
13584 let Some(options) = &self.initialization_options else {
13585 return Ok(None);
13586 };
13587 let result = serde_json::from_str(options)?;
13588 Ok(result)
13589 }
13590
13591 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13592 self.code_action_kinds.clone()
13593 }
13594}
13595
13596pub fn language_server_settings<'a>(
13597 delegate: &'a dyn LspAdapterDelegate,
13598 language: &LanguageServerName,
13599 cx: &'a App,
13600) -> Option<&'a LspSettings> {
13601 language_server_settings_for(
13602 SettingsLocation {
13603 worktree_id: delegate.worktree_id(),
13604 path: RelPath::empty(),
13605 },
13606 language,
13607 cx,
13608 )
13609}
13610
13611pub(crate) fn language_server_settings_for<'a>(
13612 location: SettingsLocation<'a>,
13613 language: &LanguageServerName,
13614 cx: &'a App,
13615) -> Option<&'a LspSettings> {
13616 ProjectSettings::get(Some(location), cx).lsp.get(language)
13617}
13618
13619pub struct LocalLspAdapterDelegate {
13620 lsp_store: WeakEntity<LspStore>,
13621 worktree: worktree::Snapshot,
13622 fs: Arc<dyn Fs>,
13623 http_client: Arc<dyn HttpClient>,
13624 language_registry: Arc<LanguageRegistry>,
13625 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13626}
13627
13628impl LocalLspAdapterDelegate {
13629 pub fn new(
13630 language_registry: Arc<LanguageRegistry>,
13631 environment: &Entity<ProjectEnvironment>,
13632 lsp_store: WeakEntity<LspStore>,
13633 worktree: &Entity<Worktree>,
13634 http_client: Arc<dyn HttpClient>,
13635 fs: Arc<dyn Fs>,
13636 cx: &mut App,
13637 ) -> Arc<Self> {
13638 let load_shell_env_task =
13639 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13640
13641 Arc::new(Self {
13642 lsp_store,
13643 worktree: worktree.read(cx).snapshot(),
13644 fs,
13645 http_client,
13646 language_registry,
13647 load_shell_env_task,
13648 })
13649 }
13650
13651 fn from_local_lsp(
13652 local: &LocalLspStore,
13653 worktree: &Entity<Worktree>,
13654 cx: &mut App,
13655 ) -> Arc<Self> {
13656 Self::new(
13657 local.languages.clone(),
13658 &local.environment,
13659 local.weak.clone(),
13660 worktree,
13661 local.http_client.clone(),
13662 local.fs.clone(),
13663 cx,
13664 )
13665 }
13666}
13667
13668#[async_trait]
13669impl LspAdapterDelegate for LocalLspAdapterDelegate {
13670 fn show_notification(&self, message: &str, cx: &mut App) {
13671 self.lsp_store
13672 .update(cx, |_, cx| {
13673 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13674 })
13675 .ok();
13676 }
13677
13678 fn http_client(&self) -> Arc<dyn HttpClient> {
13679 self.http_client.clone()
13680 }
13681
13682 fn worktree_id(&self) -> WorktreeId {
13683 self.worktree.id()
13684 }
13685
13686 fn worktree_root_path(&self) -> &Path {
13687 self.worktree.abs_path().as_ref()
13688 }
13689
13690 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13691 self.worktree.resolve_executable_path(path)
13692 }
13693
13694 async fn shell_env(&self) -> HashMap<String, String> {
13695 let task = self.load_shell_env_task.clone();
13696 task.await.unwrap_or_default()
13697 }
13698
13699 async fn npm_package_installed_version(
13700 &self,
13701 package_name: &str,
13702 ) -> Result<Option<(PathBuf, String)>> {
13703 let local_package_directory = self.worktree_root_path();
13704 let node_modules_directory = local_package_directory.join("node_modules");
13705
13706 if let Some(version) =
13707 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13708 {
13709 return Ok(Some((node_modules_directory, version)));
13710 }
13711 let Some(npm) = self.which("npm".as_ref()).await else {
13712 log::warn!(
13713 "Failed to find npm executable for {:?}",
13714 local_package_directory
13715 );
13716 return Ok(None);
13717 };
13718
13719 let env = self.shell_env().await;
13720 let output = util::command::new_smol_command(&npm)
13721 .args(["root", "-g"])
13722 .envs(env)
13723 .current_dir(local_package_directory)
13724 .output()
13725 .await?;
13726 let global_node_modules =
13727 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13728
13729 if let Some(version) =
13730 read_package_installed_version(global_node_modules.clone(), package_name).await?
13731 {
13732 return Ok(Some((global_node_modules, version)));
13733 }
13734 return Ok(None);
13735 }
13736
13737 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13738 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13739 if self.fs.is_file(&worktree_abs_path).await {
13740 worktree_abs_path.pop();
13741 }
13742
13743 let env = self.shell_env().await;
13744
13745 let shell_path = env.get("PATH").cloned();
13746
13747 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13748 }
13749
13750 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13751 let mut working_dir = self.worktree_root_path().to_path_buf();
13752 if self.fs.is_file(&working_dir).await {
13753 working_dir.pop();
13754 }
13755 let output = util::command::new_smol_command(&command.path)
13756 .args(command.arguments)
13757 .envs(command.env.clone().unwrap_or_default())
13758 .current_dir(working_dir)
13759 .output()
13760 .await?;
13761
13762 anyhow::ensure!(
13763 output.status.success(),
13764 "{}, stdout: {:?}, stderr: {:?}",
13765 output.status,
13766 String::from_utf8_lossy(&output.stdout),
13767 String::from_utf8_lossy(&output.stderr)
13768 );
13769 Ok(())
13770 }
13771
13772 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13773 self.language_registry
13774 .update_lsp_binary_status(server_name, status);
13775 }
13776
13777 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13778 self.language_registry
13779 .all_lsp_adapters()
13780 .into_iter()
13781 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13782 .collect()
13783 }
13784
13785 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13786 let dir = self.language_registry.language_server_download_dir(name)?;
13787
13788 if !dir.exists() {
13789 smol::fs::create_dir_all(&dir)
13790 .await
13791 .context("failed to create container directory")
13792 .log_err()?;
13793 }
13794
13795 Some(dir)
13796 }
13797
13798 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13799 let entry = self
13800 .worktree
13801 .entry_for_path(path)
13802 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13803 let abs_path = self.worktree.absolutize(&entry.path);
13804 self.fs.load(&abs_path).await
13805 }
13806}
13807
13808async fn populate_labels_for_symbols(
13809 symbols: Vec<CoreSymbol>,
13810 language_registry: &Arc<LanguageRegistry>,
13811 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13812 output: &mut Vec<Symbol>,
13813) {
13814 #[allow(clippy::mutable_key_type)]
13815 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13816
13817 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13818 for symbol in symbols {
13819 let Some(file_name) = symbol.path.file_name() else {
13820 continue;
13821 };
13822 let language = language_registry
13823 .load_language_for_file_path(Path::new(file_name))
13824 .await
13825 .ok()
13826 .or_else(|| {
13827 unknown_paths.insert(file_name.into());
13828 None
13829 });
13830 symbols_by_language
13831 .entry(language)
13832 .or_default()
13833 .push(symbol);
13834 }
13835
13836 for unknown_path in unknown_paths {
13837 log::info!("no language found for symbol in file {unknown_path:?}");
13838 }
13839
13840 let mut label_params = Vec::new();
13841 for (language, mut symbols) in symbols_by_language {
13842 label_params.clear();
13843 label_params.extend(
13844 symbols
13845 .iter_mut()
13846 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13847 );
13848
13849 let mut labels = Vec::new();
13850 if let Some(language) = language {
13851 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13852 language_registry
13853 .lsp_adapters(&language.name())
13854 .first()
13855 .cloned()
13856 });
13857 if let Some(lsp_adapter) = lsp_adapter {
13858 labels = lsp_adapter
13859 .labels_for_symbols(&label_params, &language)
13860 .await
13861 .log_err()
13862 .unwrap_or_default();
13863 }
13864 }
13865
13866 for ((symbol, (name, _)), label) in symbols
13867 .into_iter()
13868 .zip(label_params.drain(..))
13869 .zip(labels.into_iter().chain(iter::repeat(None)))
13870 {
13871 output.push(Symbol {
13872 language_server_name: symbol.language_server_name,
13873 source_worktree_id: symbol.source_worktree_id,
13874 source_language_server_id: symbol.source_language_server_id,
13875 path: symbol.path,
13876 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13877 name,
13878 kind: symbol.kind,
13879 range: symbol.range,
13880 });
13881 }
13882 }
13883}
13884
13885fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13886 match server.capabilities().text_document_sync.as_ref()? {
13887 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13888 // Server wants didSave but didn't specify includeText.
13889 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13890 // Server doesn't want didSave at all.
13891 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13892 // Server provided SaveOptions.
13893 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13894 Some(save_options.include_text.unwrap_or(false))
13895 }
13896 },
13897 // We do not have any save info. Kind affects didChange only.
13898 lsp::TextDocumentSyncCapability::Kind(_) => None,
13899 }
13900}
13901
13902/// Completion items are displayed in a `UniformList`.
13903/// Usually, those items are single-line strings, but in LSP responses,
13904/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13905/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13906/// 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,
13907/// breaking the completions menu presentation.
13908///
13909/// 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.
13910fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13911 let mut new_text = String::with_capacity(label.text.len());
13912 let mut offset_map = vec![0; label.text.len() + 1];
13913 let mut last_char_was_space = false;
13914 let mut new_idx = 0;
13915 let chars = label.text.char_indices().fuse();
13916 let mut newlines_removed = false;
13917
13918 for (idx, c) in chars {
13919 offset_map[idx] = new_idx;
13920
13921 match c {
13922 '\n' if last_char_was_space => {
13923 newlines_removed = true;
13924 }
13925 '\t' | ' ' if last_char_was_space => {}
13926 '\n' if !last_char_was_space => {
13927 new_text.push(' ');
13928 new_idx += 1;
13929 last_char_was_space = true;
13930 newlines_removed = true;
13931 }
13932 ' ' | '\t' => {
13933 new_text.push(' ');
13934 new_idx += 1;
13935 last_char_was_space = true;
13936 }
13937 _ => {
13938 new_text.push(c);
13939 new_idx += c.len_utf8();
13940 last_char_was_space = false;
13941 }
13942 }
13943 }
13944 offset_map[label.text.len()] = new_idx;
13945
13946 // Only modify the label if newlines were removed.
13947 if !newlines_removed {
13948 return;
13949 }
13950
13951 let last_index = new_idx;
13952 let mut run_ranges_errors = Vec::new();
13953 label.runs.retain_mut(|(range, _)| {
13954 match offset_map.get(range.start) {
13955 Some(&start) => range.start = start,
13956 None => {
13957 run_ranges_errors.push(range.clone());
13958 return false;
13959 }
13960 }
13961
13962 match offset_map.get(range.end) {
13963 Some(&end) => range.end = end,
13964 None => {
13965 run_ranges_errors.push(range.clone());
13966 range.end = last_index;
13967 }
13968 }
13969 true
13970 });
13971 if !run_ranges_errors.is_empty() {
13972 log::error!(
13973 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13974 label.text
13975 );
13976 }
13977
13978 let mut wrong_filter_range = None;
13979 if label.filter_range == (0..label.text.len()) {
13980 label.filter_range = 0..new_text.len();
13981 } else {
13982 let mut original_filter_range = Some(label.filter_range.clone());
13983 match offset_map.get(label.filter_range.start) {
13984 Some(&start) => label.filter_range.start = start,
13985 None => {
13986 wrong_filter_range = original_filter_range.take();
13987 label.filter_range.start = last_index;
13988 }
13989 }
13990
13991 match offset_map.get(label.filter_range.end) {
13992 Some(&end) => label.filter_range.end = end,
13993 None => {
13994 wrong_filter_range = original_filter_range.take();
13995 label.filter_range.end = last_index;
13996 }
13997 }
13998 }
13999 if let Some(wrong_filter_range) = wrong_filter_range {
14000 log::error!(
14001 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14002 label.text
14003 );
14004 }
14005
14006 label.text = new_text;
14007}
14008
14009#[cfg(test)]
14010mod tests {
14011 use language::HighlightId;
14012
14013 use super::*;
14014
14015 #[test]
14016 fn test_glob_literal_prefix() {
14017 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14018 assert_eq!(
14019 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14020 Path::new("node_modules")
14021 );
14022 assert_eq!(
14023 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14024 Path::new("foo")
14025 );
14026 assert_eq!(
14027 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14028 Path::new("foo/bar/baz.js")
14029 );
14030
14031 #[cfg(target_os = "windows")]
14032 {
14033 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14034 assert_eq!(
14035 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14036 Path::new("node_modules")
14037 );
14038 assert_eq!(
14039 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14040 Path::new("foo")
14041 );
14042 assert_eq!(
14043 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14044 Path::new("foo/bar/baz.js")
14045 );
14046 }
14047 }
14048
14049 #[test]
14050 fn test_multi_len_chars_normalization() {
14051 let mut label = CodeLabel::new(
14052 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14053 0..6,
14054 vec![(0..6, HighlightId(1))],
14055 );
14056 ensure_uniform_list_compatible_label(&mut label);
14057 assert_eq!(
14058 label,
14059 CodeLabel::new(
14060 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14061 0..6,
14062 vec![(0..6, HighlightId(1))],
14063 )
14064 );
14065 }
14066}