1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 worktree_store::{WorktreeStore, WorktreeStoreEvent},
42 yarn::YarnPathStore,
43};
44use anyhow::{Context as _, Result, anyhow};
45use async_trait::async_trait;
46use client::{TypedEnvelope, proto};
47use clock::Global;
48use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
49use futures::{
50 AsyncWriteExt, Future, FutureExt, StreamExt,
51 future::{Either, Shared, join_all, pending, select},
52 select, select_biased,
53 stream::FuturesUnordered,
54};
55use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
56use gpui::{
57 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
58 WeakEntity,
59};
60use http_client::HttpClient;
61use itertools::Itertools as _;
62use language::{
63 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
64 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
65 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
66 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
67 Transaction, Unclipped,
68 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
69 point_to_lsp,
70 proto::{
71 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
72 serialize_lsp_edit, serialize_version,
73 },
74 range_from_lsp, range_to_lsp,
75 row_chunk::RowChunk,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use serde_json::Value;
97use settings::{Settings, SettingsLocation, SettingsStore};
98use sha2::{Digest, Sha256};
99use smol::channel::Sender;
100use snippet::Snippet;
101use std::{
102 any::TypeId,
103 borrow::Cow,
104 cell::RefCell,
105 cmp::{Ordering, Reverse},
106 convert::TryInto,
107 ffi::OsStr,
108 future::ready,
109 iter, mem,
110 ops::{ControlFlow, Range},
111 path::{self, Path, PathBuf},
112 pin::pin,
113 rc::Rc,
114 sync::{
115 Arc,
116 atomic::{self, AtomicUsize},
117 },
118 time::{Duration, Instant},
119};
120use sum_tree::Dimensions;
121use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
122
123use util::{
124 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
125 paths::{PathStyle, SanitizedPath},
126 post_inc,
127 rel_path::RelPath,
128};
129
130pub use fs::*;
131pub use language::Location;
132pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
133#[cfg(any(test, feature = "test-support"))]
134pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
135pub use worktree::{
136 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
137 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
138};
139
140const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
141pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
142const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
143const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
144
145#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
146pub enum ProgressToken {
147 Number(i32),
148 String(SharedString),
149}
150
151impl std::fmt::Display for ProgressToken {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 Self::Number(number) => write!(f, "{number}"),
155 Self::String(string) => write!(f, "{string}"),
156 }
157 }
158}
159
160impl ProgressToken {
161 fn from_lsp(value: lsp::NumberOrString) -> Self {
162 match value {
163 lsp::NumberOrString::Number(number) => Self::Number(number),
164 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
165 }
166 }
167
168 fn to_lsp(&self) -> lsp::NumberOrString {
169 match self {
170 Self::Number(number) => lsp::NumberOrString::Number(*number),
171 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
172 }
173 }
174
175 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
176 Some(match value.value? {
177 proto::progress_token::Value::Number(number) => Self::Number(number),
178 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
179 })
180 }
181
182 fn to_proto(&self) -> proto::ProgressToken {
183 proto::ProgressToken {
184 value: Some(match self {
185 Self::Number(number) => proto::progress_token::Value::Number(*number),
186 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
187 }),
188 }
189 }
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum FormatTrigger {
194 Save,
195 Manual,
196}
197
198pub enum LspFormatTarget {
199 Buffers,
200 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
201}
202
203pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
204
205impl FormatTrigger {
206 fn from_proto(value: i32) -> FormatTrigger {
207 match value {
208 0 => FormatTrigger::Save,
209 1 => FormatTrigger::Manual,
210 _ => FormatTrigger::Save,
211 }
212 }
213}
214
215#[derive(Clone)]
216struct UnifiedLanguageServer {
217 id: LanguageServerId,
218 project_roots: HashSet<Arc<RelPath>>,
219}
220
221#[derive(Clone, Hash, PartialEq, Eq)]
222struct LanguageServerSeed {
223 worktree_id: WorktreeId,
224 name: LanguageServerName,
225 toolchain: Option<Toolchain>,
226 settings: Arc<LspSettings>,
227}
228
229#[derive(Debug)]
230pub struct DocumentDiagnosticsUpdate<'a, D> {
231 pub diagnostics: D,
232 pub result_id: Option<String>,
233 pub server_id: LanguageServerId,
234 pub disk_based_sources: Cow<'a, [String]>,
235}
236
237pub struct DocumentDiagnostics {
238 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
239 document_abs_path: PathBuf,
240 version: Option<i32>,
241}
242
243#[derive(Default, Debug)]
244struct DynamicRegistrations {
245 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
246 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
247}
248
249pub struct LocalLspStore {
250 weak: WeakEntity<LspStore>,
251 worktree_store: Entity<WorktreeStore>,
252 toolchain_store: Entity<LocalToolchainStore>,
253 http_client: Arc<dyn HttpClient>,
254 environment: Entity<ProjectEnvironment>,
255 fs: Arc<dyn Fs>,
256 languages: Arc<LanguageRegistry>,
257 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
258 yarn: Entity<YarnPathStore>,
259 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
260 buffers_being_formatted: HashSet<BufferId>,
261 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
262 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
263 watched_manifest_filenames: HashSet<ManifestName>,
264 language_server_paths_watched_for_rename:
265 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
266 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
267 supplementary_language_servers:
268 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
269 prettier_store: Entity<PrettierStore>,
270 next_diagnostic_group_id: usize,
271 diagnostics: HashMap<
272 WorktreeId,
273 HashMap<
274 Arc<RelPath>,
275 Vec<(
276 LanguageServerId,
277 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
278 )>,
279 >,
280 >,
281 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
282 _subscription: gpui::Subscription,
283 lsp_tree: LanguageServerTree,
284 registered_buffers: HashMap<BufferId, usize>,
285 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
286 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
287}
288
289impl LocalLspStore {
290 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
291 pub fn running_language_server_for_id(
292 &self,
293 id: LanguageServerId,
294 ) -> Option<&Arc<LanguageServer>> {
295 let language_server_state = self.language_servers.get(&id)?;
296
297 match language_server_state {
298 LanguageServerState::Running { server, .. } => Some(server),
299 LanguageServerState::Starting { .. } => None,
300 }
301 }
302
303 fn get_or_insert_language_server(
304 &mut self,
305 worktree_handle: &Entity<Worktree>,
306 delegate: Arc<LocalLspAdapterDelegate>,
307 disposition: &Arc<LaunchDisposition>,
308 language_name: &LanguageName,
309 cx: &mut App,
310 ) -> LanguageServerId {
311 let key = LanguageServerSeed {
312 worktree_id: worktree_handle.read(cx).id(),
313 name: disposition.server_name.clone(),
314 settings: disposition.settings.clone(),
315 toolchain: disposition.toolchain.clone(),
316 };
317 if let Some(state) = self.language_server_ids.get_mut(&key) {
318 state.project_roots.insert(disposition.path.path.clone());
319 state.id
320 } else {
321 let adapter = self
322 .languages
323 .lsp_adapters(language_name)
324 .into_iter()
325 .find(|adapter| adapter.name() == disposition.server_name)
326 .expect("To find LSP adapter");
327 let new_language_server_id = self.start_language_server(
328 worktree_handle,
329 delegate,
330 adapter,
331 disposition.settings.clone(),
332 key.clone(),
333 cx,
334 );
335 if let Some(state) = self.language_server_ids.get_mut(&key) {
336 state.project_roots.insert(disposition.path.path.clone());
337 } else {
338 debug_assert!(
339 false,
340 "Expected `start_language_server` to ensure that `key` exists in a map"
341 );
342 }
343 new_language_server_id
344 }
345 }
346
347 fn start_language_server(
348 &mut self,
349 worktree_handle: &Entity<Worktree>,
350 delegate: Arc<LocalLspAdapterDelegate>,
351 adapter: Arc<CachedLspAdapter>,
352 settings: Arc<LspSettings>,
353 key: LanguageServerSeed,
354 cx: &mut App,
355 ) -> LanguageServerId {
356 let worktree = worktree_handle.read(cx);
357
358 let root_path = worktree.abs_path();
359 let toolchain = key.toolchain.clone();
360 let override_options = settings.initialization_options.clone();
361
362 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
363
364 let server_id = self.languages.next_language_server_id();
365 log::trace!(
366 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
367 adapter.name.0
368 );
369
370 let binary = self.get_language_server_binary(
371 adapter.clone(),
372 settings,
373 toolchain.clone(),
374 delegate.clone(),
375 true,
376 cx,
377 );
378 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
379
380 let pending_server = cx.spawn({
381 let adapter = adapter.clone();
382 let server_name = adapter.name.clone();
383 let stderr_capture = stderr_capture.clone();
384 #[cfg(any(test, feature = "test-support"))]
385 let lsp_store = self.weak.clone();
386 let pending_workspace_folders = pending_workspace_folders.clone();
387 async move |cx| {
388 let binary = binary.await?;
389 #[cfg(any(test, feature = "test-support"))]
390 if let Some(server) = lsp_store
391 .update(&mut cx.clone(), |this, cx| {
392 this.languages.create_fake_language_server(
393 server_id,
394 &server_name,
395 binary.clone(),
396 &mut cx.to_async(),
397 )
398 })
399 .ok()
400 .flatten()
401 {
402 return Ok(server);
403 }
404
405 let code_action_kinds = adapter.code_action_kinds();
406 lsp::LanguageServer::new(
407 stderr_capture,
408 server_id,
409 server_name,
410 binary,
411 &root_path,
412 code_action_kinds,
413 Some(pending_workspace_folders),
414 cx,
415 )
416 }
417 });
418
419 let startup = {
420 let server_name = adapter.name.0.clone();
421 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
422 let key = key.clone();
423 let adapter = adapter.clone();
424 let lsp_store = self.weak.clone();
425 let pending_workspace_folders = pending_workspace_folders.clone();
426
427 let pull_diagnostics = ProjectSettings::get_global(cx)
428 .diagnostics
429 .lsp_pull_diagnostics
430 .enabled;
431 cx.spawn(async move |cx| {
432 let result = async {
433 let language_server = pending_server.await?;
434
435 let workspace_config = Self::workspace_configuration_for_adapter(
436 adapter.adapter.clone(),
437 &delegate,
438 toolchain,
439 cx,
440 )
441 .await?;
442
443 let mut initialization_options = Self::initialization_options_for_adapter(
444 adapter.adapter.clone(),
445 &delegate,
446 )
447 .await?;
448
449 match (&mut initialization_options, override_options) {
450 (Some(initialization_options), Some(override_options)) => {
451 merge_json_value_into(override_options, initialization_options);
452 }
453 (None, override_options) => initialization_options = override_options,
454 _ => {}
455 }
456
457 let initialization_params = cx.update(|cx| {
458 let mut params =
459 language_server.default_initialize_params(pull_diagnostics, cx);
460 params.initialization_options = initialization_options;
461 adapter.adapter.prepare_initialize_params(params, cx)
462 })??;
463
464 Self::setup_lsp_messages(
465 lsp_store.clone(),
466 &language_server,
467 delegate.clone(),
468 adapter.clone(),
469 );
470
471 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
472 settings: workspace_config,
473 };
474 let language_server = cx
475 .update(|cx| {
476 language_server.initialize(
477 initialization_params,
478 Arc::new(did_change_configuration_params.clone()),
479 cx,
480 )
481 })?
482 .await
483 .inspect_err(|_| {
484 if let Some(lsp_store) = lsp_store.upgrade() {
485 lsp_store
486 .update(cx, |lsp_store, cx| {
487 lsp_store.cleanup_lsp_data(server_id);
488 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
489 })
490 .ok();
491 }
492 })?;
493
494 language_server.notify::<lsp::notification::DidChangeConfiguration>(
495 did_change_configuration_params,
496 )?;
497
498 anyhow::Ok(language_server)
499 }
500 .await;
501
502 match result {
503 Ok(server) => {
504 lsp_store
505 .update(cx, |lsp_store, cx| {
506 lsp_store.insert_newly_running_language_server(
507 adapter,
508 server.clone(),
509 server_id,
510 key,
511 pending_workspace_folders,
512 cx,
513 );
514 })
515 .ok();
516 stderr_capture.lock().take();
517 Some(server)
518 }
519
520 Err(err) => {
521 let log = stderr_capture.lock().take().unwrap_or_default();
522 delegate.update_status(
523 adapter.name(),
524 BinaryStatus::Failed {
525 error: if log.is_empty() {
526 format!("{err:#}")
527 } else {
528 format!("{err:#}\n-- stderr --\n{log}")
529 },
530 },
531 );
532 log::error!("Failed to start language server {server_name:?}: {err:?}");
533 if !log.is_empty() {
534 log::error!("server stderr: {log}");
535 }
536 None
537 }
538 }
539 })
540 };
541 let state = LanguageServerState::Starting {
542 startup,
543 pending_workspace_folders,
544 };
545
546 self.languages
547 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
548
549 self.language_servers.insert(server_id, state);
550 self.language_server_ids
551 .entry(key)
552 .or_insert(UnifiedLanguageServer {
553 id: server_id,
554 project_roots: Default::default(),
555 });
556 server_id
557 }
558
559 fn get_language_server_binary(
560 &self,
561 adapter: Arc<CachedLspAdapter>,
562 settings: Arc<LspSettings>,
563 toolchain: Option<Toolchain>,
564 delegate: Arc<dyn LspAdapterDelegate>,
565 allow_binary_download: bool,
566 cx: &mut App,
567 ) -> Task<Result<LanguageServerBinary>> {
568 if let Some(settings) = &settings.binary
569 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
570 {
571 let settings = settings.clone();
572
573 return cx.background_spawn(async move {
574 let mut env = delegate.shell_env().await;
575 env.extend(settings.env.unwrap_or_default());
576
577 Ok(LanguageServerBinary {
578 path: delegate.resolve_executable_path(path),
579 env: Some(env),
580 arguments: settings
581 .arguments
582 .unwrap_or_default()
583 .iter()
584 .map(Into::into)
585 .collect(),
586 })
587 });
588 }
589 let lsp_binary_options = LanguageServerBinaryOptions {
590 allow_path_lookup: !settings
591 .binary
592 .as_ref()
593 .and_then(|b| b.ignore_system_version)
594 .unwrap_or_default(),
595 allow_binary_download,
596 pre_release: settings
597 .fetch
598 .as_ref()
599 .and_then(|f| f.pre_release)
600 .unwrap_or(false),
601 };
602
603 cx.spawn(async move |cx| {
604 let (existing_binary, maybe_download_binary) = adapter
605 .clone()
606 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
607 .await
608 .await;
609
610 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
611
612 let mut binary = match (existing_binary, maybe_download_binary) {
613 (binary, None) => binary?,
614 (Err(_), Some(downloader)) => downloader.await?,
615 (Ok(existing_binary), Some(downloader)) => {
616 let mut download_timeout = cx
617 .background_executor()
618 .timer(SERVER_DOWNLOAD_TIMEOUT)
619 .fuse();
620 let mut downloader = downloader.fuse();
621 futures::select! {
622 _ = download_timeout => {
623 // Return existing binary and kick the existing work to the background.
624 cx.spawn(async move |_| downloader.await).detach();
625 Ok(existing_binary)
626 },
627 downloaded_or_existing_binary = downloader => {
628 // If download fails, this results in the existing binary.
629 downloaded_or_existing_binary
630 }
631 }?
632 }
633 };
634 let mut shell_env = delegate.shell_env().await;
635
636 shell_env.extend(binary.env.unwrap_or_default());
637
638 if let Some(settings) = settings.binary.as_ref() {
639 if let Some(arguments) = &settings.arguments {
640 binary.arguments = arguments.iter().map(Into::into).collect();
641 }
642 if let Some(env) = &settings.env {
643 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
644 }
645 }
646
647 binary.env = Some(shell_env);
648 Ok(binary)
649 })
650 }
651
652 fn setup_lsp_messages(
653 lsp_store: WeakEntity<LspStore>,
654 language_server: &LanguageServer,
655 delegate: Arc<dyn LspAdapterDelegate>,
656 adapter: Arc<CachedLspAdapter>,
657 ) {
658 let name = language_server.name();
659 let server_id = language_server.server_id();
660 language_server
661 .on_notification::<lsp::notification::PublishDiagnostics, _>({
662 let adapter = adapter.clone();
663 let this = lsp_store.clone();
664 move |mut params, cx| {
665 let adapter = adapter.clone();
666 if let Some(this) = this.upgrade() {
667 this.update(cx, |this, cx| {
668 {
669 let buffer = params
670 .uri
671 .to_file_path()
672 .map(|file_path| this.get_buffer(&file_path, cx))
673 .ok()
674 .flatten();
675 adapter.process_diagnostics(&mut params, server_id, buffer);
676 }
677
678 this.merge_lsp_diagnostics(
679 DiagnosticSourceKind::Pushed,
680 vec![DocumentDiagnosticsUpdate {
681 server_id,
682 diagnostics: params,
683 result_id: None,
684 disk_based_sources: Cow::Borrowed(
685 &adapter.disk_based_diagnostic_sources,
686 ),
687 }],
688 |_, diagnostic, cx| match diagnostic.source_kind {
689 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
690 adapter.retain_old_diagnostic(diagnostic, cx)
691 }
692 DiagnosticSourceKind::Pulled => true,
693 },
694 cx,
695 )
696 .log_err();
697 })
698 .ok();
699 }
700 }
701 })
702 .detach();
703 language_server
704 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
705 let adapter = adapter.adapter.clone();
706 let delegate = delegate.clone();
707 let this = lsp_store.clone();
708 move |params, cx| {
709 let adapter = adapter.clone();
710 let delegate = delegate.clone();
711 let this = this.clone();
712 let mut cx = cx.clone();
713 async move {
714 let toolchain_for_id = this
715 .update(&mut cx, |this, _| {
716 this.as_local()?.language_server_ids.iter().find_map(
717 |(seed, value)| {
718 (value.id == server_id).then(|| seed.toolchain.clone())
719 },
720 )
721 })?
722 .context("Expected the LSP store to be in a local mode")?;
723 let workspace_config = Self::workspace_configuration_for_adapter(
724 adapter.clone(),
725 &delegate,
726 toolchain_for_id,
727 &mut cx,
728 )
729 .await?;
730
731 Ok(params
732 .items
733 .into_iter()
734 .map(|item| {
735 if let Some(section) = &item.section {
736 workspace_config
737 .get(section)
738 .cloned()
739 .unwrap_or(serde_json::Value::Null)
740 } else {
741 workspace_config.clone()
742 }
743 })
744 .collect())
745 }
746 }
747 })
748 .detach();
749
750 language_server
751 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
752 let this = lsp_store.clone();
753 move |_, cx| {
754 let this = this.clone();
755 let cx = cx.clone();
756 async move {
757 let Some(server) =
758 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
759 else {
760 return Ok(None);
761 };
762 let root = server.workspace_folders();
763 Ok(Some(
764 root.into_iter()
765 .map(|uri| WorkspaceFolder {
766 uri,
767 name: Default::default(),
768 })
769 .collect(),
770 ))
771 }
772 }
773 })
774 .detach();
775 // Even though we don't have handling for these requests, respond to them to
776 // avoid stalling any language server like `gopls` which waits for a response
777 // to these requests when initializing.
778 language_server
779 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
780 let this = lsp_store.clone();
781 move |params, cx| {
782 let this = this.clone();
783 let mut cx = cx.clone();
784 async move {
785 this.update(&mut cx, |this, _| {
786 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
787 {
788 status
789 .progress_tokens
790 .insert(ProgressToken::from_lsp(params.token));
791 }
792 })?;
793
794 Ok(())
795 }
796 }
797 })
798 .detach();
799
800 language_server
801 .on_request::<lsp::request::RegisterCapability, _, _>({
802 let lsp_store = lsp_store.clone();
803 move |params, cx| {
804 let lsp_store = lsp_store.clone();
805 let mut cx = cx.clone();
806 async move {
807 lsp_store
808 .update(&mut cx, |lsp_store, cx| {
809 if lsp_store.as_local().is_some() {
810 match lsp_store
811 .register_server_capabilities(server_id, params, cx)
812 {
813 Ok(()) => {}
814 Err(e) => {
815 log::error!(
816 "Failed to register server capabilities: {e:#}"
817 );
818 }
819 };
820 }
821 })
822 .ok();
823 Ok(())
824 }
825 }
826 })
827 .detach();
828
829 language_server
830 .on_request::<lsp::request::UnregisterCapability, _, _>({
831 let lsp_store = lsp_store.clone();
832 move |params, cx| {
833 let lsp_store = lsp_store.clone();
834 let mut cx = cx.clone();
835 async move {
836 lsp_store
837 .update(&mut cx, |lsp_store, cx| {
838 if lsp_store.as_local().is_some() {
839 match lsp_store
840 .unregister_server_capabilities(server_id, params, cx)
841 {
842 Ok(()) => {}
843 Err(e) => {
844 log::error!(
845 "Failed to unregister server capabilities: {e:#}"
846 );
847 }
848 }
849 }
850 })
851 .ok();
852 Ok(())
853 }
854 }
855 })
856 .detach();
857
858 language_server
859 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
860 let this = lsp_store.clone();
861 move |params, cx| {
862 let mut cx = cx.clone();
863 let this = this.clone();
864 async move {
865 LocalLspStore::on_lsp_workspace_edit(
866 this.clone(),
867 params,
868 server_id,
869 &mut cx,
870 )
871 .await
872 }
873 }
874 })
875 .detach();
876
877 language_server
878 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
879 let lsp_store = lsp_store.clone();
880 let request_id = Arc::new(AtomicUsize::new(0));
881 move |(), cx| {
882 let lsp_store = lsp_store.clone();
883 let request_id = request_id.clone();
884 let mut cx = cx.clone();
885 async move {
886 lsp_store
887 .update(&mut cx, |lsp_store, cx| {
888 let request_id =
889 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
890 cx.emit(LspStoreEvent::RefreshInlayHints {
891 server_id,
892 request_id,
893 });
894 lsp_store
895 .downstream_client
896 .as_ref()
897 .map(|(client, project_id)| {
898 client.send(proto::RefreshInlayHints {
899 project_id: *project_id,
900 server_id: server_id.to_proto(),
901 request_id: request_id.map(|id| id as u64),
902 })
903 })
904 })?
905 .transpose()?;
906 Ok(())
907 }
908 }
909 })
910 .detach();
911
912 language_server
913 .on_request::<lsp::request::CodeLensRefresh, _, _>({
914 let this = lsp_store.clone();
915 move |(), cx| {
916 let this = this.clone();
917 let mut cx = cx.clone();
918 async move {
919 this.update(&mut cx, |this, cx| {
920 cx.emit(LspStoreEvent::RefreshCodeLens);
921 this.downstream_client.as_ref().map(|(client, project_id)| {
922 client.send(proto::RefreshCodeLens {
923 project_id: *project_id,
924 })
925 })
926 })?
927 .transpose()?;
928 Ok(())
929 }
930 }
931 })
932 .detach();
933
934 language_server
935 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
936 let this = lsp_store.clone();
937 move |(), cx| {
938 let this = this.clone();
939 let mut cx = cx.clone();
940 async move {
941 this.update(&mut cx, |lsp_store, _| {
942 lsp_store.pull_workspace_diagnostics(server_id);
943 lsp_store
944 .downstream_client
945 .as_ref()
946 .map(|(client, project_id)| {
947 client.send(proto::PullWorkspaceDiagnostics {
948 project_id: *project_id,
949 server_id: server_id.to_proto(),
950 })
951 })
952 })?
953 .transpose()?;
954 Ok(())
955 }
956 }
957 })
958 .detach();
959
960 language_server
961 .on_request::<lsp::request::ShowMessageRequest, _, _>({
962 let this = lsp_store.clone();
963 let name = name.to_string();
964 move |params, cx| {
965 let this = this.clone();
966 let name = name.to_string();
967 let mut cx = cx.clone();
968 async move {
969 let actions = params.actions.unwrap_or_default();
970 let (tx, rx) = smol::channel::bounded(1);
971 let request = LanguageServerPromptRequest {
972 level: match params.typ {
973 lsp::MessageType::ERROR => PromptLevel::Critical,
974 lsp::MessageType::WARNING => PromptLevel::Warning,
975 _ => PromptLevel::Info,
976 },
977 message: params.message,
978 actions,
979 response_channel: tx,
980 lsp_name: name.clone(),
981 };
982
983 let did_update = this
984 .update(&mut cx, |_, cx| {
985 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
986 })
987 .is_ok();
988 if did_update {
989 let response = rx.recv().await.ok();
990 Ok(response)
991 } else {
992 Ok(None)
993 }
994 }
995 }
996 })
997 .detach();
998 language_server
999 .on_notification::<lsp::notification::ShowMessage, _>({
1000 let this = lsp_store.clone();
1001 let name = name.to_string();
1002 move |params, cx| {
1003 let this = this.clone();
1004 let name = name.to_string();
1005 let mut cx = cx.clone();
1006
1007 let (tx, _) = smol::channel::bounded(1);
1008 let request = LanguageServerPromptRequest {
1009 level: match params.typ {
1010 lsp::MessageType::ERROR => PromptLevel::Critical,
1011 lsp::MessageType::WARNING => PromptLevel::Warning,
1012 _ => PromptLevel::Info,
1013 },
1014 message: params.message,
1015 actions: vec![],
1016 response_channel: tx,
1017 lsp_name: name,
1018 };
1019
1020 let _ = this.update(&mut cx, |_, cx| {
1021 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1022 });
1023 }
1024 })
1025 .detach();
1026
1027 let disk_based_diagnostics_progress_token =
1028 adapter.disk_based_diagnostics_progress_token.clone();
1029
1030 language_server
1031 .on_notification::<lsp::notification::Progress, _>({
1032 let this = lsp_store.clone();
1033 move |params, cx| {
1034 if let Some(this) = this.upgrade() {
1035 this.update(cx, |this, cx| {
1036 this.on_lsp_progress(
1037 params,
1038 server_id,
1039 disk_based_diagnostics_progress_token.clone(),
1040 cx,
1041 );
1042 })
1043 .ok();
1044 }
1045 }
1046 })
1047 .detach();
1048
1049 language_server
1050 .on_notification::<lsp::notification::LogMessage, _>({
1051 let this = lsp_store.clone();
1052 move |params, cx| {
1053 if let Some(this) = this.upgrade() {
1054 this.update(cx, |_, cx| {
1055 cx.emit(LspStoreEvent::LanguageServerLog(
1056 server_id,
1057 LanguageServerLogType::Log(params.typ),
1058 params.message,
1059 ));
1060 })
1061 .ok();
1062 }
1063 }
1064 })
1065 .detach();
1066
1067 language_server
1068 .on_notification::<lsp::notification::LogTrace, _>({
1069 let this = lsp_store.clone();
1070 move |params, cx| {
1071 let mut cx = cx.clone();
1072 if let Some(this) = this.upgrade() {
1073 this.update(&mut cx, |_, cx| {
1074 cx.emit(LspStoreEvent::LanguageServerLog(
1075 server_id,
1076 LanguageServerLogType::Trace {
1077 verbose_info: params.verbose,
1078 },
1079 params.message,
1080 ));
1081 })
1082 .ok();
1083 }
1084 }
1085 })
1086 .detach();
1087
1088 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1089 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1090 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1091 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1092 }
1093
1094 fn shutdown_language_servers_on_quit(
1095 &mut self,
1096 _: &mut Context<LspStore>,
1097 ) -> impl Future<Output = ()> + use<> {
1098 let shutdown_futures = self
1099 .language_servers
1100 .drain()
1101 .map(|(_, server_state)| Self::shutdown_server(server_state))
1102 .collect::<Vec<_>>();
1103
1104 async move {
1105 join_all(shutdown_futures).await;
1106 }
1107 }
1108
1109 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1110 match server_state {
1111 LanguageServerState::Running { server, .. } => {
1112 if let Some(shutdown) = server.shutdown() {
1113 shutdown.await;
1114 }
1115 }
1116 LanguageServerState::Starting { startup, .. } => {
1117 if let Some(server) = startup.await
1118 && let Some(shutdown) = server.shutdown()
1119 {
1120 shutdown.await;
1121 }
1122 }
1123 }
1124 Ok(())
1125 }
1126
1127 fn language_servers_for_worktree(
1128 &self,
1129 worktree_id: WorktreeId,
1130 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1131 self.language_server_ids
1132 .iter()
1133 .filter_map(move |(seed, state)| {
1134 if seed.worktree_id != worktree_id {
1135 return None;
1136 }
1137
1138 if let Some(LanguageServerState::Running { server, .. }) =
1139 self.language_servers.get(&state.id)
1140 {
1141 Some(server)
1142 } else {
1143 None
1144 }
1145 })
1146 }
1147
1148 fn language_server_ids_for_project_path(
1149 &self,
1150 project_path: ProjectPath,
1151 language: &Language,
1152 cx: &mut App,
1153 ) -> Vec<LanguageServerId> {
1154 let Some(worktree) = self
1155 .worktree_store
1156 .read(cx)
1157 .worktree_for_id(project_path.worktree_id, cx)
1158 else {
1159 return Vec::new();
1160 };
1161 let delegate: Arc<dyn ManifestDelegate> =
1162 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1163
1164 self.lsp_tree
1165 .get(
1166 project_path,
1167 language.name(),
1168 language.manifest(),
1169 &delegate,
1170 cx,
1171 )
1172 .collect::<Vec<_>>()
1173 }
1174
1175 fn language_server_ids_for_buffer(
1176 &self,
1177 buffer: &Buffer,
1178 cx: &mut App,
1179 ) -> Vec<LanguageServerId> {
1180 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1181 let worktree_id = file.worktree_id(cx);
1182
1183 let path: Arc<RelPath> = file
1184 .path()
1185 .parent()
1186 .map(Arc::from)
1187 .unwrap_or_else(|| file.path().clone());
1188 let worktree_path = ProjectPath { worktree_id, path };
1189 self.language_server_ids_for_project_path(worktree_path, language, cx)
1190 } else {
1191 Vec::new()
1192 }
1193 }
1194
1195 fn language_servers_for_buffer<'a>(
1196 &'a self,
1197 buffer: &'a Buffer,
1198 cx: &'a mut App,
1199 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1200 self.language_server_ids_for_buffer(buffer, cx)
1201 .into_iter()
1202 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1203 LanguageServerState::Running {
1204 adapter, server, ..
1205 } => Some((adapter, server)),
1206 _ => None,
1207 })
1208 }
1209
1210 async fn execute_code_action_kind_locally(
1211 lsp_store: WeakEntity<LspStore>,
1212 mut buffers: Vec<Entity<Buffer>>,
1213 kind: CodeActionKind,
1214 push_to_history: bool,
1215 cx: &mut AsyncApp,
1216 ) -> anyhow::Result<ProjectTransaction> {
1217 // Do not allow multiple concurrent code actions requests for the
1218 // same buffer.
1219 lsp_store.update(cx, |this, cx| {
1220 let this = this.as_local_mut().unwrap();
1221 buffers.retain(|buffer| {
1222 this.buffers_being_formatted
1223 .insert(buffer.read(cx).remote_id())
1224 });
1225 })?;
1226 let _cleanup = defer({
1227 let this = lsp_store.clone();
1228 let mut cx = cx.clone();
1229 let buffers = &buffers;
1230 move || {
1231 this.update(&mut cx, |this, cx| {
1232 let this = this.as_local_mut().unwrap();
1233 for buffer in buffers {
1234 this.buffers_being_formatted
1235 .remove(&buffer.read(cx).remote_id());
1236 }
1237 })
1238 .ok();
1239 }
1240 });
1241 let mut project_transaction = ProjectTransaction::default();
1242
1243 for buffer in &buffers {
1244 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1245 buffer.update(cx, |buffer, cx| {
1246 lsp_store
1247 .as_local()
1248 .unwrap()
1249 .language_servers_for_buffer(buffer, cx)
1250 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1251 .collect::<Vec<_>>()
1252 })
1253 })?;
1254 for (_, language_server) in adapters_and_servers.iter() {
1255 let actions = Self::get_server_code_actions_from_action_kinds(
1256 &lsp_store,
1257 language_server.server_id(),
1258 vec![kind.clone()],
1259 buffer,
1260 cx,
1261 )
1262 .await?;
1263 Self::execute_code_actions_on_server(
1264 &lsp_store,
1265 language_server,
1266 actions,
1267 push_to_history,
1268 &mut project_transaction,
1269 cx,
1270 )
1271 .await?;
1272 }
1273 }
1274 Ok(project_transaction)
1275 }
1276
1277 async fn format_locally(
1278 lsp_store: WeakEntity<LspStore>,
1279 mut buffers: Vec<FormattableBuffer>,
1280 push_to_history: bool,
1281 trigger: FormatTrigger,
1282 logger: zlog::Logger,
1283 cx: &mut AsyncApp,
1284 ) -> anyhow::Result<ProjectTransaction> {
1285 // Do not allow multiple concurrent formatting requests for the
1286 // same buffer.
1287 lsp_store.update(cx, |this, cx| {
1288 let this = this.as_local_mut().unwrap();
1289 buffers.retain(|buffer| {
1290 this.buffers_being_formatted
1291 .insert(buffer.handle.read(cx).remote_id())
1292 });
1293 })?;
1294
1295 let _cleanup = defer({
1296 let this = lsp_store.clone();
1297 let mut cx = cx.clone();
1298 let buffers = &buffers;
1299 move || {
1300 this.update(&mut cx, |this, cx| {
1301 let this = this.as_local_mut().unwrap();
1302 for buffer in buffers {
1303 this.buffers_being_formatted
1304 .remove(&buffer.handle.read(cx).remote_id());
1305 }
1306 })
1307 .ok();
1308 }
1309 });
1310
1311 let mut project_transaction = ProjectTransaction::default();
1312
1313 for buffer in &buffers {
1314 zlog::debug!(
1315 logger =>
1316 "formatting buffer '{:?}'",
1317 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1318 );
1319 // Create an empty transaction to hold all of the formatting edits.
1320 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1321 // ensure no transactions created while formatting are
1322 // grouped with the previous transaction in the history
1323 // based on the transaction group interval
1324 buffer.finalize_last_transaction();
1325 buffer
1326 .start_transaction()
1327 .context("transaction already open")?;
1328 buffer.end_transaction(cx);
1329 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1330 buffer.finalize_last_transaction();
1331 anyhow::Ok(transaction_id)
1332 })??;
1333
1334 let result = Self::format_buffer_locally(
1335 lsp_store.clone(),
1336 buffer,
1337 formatting_transaction_id,
1338 trigger,
1339 logger,
1340 cx,
1341 )
1342 .await;
1343
1344 buffer.handle.update(cx, |buffer, cx| {
1345 let Some(formatting_transaction) =
1346 buffer.get_transaction(formatting_transaction_id).cloned()
1347 else {
1348 zlog::warn!(logger => "no formatting transaction");
1349 return;
1350 };
1351 if formatting_transaction.edit_ids.is_empty() {
1352 zlog::debug!(logger => "no changes made while formatting");
1353 buffer.forget_transaction(formatting_transaction_id);
1354 return;
1355 }
1356 if !push_to_history {
1357 zlog::trace!(logger => "forgetting format transaction");
1358 buffer.forget_transaction(formatting_transaction.id);
1359 }
1360 project_transaction
1361 .0
1362 .insert(cx.entity(), formatting_transaction);
1363 })?;
1364
1365 result?;
1366 }
1367
1368 Ok(project_transaction)
1369 }
1370
1371 async fn format_buffer_locally(
1372 lsp_store: WeakEntity<LspStore>,
1373 buffer: &FormattableBuffer,
1374 formatting_transaction_id: clock::Lamport,
1375 trigger: FormatTrigger,
1376 logger: zlog::Logger,
1377 cx: &mut AsyncApp,
1378 ) -> Result<()> {
1379 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1380 buffer.handle.update(cx, |buffer, cx| {
1381 let adapters_and_servers = lsp_store
1382 .as_local()
1383 .unwrap()
1384 .language_servers_for_buffer(buffer, cx)
1385 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1386 .collect::<Vec<_>>();
1387 let settings =
1388 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1389 .into_owned();
1390 (adapters_and_servers, settings)
1391 })
1392 })?;
1393
1394 /// Apply edits to the buffer that will become part of the formatting transaction.
1395 /// Fails if the buffer has been edited since the start of that transaction.
1396 fn extend_formatting_transaction(
1397 buffer: &FormattableBuffer,
1398 formatting_transaction_id: text::TransactionId,
1399 cx: &mut AsyncApp,
1400 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1401 ) -> anyhow::Result<()> {
1402 buffer.handle.update(cx, |buffer, cx| {
1403 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1404 if last_transaction_id != Some(formatting_transaction_id) {
1405 anyhow::bail!("Buffer edited while formatting. Aborting")
1406 }
1407 buffer.start_transaction();
1408 operation(buffer, cx);
1409 if let Some(transaction_id) = buffer.end_transaction(cx) {
1410 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1411 }
1412 Ok(())
1413 })?
1414 }
1415
1416 // handle whitespace formatting
1417 if settings.remove_trailing_whitespace_on_save {
1418 zlog::trace!(logger => "removing trailing whitespace");
1419 let diff = buffer
1420 .handle
1421 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1422 .await;
1423 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1424 buffer.apply_diff(diff, cx);
1425 })?;
1426 }
1427
1428 if settings.ensure_final_newline_on_save {
1429 zlog::trace!(logger => "ensuring final newline");
1430 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1431 buffer.ensure_final_newline(cx);
1432 })?;
1433 }
1434
1435 // Formatter for `code_actions_on_format` that runs before
1436 // the rest of the formatters
1437 let mut code_actions_on_format_formatters = None;
1438 let should_run_code_actions_on_format = !matches!(
1439 (trigger, &settings.format_on_save),
1440 (FormatTrigger::Save, &FormatOnSave::Off)
1441 );
1442 if should_run_code_actions_on_format {
1443 let have_code_actions_to_run_on_format = settings
1444 .code_actions_on_format
1445 .values()
1446 .any(|enabled| *enabled);
1447 if have_code_actions_to_run_on_format {
1448 zlog::trace!(logger => "going to run code actions on format");
1449 code_actions_on_format_formatters = Some(
1450 settings
1451 .code_actions_on_format
1452 .iter()
1453 .filter_map(|(action, enabled)| enabled.then_some(action))
1454 .cloned()
1455 .map(Formatter::CodeAction)
1456 .collect::<Vec<_>>(),
1457 );
1458 }
1459 }
1460
1461 let formatters = match (trigger, &settings.format_on_save) {
1462 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1463 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1464 settings.formatter.as_ref()
1465 }
1466 };
1467
1468 let formatters = code_actions_on_format_formatters
1469 .iter()
1470 .flatten()
1471 .chain(formatters);
1472
1473 for formatter in formatters {
1474 let formatter = if formatter == &Formatter::Auto {
1475 if settings.prettier.allowed {
1476 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1477 &Formatter::Prettier
1478 } else {
1479 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1480 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1481 }
1482 } else {
1483 formatter
1484 };
1485 match formatter {
1486 Formatter::Auto => unreachable!("Auto resolved above"),
1487 Formatter::Prettier => {
1488 let logger = zlog::scoped!(logger => "prettier");
1489 zlog::trace!(logger => "formatting");
1490 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1491
1492 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1493 lsp_store.prettier_store().unwrap().downgrade()
1494 })?;
1495 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1496 .await
1497 .transpose()?;
1498 let Some(diff) = diff else {
1499 zlog::trace!(logger => "No changes");
1500 continue;
1501 };
1502
1503 extend_formatting_transaction(
1504 buffer,
1505 formatting_transaction_id,
1506 cx,
1507 |buffer, cx| {
1508 buffer.apply_diff(diff, cx);
1509 },
1510 )?;
1511 }
1512 Formatter::External { command, arguments } => {
1513 let logger = zlog::scoped!(logger => "command");
1514 zlog::trace!(logger => "formatting");
1515 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1516
1517 let diff = Self::format_via_external_command(
1518 buffer,
1519 command.as_ref(),
1520 arguments.as_deref(),
1521 cx,
1522 )
1523 .await
1524 .with_context(|| {
1525 format!("Failed to format buffer via external command: {}", command)
1526 })?;
1527 let Some(diff) = diff else {
1528 zlog::trace!(logger => "No changes");
1529 continue;
1530 };
1531
1532 extend_formatting_transaction(
1533 buffer,
1534 formatting_transaction_id,
1535 cx,
1536 |buffer, cx| {
1537 buffer.apply_diff(diff, cx);
1538 },
1539 )?;
1540 }
1541 Formatter::LanguageServer(specifier) => {
1542 let logger = zlog::scoped!(logger => "language-server");
1543 zlog::trace!(logger => "formatting");
1544 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1545
1546 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1547 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1548 continue;
1549 };
1550
1551 let language_server = match specifier {
1552 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1553 adapters_and_servers.iter().find_map(|(adapter, server)| {
1554 if adapter.name.0.as_ref() == name {
1555 Some(server.clone())
1556 } else {
1557 None
1558 }
1559 })
1560 }
1561 settings::LanguageServerFormatterSpecifier::Current => {
1562 adapters_and_servers.first().map(|e| e.1.clone())
1563 }
1564 };
1565
1566 let Some(language_server) = language_server else {
1567 log::debug!(
1568 "No language server found to format buffer '{:?}'. Skipping",
1569 buffer_path_abs.as_path().to_string_lossy()
1570 );
1571 continue;
1572 };
1573
1574 zlog::trace!(
1575 logger =>
1576 "Formatting buffer '{:?}' using language server '{:?}'",
1577 buffer_path_abs.as_path().to_string_lossy(),
1578 language_server.name()
1579 );
1580
1581 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1582 zlog::trace!(logger => "formatting ranges");
1583 Self::format_ranges_via_lsp(
1584 &lsp_store,
1585 &buffer.handle,
1586 ranges,
1587 buffer_path_abs,
1588 &language_server,
1589 &settings,
1590 cx,
1591 )
1592 .await
1593 .context("Failed to format ranges via language server")?
1594 } else {
1595 zlog::trace!(logger => "formatting full");
1596 Self::format_via_lsp(
1597 &lsp_store,
1598 &buffer.handle,
1599 buffer_path_abs,
1600 &language_server,
1601 &settings,
1602 cx,
1603 )
1604 .await
1605 .context("failed to format via language server")?
1606 };
1607
1608 if edits.is_empty() {
1609 zlog::trace!(logger => "No changes");
1610 continue;
1611 }
1612 extend_formatting_transaction(
1613 buffer,
1614 formatting_transaction_id,
1615 cx,
1616 |buffer, cx| {
1617 buffer.edit(edits, None, cx);
1618 },
1619 )?;
1620 }
1621 Formatter::CodeAction(code_action_name) => {
1622 let logger = zlog::scoped!(logger => "code-actions");
1623 zlog::trace!(logger => "formatting");
1624 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1625
1626 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1627 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1628 continue;
1629 };
1630
1631 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1632 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1633
1634 let mut actions_and_servers = Vec::new();
1635
1636 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1637 let actions_result = Self::get_server_code_actions_from_action_kinds(
1638 &lsp_store,
1639 language_server.server_id(),
1640 vec![code_action_kind.clone()],
1641 &buffer.handle,
1642 cx,
1643 )
1644 .await
1645 .with_context(|| {
1646 format!(
1647 "Failed to resolve code action {:?} with language server {}",
1648 code_action_kind,
1649 language_server.name()
1650 )
1651 });
1652 let Ok(actions) = actions_result else {
1653 // note: it may be better to set result to the error and break formatters here
1654 // but for now we try to execute the actions that we can resolve and skip the rest
1655 zlog::error!(
1656 logger =>
1657 "Failed to resolve code action {:?} with language server {}",
1658 code_action_kind,
1659 language_server.name()
1660 );
1661 continue;
1662 };
1663 for action in actions {
1664 actions_and_servers.push((action, index));
1665 }
1666 }
1667
1668 if actions_and_servers.is_empty() {
1669 zlog::warn!(logger => "No code actions were resolved, continuing");
1670 continue;
1671 }
1672
1673 'actions: for (mut action, server_index) in actions_and_servers {
1674 let server = &adapters_and_servers[server_index].1;
1675
1676 let describe_code_action = |action: &CodeAction| {
1677 format!(
1678 "code action '{}' with title \"{}\" on server {}",
1679 action
1680 .lsp_action
1681 .action_kind()
1682 .unwrap_or("unknown".into())
1683 .as_str(),
1684 action.lsp_action.title(),
1685 server.name(),
1686 )
1687 };
1688
1689 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1690
1691 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1692 zlog::error!(
1693 logger =>
1694 "Failed to resolve {}. Error: {}",
1695 describe_code_action(&action),
1696 err
1697 );
1698 continue;
1699 }
1700
1701 if let Some(edit) = action.lsp_action.edit().cloned() {
1702 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1703 // but filters out and logs warnings for code actions that require unreasonably
1704 // difficult handling on our part, such as:
1705 // - applying edits that call commands
1706 // which can result in arbitrary workspace edits being sent from the server that
1707 // have no way of being tied back to the command that initiated them (i.e. we
1708 // can't know which edits are part of the format request, or if the server is done sending
1709 // actions in response to the command)
1710 // - actions that create/delete/modify/rename files other than the one we are formatting
1711 // as we then would need to handle such changes correctly in the local history as well
1712 // as the remote history through the ProjectTransaction
1713 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1714 // Supporting these actions is not impossible, but not supported as of yet.
1715 if edit.changes.is_none() && edit.document_changes.is_none() {
1716 zlog::trace!(
1717 logger =>
1718 "No changes for code action. Skipping {}",
1719 describe_code_action(&action),
1720 );
1721 continue;
1722 }
1723
1724 let mut operations = Vec::new();
1725 if let Some(document_changes) = edit.document_changes {
1726 match document_changes {
1727 lsp::DocumentChanges::Edits(edits) => operations.extend(
1728 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1729 ),
1730 lsp::DocumentChanges::Operations(ops) => operations = ops,
1731 }
1732 } else if let Some(changes) = edit.changes {
1733 operations.extend(changes.into_iter().map(|(uri, edits)| {
1734 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1735 text_document:
1736 lsp::OptionalVersionedTextDocumentIdentifier {
1737 uri,
1738 version: None,
1739 },
1740 edits: edits.into_iter().map(Edit::Plain).collect(),
1741 })
1742 }));
1743 }
1744
1745 let mut edits = Vec::with_capacity(operations.len());
1746
1747 if operations.is_empty() {
1748 zlog::trace!(
1749 logger =>
1750 "No changes for code action. Skipping {}",
1751 describe_code_action(&action),
1752 );
1753 continue;
1754 }
1755 for operation in operations {
1756 let op = match operation {
1757 lsp::DocumentChangeOperation::Edit(op) => op,
1758 lsp::DocumentChangeOperation::Op(_) => {
1759 zlog::warn!(
1760 logger =>
1761 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1762 describe_code_action(&action),
1763 );
1764 continue 'actions;
1765 }
1766 };
1767 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1768 zlog::warn!(
1769 logger =>
1770 "Failed to convert URI '{:?}' to file path. Skipping {}",
1771 &op.text_document.uri,
1772 describe_code_action(&action),
1773 );
1774 continue 'actions;
1775 };
1776 if &file_path != buffer_path_abs {
1777 zlog::warn!(
1778 logger =>
1779 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1780 file_path,
1781 buffer_path_abs,
1782 describe_code_action(&action),
1783 );
1784 continue 'actions;
1785 }
1786
1787 let mut lsp_edits = Vec::new();
1788 for edit in op.edits {
1789 match edit {
1790 Edit::Plain(edit) => {
1791 if !lsp_edits.contains(&edit) {
1792 lsp_edits.push(edit);
1793 }
1794 }
1795 Edit::Annotated(edit) => {
1796 if !lsp_edits.contains(&edit.text_edit) {
1797 lsp_edits.push(edit.text_edit);
1798 }
1799 }
1800 Edit::Snippet(_) => {
1801 zlog::warn!(
1802 logger =>
1803 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1804 describe_code_action(&action),
1805 );
1806 continue 'actions;
1807 }
1808 }
1809 }
1810 let edits_result = lsp_store
1811 .update(cx, |lsp_store, cx| {
1812 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1813 &buffer.handle,
1814 lsp_edits,
1815 server.server_id(),
1816 op.text_document.version,
1817 cx,
1818 )
1819 })?
1820 .await;
1821 let Ok(resolved_edits) = edits_result else {
1822 zlog::warn!(
1823 logger =>
1824 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1825 buffer_path_abs.as_path(),
1826 describe_code_action(&action),
1827 );
1828 continue 'actions;
1829 };
1830 edits.extend(resolved_edits);
1831 }
1832
1833 if edits.is_empty() {
1834 zlog::warn!(logger => "No edits resolved from LSP");
1835 continue;
1836 }
1837
1838 extend_formatting_transaction(
1839 buffer,
1840 formatting_transaction_id,
1841 cx,
1842 |buffer, cx| {
1843 zlog::info!(
1844 "Applying edits {edits:?}. Content: {:?}",
1845 buffer.text()
1846 );
1847 buffer.edit(edits, None, cx);
1848 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1849 },
1850 )?;
1851 }
1852
1853 if let Some(command) = action.lsp_action.command() {
1854 zlog::warn!(
1855 logger =>
1856 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1857 &command.command,
1858 );
1859
1860 // bail early if command is invalid
1861 let server_capabilities = server.capabilities();
1862 let available_commands = server_capabilities
1863 .execute_command_provider
1864 .as_ref()
1865 .map(|options| options.commands.as_slice())
1866 .unwrap_or_default();
1867 if !available_commands.contains(&command.command) {
1868 zlog::warn!(
1869 logger =>
1870 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1871 command.command,
1872 server.name(),
1873 );
1874 continue;
1875 }
1876
1877 // noop so we just ensure buffer hasn't been edited since resolving code actions
1878 extend_formatting_transaction(
1879 buffer,
1880 formatting_transaction_id,
1881 cx,
1882 |_, _| {},
1883 )?;
1884 zlog::info!(logger => "Executing command {}", &command.command);
1885
1886 lsp_store.update(cx, |this, _| {
1887 this.as_local_mut()
1888 .unwrap()
1889 .last_workspace_edits_by_language_server
1890 .remove(&server.server_id());
1891 })?;
1892
1893 let execute_command_result = server
1894 .request::<lsp::request::ExecuteCommand>(
1895 lsp::ExecuteCommandParams {
1896 command: command.command.clone(),
1897 arguments: command.arguments.clone().unwrap_or_default(),
1898 ..Default::default()
1899 },
1900 )
1901 .await
1902 .into_response();
1903
1904 if execute_command_result.is_err() {
1905 zlog::error!(
1906 logger =>
1907 "Failed to execute command '{}' as part of {}",
1908 &command.command,
1909 describe_code_action(&action),
1910 );
1911 continue 'actions;
1912 }
1913
1914 let mut project_transaction_command =
1915 lsp_store.update(cx, |this, _| {
1916 this.as_local_mut()
1917 .unwrap()
1918 .last_workspace_edits_by_language_server
1919 .remove(&server.server_id())
1920 .unwrap_or_default()
1921 })?;
1922
1923 if let Some(transaction) =
1924 project_transaction_command.0.remove(&buffer.handle)
1925 {
1926 zlog::trace!(
1927 logger =>
1928 "Successfully captured {} edits that resulted from command {}",
1929 transaction.edit_ids.len(),
1930 &command.command,
1931 );
1932 let transaction_id_project_transaction = transaction.id;
1933 buffer.handle.update(cx, |buffer, _| {
1934 // it may have been removed from history if push_to_history was
1935 // false in deserialize_workspace_edit. If so push it so we
1936 // can merge it with the format transaction
1937 // and pop the combined transaction off the history stack
1938 // later if push_to_history is false
1939 if buffer.get_transaction(transaction.id).is_none() {
1940 buffer.push_transaction(transaction, Instant::now());
1941 }
1942 buffer.merge_transactions(
1943 transaction_id_project_transaction,
1944 formatting_transaction_id,
1945 );
1946 })?;
1947 }
1948
1949 if !project_transaction_command.0.is_empty() {
1950 let mut extra_buffers = String::new();
1951 for buffer in project_transaction_command.0.keys() {
1952 buffer
1953 .read_with(cx, |b, cx| {
1954 if let Some(path) = b.project_path(cx) {
1955 if !extra_buffers.is_empty() {
1956 extra_buffers.push_str(", ");
1957 }
1958 extra_buffers.push_str(path.path.as_unix_str());
1959 }
1960 })
1961 .ok();
1962 }
1963 zlog::warn!(
1964 logger =>
1965 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1966 &command.command,
1967 extra_buffers,
1968 );
1969 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1970 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1971 // add it so it's included, and merge it into the format transaction when its created later
1972 }
1973 }
1974 }
1975 }
1976 }
1977 }
1978
1979 Ok(())
1980 }
1981
1982 pub async fn format_ranges_via_lsp(
1983 this: &WeakEntity<LspStore>,
1984 buffer_handle: &Entity<Buffer>,
1985 ranges: &[Range<Anchor>],
1986 abs_path: &Path,
1987 language_server: &Arc<LanguageServer>,
1988 settings: &LanguageSettings,
1989 cx: &mut AsyncApp,
1990 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1991 let capabilities = &language_server.capabilities();
1992 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1993 if range_formatting_provider == Some(&OneOf::Left(false)) {
1994 anyhow::bail!(
1995 "{} language server does not support range formatting",
1996 language_server.name()
1997 );
1998 }
1999
2000 let uri = file_path_to_lsp_url(abs_path)?;
2001 let text_document = lsp::TextDocumentIdentifier::new(uri);
2002
2003 let lsp_edits = {
2004 let mut lsp_ranges = Vec::new();
2005 this.update(cx, |_this, cx| {
2006 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2007 // not have been sent to the language server. This seems like a fairly systemic
2008 // issue, though, the resolution probably is not specific to formatting.
2009 //
2010 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2011 // LSP.
2012 let snapshot = buffer_handle.read(cx).snapshot();
2013 for range in ranges {
2014 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2015 }
2016 anyhow::Ok(())
2017 })??;
2018
2019 let mut edits = None;
2020 for range in lsp_ranges {
2021 if let Some(mut edit) = language_server
2022 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2023 text_document: text_document.clone(),
2024 range,
2025 options: lsp_command::lsp_formatting_options(settings),
2026 work_done_progress_params: Default::default(),
2027 })
2028 .await
2029 .into_response()?
2030 {
2031 edits.get_or_insert_with(Vec::new).append(&mut edit);
2032 }
2033 }
2034 edits
2035 };
2036
2037 if let Some(lsp_edits) = lsp_edits {
2038 this.update(cx, |this, cx| {
2039 this.as_local_mut().unwrap().edits_from_lsp(
2040 buffer_handle,
2041 lsp_edits,
2042 language_server.server_id(),
2043 None,
2044 cx,
2045 )
2046 })?
2047 .await
2048 } else {
2049 Ok(Vec::with_capacity(0))
2050 }
2051 }
2052
2053 async fn format_via_lsp(
2054 this: &WeakEntity<LspStore>,
2055 buffer: &Entity<Buffer>,
2056 abs_path: &Path,
2057 language_server: &Arc<LanguageServer>,
2058 settings: &LanguageSettings,
2059 cx: &mut AsyncApp,
2060 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2061 let logger = zlog::scoped!("lsp_format");
2062 zlog::debug!(logger => "Formatting via LSP");
2063
2064 let uri = file_path_to_lsp_url(abs_path)?;
2065 let text_document = lsp::TextDocumentIdentifier::new(uri);
2066 let capabilities = &language_server.capabilities();
2067
2068 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2069 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2070
2071 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2072 let _timer = zlog::time!(logger => "format-full");
2073 language_server
2074 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2075 text_document,
2076 options: lsp_command::lsp_formatting_options(settings),
2077 work_done_progress_params: Default::default(),
2078 })
2079 .await
2080 .into_response()?
2081 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2082 let _timer = zlog::time!(logger => "format-range");
2083 let buffer_start = lsp::Position::new(0, 0);
2084 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2085 language_server
2086 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2087 text_document: text_document.clone(),
2088 range: lsp::Range::new(buffer_start, buffer_end),
2089 options: lsp_command::lsp_formatting_options(settings),
2090 work_done_progress_params: Default::default(),
2091 })
2092 .await
2093 .into_response()?
2094 } else {
2095 None
2096 };
2097
2098 if let Some(lsp_edits) = lsp_edits {
2099 this.update(cx, |this, cx| {
2100 this.as_local_mut().unwrap().edits_from_lsp(
2101 buffer,
2102 lsp_edits,
2103 language_server.server_id(),
2104 None,
2105 cx,
2106 )
2107 })?
2108 .await
2109 } else {
2110 Ok(Vec::with_capacity(0))
2111 }
2112 }
2113
2114 async fn format_via_external_command(
2115 buffer: &FormattableBuffer,
2116 command: &str,
2117 arguments: Option<&[String]>,
2118 cx: &mut AsyncApp,
2119 ) -> Result<Option<Diff>> {
2120 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2121 let file = File::from_dyn(buffer.file())?;
2122 let worktree = file.worktree.read(cx);
2123 let mut worktree_path = worktree.abs_path().to_path_buf();
2124 if worktree.root_entry()?.is_file() {
2125 worktree_path.pop();
2126 }
2127 Some(worktree_path)
2128 })?;
2129
2130 let mut child = util::command::new_smol_command(command);
2131
2132 if let Some(buffer_env) = buffer.env.as_ref() {
2133 child.envs(buffer_env);
2134 }
2135
2136 if let Some(working_dir_path) = working_dir_path {
2137 child.current_dir(working_dir_path);
2138 }
2139
2140 if let Some(arguments) = arguments {
2141 child.args(arguments.iter().map(|arg| {
2142 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2143 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2144 } else {
2145 arg.replace("{buffer_path}", "Untitled")
2146 }
2147 }));
2148 }
2149
2150 let mut child = child
2151 .stdin(smol::process::Stdio::piped())
2152 .stdout(smol::process::Stdio::piped())
2153 .stderr(smol::process::Stdio::piped())
2154 .spawn()?;
2155
2156 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2157 let text = buffer
2158 .handle
2159 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2160 for chunk in text.chunks() {
2161 stdin.write_all(chunk.as_bytes()).await?;
2162 }
2163 stdin.flush().await?;
2164
2165 let output = child.output().await?;
2166 anyhow::ensure!(
2167 output.status.success(),
2168 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2169 output.status.code(),
2170 String::from_utf8_lossy(&output.stdout),
2171 String::from_utf8_lossy(&output.stderr),
2172 );
2173
2174 let stdout = String::from_utf8(output.stdout)?;
2175 Ok(Some(
2176 buffer
2177 .handle
2178 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2179 .await,
2180 ))
2181 }
2182
2183 async fn try_resolve_code_action(
2184 lang_server: &LanguageServer,
2185 action: &mut CodeAction,
2186 ) -> anyhow::Result<()> {
2187 match &mut action.lsp_action {
2188 LspAction::Action(lsp_action) => {
2189 if !action.resolved
2190 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2191 && lsp_action.data.is_some()
2192 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2193 {
2194 *lsp_action = Box::new(
2195 lang_server
2196 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2197 .await
2198 .into_response()?,
2199 );
2200 }
2201 }
2202 LspAction::CodeLens(lens) => {
2203 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2204 *lens = lang_server
2205 .request::<lsp::request::CodeLensResolve>(lens.clone())
2206 .await
2207 .into_response()?;
2208 }
2209 }
2210 LspAction::Command(_) => {}
2211 }
2212
2213 action.resolved = true;
2214 anyhow::Ok(())
2215 }
2216
2217 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2218 let buffer = buffer_handle.read(cx);
2219
2220 let file = buffer.file().cloned();
2221
2222 let Some(file) = File::from_dyn(file.as_ref()) else {
2223 return;
2224 };
2225 if !file.is_local() {
2226 return;
2227 }
2228 let path = ProjectPath::from_file(file, cx);
2229 let worktree_id = file.worktree_id(cx);
2230 let language = buffer.language().cloned();
2231
2232 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2233 for (server_id, diagnostics) in
2234 diagnostics.get(file.path()).cloned().unwrap_or_default()
2235 {
2236 self.update_buffer_diagnostics(
2237 buffer_handle,
2238 server_id,
2239 None,
2240 None,
2241 diagnostics,
2242 Vec::new(),
2243 cx,
2244 )
2245 .log_err();
2246 }
2247 }
2248 let Some(language) = language else {
2249 return;
2250 };
2251 let Some(snapshot) = self
2252 .worktree_store
2253 .read(cx)
2254 .worktree_for_id(worktree_id, cx)
2255 .map(|worktree| worktree.read(cx).snapshot())
2256 else {
2257 return;
2258 };
2259 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2260
2261 for server_id in
2262 self.lsp_tree
2263 .get(path, language.name(), language.manifest(), &delegate, cx)
2264 {
2265 let server = self
2266 .language_servers
2267 .get(&server_id)
2268 .and_then(|server_state| {
2269 if let LanguageServerState::Running { server, .. } = server_state {
2270 Some(server.clone())
2271 } else {
2272 None
2273 }
2274 });
2275 let server = match server {
2276 Some(server) => server,
2277 None => continue,
2278 };
2279
2280 buffer_handle.update(cx, |buffer, cx| {
2281 buffer.set_completion_triggers(
2282 server.server_id(),
2283 server
2284 .capabilities()
2285 .completion_provider
2286 .as_ref()
2287 .and_then(|provider| {
2288 provider
2289 .trigger_characters
2290 .as_ref()
2291 .map(|characters| characters.iter().cloned().collect())
2292 })
2293 .unwrap_or_default(),
2294 cx,
2295 );
2296 });
2297 }
2298 }
2299
2300 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2301 buffer.update(cx, |buffer, cx| {
2302 let Some(language) = buffer.language() else {
2303 return;
2304 };
2305 let path = ProjectPath {
2306 worktree_id: old_file.worktree_id(cx),
2307 path: old_file.path.clone(),
2308 };
2309 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2310 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2311 buffer.set_completion_triggers(server_id, Default::default(), cx);
2312 }
2313 });
2314 }
2315
2316 fn update_buffer_diagnostics(
2317 &mut self,
2318 buffer: &Entity<Buffer>,
2319 server_id: LanguageServerId,
2320 result_id: Option<String>,
2321 version: Option<i32>,
2322 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2323 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2324 cx: &mut Context<LspStore>,
2325 ) -> Result<()> {
2326 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2327 Ordering::Equal
2328 .then_with(|| b.is_primary.cmp(&a.is_primary))
2329 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2330 .then_with(|| a.severity.cmp(&b.severity))
2331 .then_with(|| a.message.cmp(&b.message))
2332 }
2333
2334 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2335 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2336 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2337
2338 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2339 Ordering::Equal
2340 .then_with(|| a.range.start.cmp(&b.range.start))
2341 .then_with(|| b.range.end.cmp(&a.range.end))
2342 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2343 });
2344
2345 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2346
2347 let edits_since_save = std::cell::LazyCell::new(|| {
2348 let saved_version = buffer.read(cx).saved_version();
2349 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2350 });
2351
2352 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2353
2354 for (new_diagnostic, entry) in diagnostics {
2355 let start;
2356 let end;
2357 if new_diagnostic && entry.diagnostic.is_disk_based {
2358 // Some diagnostics are based on files on disk instead of buffers'
2359 // current contents. Adjust these diagnostics' ranges to reflect
2360 // any unsaved edits.
2361 // Do not alter the reused ones though, as their coordinates were stored as anchors
2362 // and were properly adjusted on reuse.
2363 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2364 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2365 } else {
2366 start = entry.range.start;
2367 end = entry.range.end;
2368 }
2369
2370 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2371 ..snapshot.clip_point_utf16(end, Bias::Right);
2372
2373 // Expand empty ranges by one codepoint
2374 if range.start == range.end {
2375 // This will be go to the next boundary when being clipped
2376 range.end.column += 1;
2377 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2378 if range.start == range.end && range.end.column > 0 {
2379 range.start.column -= 1;
2380 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2381 }
2382 }
2383
2384 sanitized_diagnostics.push(DiagnosticEntry {
2385 range,
2386 diagnostic: entry.diagnostic,
2387 });
2388 }
2389 drop(edits_since_save);
2390
2391 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2392 buffer.update(cx, |buffer, cx| {
2393 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2394 self.buffer_pull_diagnostics_result_ids
2395 .entry(server_id)
2396 .or_default()
2397 .insert(abs_path, result_id);
2398 }
2399
2400 buffer.update_diagnostics(server_id, set, cx)
2401 });
2402
2403 Ok(())
2404 }
2405
2406 fn register_language_server_for_invisible_worktree(
2407 &mut self,
2408 worktree: &Entity<Worktree>,
2409 language_server_id: LanguageServerId,
2410 cx: &mut App,
2411 ) {
2412 let worktree = worktree.read(cx);
2413 let worktree_id = worktree.id();
2414 debug_assert!(!worktree.is_visible());
2415 let Some(mut origin_seed) = self
2416 .language_server_ids
2417 .iter()
2418 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2419 else {
2420 return;
2421 };
2422 origin_seed.worktree_id = worktree_id;
2423 self.language_server_ids
2424 .entry(origin_seed)
2425 .or_insert_with(|| UnifiedLanguageServer {
2426 id: language_server_id,
2427 project_roots: Default::default(),
2428 });
2429 }
2430
2431 fn register_buffer_with_language_servers(
2432 &mut self,
2433 buffer_handle: &Entity<Buffer>,
2434 only_register_servers: HashSet<LanguageServerSelector>,
2435 cx: &mut Context<LspStore>,
2436 ) {
2437 let buffer = buffer_handle.read(cx);
2438 let buffer_id = buffer.remote_id();
2439
2440 let Some(file) = File::from_dyn(buffer.file()) else {
2441 return;
2442 };
2443 if !file.is_local() {
2444 return;
2445 }
2446
2447 let abs_path = file.abs_path(cx);
2448 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2449 return;
2450 };
2451 let initial_snapshot = buffer.text_snapshot();
2452 let worktree_id = file.worktree_id(cx);
2453
2454 let Some(language) = buffer.language().cloned() else {
2455 return;
2456 };
2457 let path: Arc<RelPath> = file
2458 .path()
2459 .parent()
2460 .map(Arc::from)
2461 .unwrap_or_else(|| file.path().clone());
2462 let Some(worktree) = self
2463 .worktree_store
2464 .read(cx)
2465 .worktree_for_id(worktree_id, cx)
2466 else {
2467 return;
2468 };
2469 let language_name = language.name();
2470 let (reused, delegate, servers) = self
2471 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2472 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2473 .unwrap_or_else(|| {
2474 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2475 let delegate: Arc<dyn ManifestDelegate> =
2476 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2477
2478 let servers = self
2479 .lsp_tree
2480 .walk(
2481 ProjectPath { worktree_id, path },
2482 language.name(),
2483 language.manifest(),
2484 &delegate,
2485 cx,
2486 )
2487 .collect::<Vec<_>>();
2488 (false, lsp_delegate, servers)
2489 });
2490 let servers_and_adapters = servers
2491 .into_iter()
2492 .filter_map(|server_node| {
2493 if reused && server_node.server_id().is_none() {
2494 return None;
2495 }
2496 if !only_register_servers.is_empty() {
2497 if let Some(server_id) = server_node.server_id()
2498 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2499 {
2500 return None;
2501 }
2502 if let Some(name) = server_node.name()
2503 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2504 {
2505 return None;
2506 }
2507 }
2508
2509 let server_id = server_node.server_id_or_init(|disposition| {
2510 let path = &disposition.path;
2511
2512 {
2513 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2514
2515 let server_id = self.get_or_insert_language_server(
2516 &worktree,
2517 delegate.clone(),
2518 disposition,
2519 &language_name,
2520 cx,
2521 );
2522
2523 if let Some(state) = self.language_servers.get(&server_id)
2524 && let Ok(uri) = uri
2525 {
2526 state.add_workspace_folder(uri);
2527 };
2528 server_id
2529 }
2530 })?;
2531 let server_state = self.language_servers.get(&server_id)?;
2532 if let LanguageServerState::Running {
2533 server, adapter, ..
2534 } = server_state
2535 {
2536 Some((server.clone(), adapter.clone()))
2537 } else {
2538 None
2539 }
2540 })
2541 .collect::<Vec<_>>();
2542 for (server, adapter) in servers_and_adapters {
2543 buffer_handle.update(cx, |buffer, cx| {
2544 buffer.set_completion_triggers(
2545 server.server_id(),
2546 server
2547 .capabilities()
2548 .completion_provider
2549 .as_ref()
2550 .and_then(|provider| {
2551 provider
2552 .trigger_characters
2553 .as_ref()
2554 .map(|characters| characters.iter().cloned().collect())
2555 })
2556 .unwrap_or_default(),
2557 cx,
2558 );
2559 });
2560
2561 let snapshot = LspBufferSnapshot {
2562 version: 0,
2563 snapshot: initial_snapshot.clone(),
2564 };
2565
2566 let mut registered = false;
2567 self.buffer_snapshots
2568 .entry(buffer_id)
2569 .or_default()
2570 .entry(server.server_id())
2571 .or_insert_with(|| {
2572 registered = true;
2573 server.register_buffer(
2574 uri.clone(),
2575 adapter.language_id(&language.name()),
2576 0,
2577 initial_snapshot.text(),
2578 );
2579
2580 vec![snapshot]
2581 });
2582
2583 self.buffers_opened_in_servers
2584 .entry(buffer_id)
2585 .or_default()
2586 .insert(server.server_id());
2587 if registered {
2588 cx.emit(LspStoreEvent::LanguageServerUpdate {
2589 language_server_id: server.server_id(),
2590 name: None,
2591 message: proto::update_language_server::Variant::RegisteredForBuffer(
2592 proto::RegisteredForBuffer {
2593 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2594 buffer_id: buffer_id.to_proto(),
2595 },
2596 ),
2597 });
2598 }
2599 }
2600 }
2601
2602 fn reuse_existing_language_server<'lang_name>(
2603 &self,
2604 server_tree: &LanguageServerTree,
2605 worktree: &Entity<Worktree>,
2606 language_name: &'lang_name LanguageName,
2607 cx: &mut App,
2608 ) -> Option<(
2609 Arc<LocalLspAdapterDelegate>,
2610 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2611 )> {
2612 if worktree.read(cx).is_visible() {
2613 return None;
2614 }
2615
2616 let worktree_store = self.worktree_store.read(cx);
2617 let servers = server_tree
2618 .instances
2619 .iter()
2620 .filter(|(worktree_id, _)| {
2621 worktree_store
2622 .worktree_for_id(**worktree_id, cx)
2623 .is_some_and(|worktree| worktree.read(cx).is_visible())
2624 })
2625 .flat_map(|(worktree_id, servers)| {
2626 servers
2627 .roots
2628 .iter()
2629 .flat_map(|(_, language_servers)| language_servers)
2630 .map(move |(_, (server_node, server_languages))| {
2631 (worktree_id, server_node, server_languages)
2632 })
2633 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2634 .map(|(worktree_id, server_node, _)| {
2635 (
2636 *worktree_id,
2637 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2638 )
2639 })
2640 })
2641 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2642 acc.entry(worktree_id)
2643 .or_insert_with(Vec::new)
2644 .push(server_node);
2645 acc
2646 })
2647 .into_values()
2648 .max_by_key(|servers| servers.len())?;
2649
2650 let worktree_id = worktree.read(cx).id();
2651 let apply = move |tree: &mut LanguageServerTree| {
2652 for server_node in &servers {
2653 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2654 }
2655 servers
2656 };
2657
2658 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2659 Some((delegate, apply))
2660 }
2661
2662 pub(crate) fn unregister_old_buffer_from_language_servers(
2663 &mut self,
2664 buffer: &Entity<Buffer>,
2665 old_file: &File,
2666 cx: &mut App,
2667 ) {
2668 let old_path = match old_file.as_local() {
2669 Some(local) => local.abs_path(cx),
2670 None => return,
2671 };
2672
2673 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2674 debug_panic!("{old_path:?} is not parseable as an URI");
2675 return;
2676 };
2677 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2678 }
2679
2680 pub(crate) fn unregister_buffer_from_language_servers(
2681 &mut self,
2682 buffer: &Entity<Buffer>,
2683 file_url: &lsp::Uri,
2684 cx: &mut App,
2685 ) {
2686 buffer.update(cx, |buffer, cx| {
2687 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2688
2689 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2690 if snapshots
2691 .as_mut()
2692 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2693 {
2694 language_server.unregister_buffer(file_url.clone());
2695 }
2696 }
2697 });
2698 }
2699
2700 fn buffer_snapshot_for_lsp_version(
2701 &mut self,
2702 buffer: &Entity<Buffer>,
2703 server_id: LanguageServerId,
2704 version: Option<i32>,
2705 cx: &App,
2706 ) -> Result<TextBufferSnapshot> {
2707 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2708
2709 if let Some(version) = version {
2710 let buffer_id = buffer.read(cx).remote_id();
2711 let snapshots = if let Some(snapshots) = self
2712 .buffer_snapshots
2713 .get_mut(&buffer_id)
2714 .and_then(|m| m.get_mut(&server_id))
2715 {
2716 snapshots
2717 } else if version == 0 {
2718 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2719 // We detect this case and treat it as if the version was `None`.
2720 return Ok(buffer.read(cx).text_snapshot());
2721 } else {
2722 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2723 };
2724
2725 let found_snapshot = snapshots
2726 .binary_search_by_key(&version, |e| e.version)
2727 .map(|ix| snapshots[ix].snapshot.clone())
2728 .map_err(|_| {
2729 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2730 })?;
2731
2732 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2733 Ok(found_snapshot)
2734 } else {
2735 Ok((buffer.read(cx)).text_snapshot())
2736 }
2737 }
2738
2739 async fn get_server_code_actions_from_action_kinds(
2740 lsp_store: &WeakEntity<LspStore>,
2741 language_server_id: LanguageServerId,
2742 code_action_kinds: Vec<lsp::CodeActionKind>,
2743 buffer: &Entity<Buffer>,
2744 cx: &mut AsyncApp,
2745 ) -> Result<Vec<CodeAction>> {
2746 let actions = lsp_store
2747 .update(cx, move |this, cx| {
2748 let request = GetCodeActions {
2749 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2750 kinds: Some(code_action_kinds),
2751 };
2752 let server = LanguageServerToQuery::Other(language_server_id);
2753 this.request_lsp(buffer.clone(), server, request, cx)
2754 })?
2755 .await?;
2756 Ok(actions)
2757 }
2758
2759 pub async fn execute_code_actions_on_server(
2760 lsp_store: &WeakEntity<LspStore>,
2761 language_server: &Arc<LanguageServer>,
2762
2763 actions: Vec<CodeAction>,
2764 push_to_history: bool,
2765 project_transaction: &mut ProjectTransaction,
2766 cx: &mut AsyncApp,
2767 ) -> anyhow::Result<()> {
2768 for mut action in actions {
2769 Self::try_resolve_code_action(language_server, &mut action)
2770 .await
2771 .context("resolving a formatting code action")?;
2772
2773 if let Some(edit) = action.lsp_action.edit() {
2774 if edit.changes.is_none() && edit.document_changes.is_none() {
2775 continue;
2776 }
2777
2778 let new = Self::deserialize_workspace_edit(
2779 lsp_store.upgrade().context("project dropped")?,
2780 edit.clone(),
2781 push_to_history,
2782 language_server.clone(),
2783 cx,
2784 )
2785 .await?;
2786 project_transaction.0.extend(new.0);
2787 }
2788
2789 if let Some(command) = action.lsp_action.command() {
2790 let server_capabilities = language_server.capabilities();
2791 let available_commands = server_capabilities
2792 .execute_command_provider
2793 .as_ref()
2794 .map(|options| options.commands.as_slice())
2795 .unwrap_or_default();
2796 if available_commands.contains(&command.command) {
2797 lsp_store.update(cx, |lsp_store, _| {
2798 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2799 mode.last_workspace_edits_by_language_server
2800 .remove(&language_server.server_id());
2801 }
2802 })?;
2803
2804 language_server
2805 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2806 command: command.command.clone(),
2807 arguments: command.arguments.clone().unwrap_or_default(),
2808 ..Default::default()
2809 })
2810 .await
2811 .into_response()
2812 .context("execute command")?;
2813
2814 lsp_store.update(cx, |this, _| {
2815 if let LspStoreMode::Local(mode) = &mut this.mode {
2816 project_transaction.0.extend(
2817 mode.last_workspace_edits_by_language_server
2818 .remove(&language_server.server_id())
2819 .unwrap_or_default()
2820 .0,
2821 )
2822 }
2823 })?;
2824 } else {
2825 log::warn!(
2826 "Cannot execute a command {} not listed in the language server capabilities",
2827 command.command
2828 )
2829 }
2830 }
2831 }
2832 Ok(())
2833 }
2834
2835 pub async fn deserialize_text_edits(
2836 this: Entity<LspStore>,
2837 buffer_to_edit: Entity<Buffer>,
2838 edits: Vec<lsp::TextEdit>,
2839 push_to_history: bool,
2840 _: Arc<CachedLspAdapter>,
2841 language_server: Arc<LanguageServer>,
2842 cx: &mut AsyncApp,
2843 ) -> Result<Option<Transaction>> {
2844 let edits = this
2845 .update(cx, |this, cx| {
2846 this.as_local_mut().unwrap().edits_from_lsp(
2847 &buffer_to_edit,
2848 edits,
2849 language_server.server_id(),
2850 None,
2851 cx,
2852 )
2853 })?
2854 .await?;
2855
2856 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2857 buffer.finalize_last_transaction();
2858 buffer.start_transaction();
2859 for (range, text) in edits {
2860 buffer.edit([(range, text)], None, cx);
2861 }
2862
2863 if buffer.end_transaction(cx).is_some() {
2864 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2865 if !push_to_history {
2866 buffer.forget_transaction(transaction.id);
2867 }
2868 Some(transaction)
2869 } else {
2870 None
2871 }
2872 })?;
2873
2874 Ok(transaction)
2875 }
2876
2877 #[allow(clippy::type_complexity)]
2878 pub(crate) fn edits_from_lsp(
2879 &mut self,
2880 buffer: &Entity<Buffer>,
2881 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2882 server_id: LanguageServerId,
2883 version: Option<i32>,
2884 cx: &mut Context<LspStore>,
2885 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2886 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2887 cx.background_spawn(async move {
2888 let snapshot = snapshot?;
2889 let mut lsp_edits = lsp_edits
2890 .into_iter()
2891 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2892 .collect::<Vec<_>>();
2893
2894 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2895
2896 let mut lsp_edits = lsp_edits.into_iter().peekable();
2897 let mut edits = Vec::new();
2898 while let Some((range, mut new_text)) = lsp_edits.next() {
2899 // Clip invalid ranges provided by the language server.
2900 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2901 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2902
2903 // Combine any LSP edits that are adjacent.
2904 //
2905 // Also, combine LSP edits that are separated from each other by only
2906 // a newline. This is important because for some code actions,
2907 // Rust-analyzer rewrites the entire buffer via a series of edits that
2908 // are separated by unchanged newline characters.
2909 //
2910 // In order for the diffing logic below to work properly, any edits that
2911 // cancel each other out must be combined into one.
2912 while let Some((next_range, next_text)) = lsp_edits.peek() {
2913 if next_range.start.0 > range.end {
2914 if next_range.start.0.row > range.end.row + 1
2915 || next_range.start.0.column > 0
2916 || snapshot.clip_point_utf16(
2917 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2918 Bias::Left,
2919 ) > range.end
2920 {
2921 break;
2922 }
2923 new_text.push('\n');
2924 }
2925 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2926 new_text.push_str(next_text);
2927 lsp_edits.next();
2928 }
2929
2930 // For multiline edits, perform a diff of the old and new text so that
2931 // we can identify the changes more precisely, preserving the locations
2932 // of any anchors positioned in the unchanged regions.
2933 if range.end.row > range.start.row {
2934 let offset = range.start.to_offset(&snapshot);
2935 let old_text = snapshot.text_for_range(range).collect::<String>();
2936 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2937 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2938 (
2939 snapshot.anchor_after(offset + range.start)
2940 ..snapshot.anchor_before(offset + range.end),
2941 replacement,
2942 )
2943 }));
2944 } else if range.end == range.start {
2945 let anchor = snapshot.anchor_after(range.start);
2946 edits.push((anchor..anchor, new_text.into()));
2947 } else {
2948 let edit_start = snapshot.anchor_after(range.start);
2949 let edit_end = snapshot.anchor_before(range.end);
2950 edits.push((edit_start..edit_end, new_text.into()));
2951 }
2952 }
2953
2954 Ok(edits)
2955 })
2956 }
2957
2958 pub(crate) async fn deserialize_workspace_edit(
2959 this: Entity<LspStore>,
2960 edit: lsp::WorkspaceEdit,
2961 push_to_history: bool,
2962 language_server: Arc<LanguageServer>,
2963 cx: &mut AsyncApp,
2964 ) -> Result<ProjectTransaction> {
2965 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2966
2967 let mut operations = Vec::new();
2968 if let Some(document_changes) = edit.document_changes {
2969 match document_changes {
2970 lsp::DocumentChanges::Edits(edits) => {
2971 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2972 }
2973 lsp::DocumentChanges::Operations(ops) => operations = ops,
2974 }
2975 } else if let Some(changes) = edit.changes {
2976 operations.extend(changes.into_iter().map(|(uri, edits)| {
2977 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2978 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2979 uri,
2980 version: None,
2981 },
2982 edits: edits.into_iter().map(Edit::Plain).collect(),
2983 })
2984 }));
2985 }
2986
2987 let mut project_transaction = ProjectTransaction::default();
2988 for operation in operations {
2989 match operation {
2990 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2991 let abs_path = op
2992 .uri
2993 .to_file_path()
2994 .map_err(|()| anyhow!("can't convert URI to path"))?;
2995
2996 if let Some(parent_path) = abs_path.parent() {
2997 fs.create_dir(parent_path).await?;
2998 }
2999 if abs_path.ends_with("/") {
3000 fs.create_dir(&abs_path).await?;
3001 } else {
3002 fs.create_file(
3003 &abs_path,
3004 op.options
3005 .map(|options| fs::CreateOptions {
3006 overwrite: options.overwrite.unwrap_or(false),
3007 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3008 })
3009 .unwrap_or_default(),
3010 )
3011 .await?;
3012 }
3013 }
3014
3015 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3016 let source_abs_path = op
3017 .old_uri
3018 .to_file_path()
3019 .map_err(|()| anyhow!("can't convert URI to path"))?;
3020 let target_abs_path = op
3021 .new_uri
3022 .to_file_path()
3023 .map_err(|()| anyhow!("can't convert URI to path"))?;
3024
3025 let options = fs::RenameOptions {
3026 overwrite: op
3027 .options
3028 .as_ref()
3029 .and_then(|options| options.overwrite)
3030 .unwrap_or(false),
3031 ignore_if_exists: op
3032 .options
3033 .as_ref()
3034 .and_then(|options| options.ignore_if_exists)
3035 .unwrap_or(false),
3036 create_parents: true,
3037 };
3038
3039 fs.rename(&source_abs_path, &target_abs_path, options)
3040 .await?;
3041 }
3042
3043 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3044 let abs_path = op
3045 .uri
3046 .to_file_path()
3047 .map_err(|()| anyhow!("can't convert URI to path"))?;
3048 let options = op
3049 .options
3050 .map(|options| fs::RemoveOptions {
3051 recursive: options.recursive.unwrap_or(false),
3052 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3053 })
3054 .unwrap_or_default();
3055 if abs_path.ends_with("/") {
3056 fs.remove_dir(&abs_path, options).await?;
3057 } else {
3058 fs.remove_file(&abs_path, options).await?;
3059 }
3060 }
3061
3062 lsp::DocumentChangeOperation::Edit(op) => {
3063 let buffer_to_edit = this
3064 .update(cx, |this, cx| {
3065 this.open_local_buffer_via_lsp(
3066 op.text_document.uri.clone(),
3067 language_server.server_id(),
3068 cx,
3069 )
3070 })?
3071 .await?;
3072
3073 let edits = this
3074 .update(cx, |this, cx| {
3075 let path = buffer_to_edit.read(cx).project_path(cx);
3076 let active_entry = this.active_entry;
3077 let is_active_entry = path.is_some_and(|project_path| {
3078 this.worktree_store
3079 .read(cx)
3080 .entry_for_path(&project_path, cx)
3081 .is_some_and(|entry| Some(entry.id) == active_entry)
3082 });
3083 let local = this.as_local_mut().unwrap();
3084
3085 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3086 for edit in op.edits {
3087 match edit {
3088 Edit::Plain(edit) => {
3089 if !edits.contains(&edit) {
3090 edits.push(edit)
3091 }
3092 }
3093 Edit::Annotated(edit) => {
3094 if !edits.contains(&edit.text_edit) {
3095 edits.push(edit.text_edit)
3096 }
3097 }
3098 Edit::Snippet(edit) => {
3099 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3100 else {
3101 continue;
3102 };
3103
3104 if is_active_entry {
3105 snippet_edits.push((edit.range, snippet));
3106 } else {
3107 // Since this buffer is not focused, apply a normal edit.
3108 let new_edit = TextEdit {
3109 range: edit.range,
3110 new_text: snippet.text,
3111 };
3112 if !edits.contains(&new_edit) {
3113 edits.push(new_edit);
3114 }
3115 }
3116 }
3117 }
3118 }
3119 if !snippet_edits.is_empty() {
3120 let buffer_id = buffer_to_edit.read(cx).remote_id();
3121 let version = if let Some(buffer_version) = op.text_document.version
3122 {
3123 local
3124 .buffer_snapshot_for_lsp_version(
3125 &buffer_to_edit,
3126 language_server.server_id(),
3127 Some(buffer_version),
3128 cx,
3129 )
3130 .ok()
3131 .map(|snapshot| snapshot.version)
3132 } else {
3133 Some(buffer_to_edit.read(cx).saved_version().clone())
3134 };
3135
3136 let most_recent_edit =
3137 version.and_then(|version| version.most_recent());
3138 // Check if the edit that triggered that edit has been made by this participant.
3139
3140 if let Some(most_recent_edit) = most_recent_edit {
3141 cx.emit(LspStoreEvent::SnippetEdit {
3142 buffer_id,
3143 edits: snippet_edits,
3144 most_recent_edit,
3145 });
3146 }
3147 }
3148
3149 local.edits_from_lsp(
3150 &buffer_to_edit,
3151 edits,
3152 language_server.server_id(),
3153 op.text_document.version,
3154 cx,
3155 )
3156 })?
3157 .await?;
3158
3159 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3160 buffer.finalize_last_transaction();
3161 buffer.start_transaction();
3162 for (range, text) in edits {
3163 buffer.edit([(range, text)], None, cx);
3164 }
3165
3166 buffer.end_transaction(cx).and_then(|transaction_id| {
3167 if push_to_history {
3168 buffer.finalize_last_transaction();
3169 buffer.get_transaction(transaction_id).cloned()
3170 } else {
3171 buffer.forget_transaction(transaction_id)
3172 }
3173 })
3174 })?;
3175 if let Some(transaction) = transaction {
3176 project_transaction.0.insert(buffer_to_edit, transaction);
3177 }
3178 }
3179 }
3180 }
3181
3182 Ok(project_transaction)
3183 }
3184
3185 async fn on_lsp_workspace_edit(
3186 this: WeakEntity<LspStore>,
3187 params: lsp::ApplyWorkspaceEditParams,
3188 server_id: LanguageServerId,
3189 cx: &mut AsyncApp,
3190 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3191 let this = this.upgrade().context("project project closed")?;
3192 let language_server = this
3193 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3194 .context("language server not found")?;
3195 let transaction = Self::deserialize_workspace_edit(
3196 this.clone(),
3197 params.edit,
3198 true,
3199 language_server.clone(),
3200 cx,
3201 )
3202 .await
3203 .log_err();
3204 this.update(cx, |this, _| {
3205 if let Some(transaction) = transaction {
3206 this.as_local_mut()
3207 .unwrap()
3208 .last_workspace_edits_by_language_server
3209 .insert(server_id, transaction);
3210 }
3211 })?;
3212 Ok(lsp::ApplyWorkspaceEditResponse {
3213 applied: true,
3214 failed_change: None,
3215 failure_reason: None,
3216 })
3217 }
3218
3219 fn remove_worktree(
3220 &mut self,
3221 id_to_remove: WorktreeId,
3222 cx: &mut Context<LspStore>,
3223 ) -> Vec<LanguageServerId> {
3224 self.diagnostics.remove(&id_to_remove);
3225 self.prettier_store.update(cx, |prettier_store, cx| {
3226 prettier_store.remove_worktree(id_to_remove, cx);
3227 });
3228
3229 let mut servers_to_remove = BTreeSet::default();
3230 let mut servers_to_preserve = HashSet::default();
3231 for (seed, state) in &self.language_server_ids {
3232 if seed.worktree_id == id_to_remove {
3233 servers_to_remove.insert(state.id);
3234 } else {
3235 servers_to_preserve.insert(state.id);
3236 }
3237 }
3238 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3239 self.language_server_ids
3240 .retain(|_, state| !servers_to_remove.contains(&state.id));
3241 for server_id_to_remove in &servers_to_remove {
3242 self.language_server_watched_paths
3243 .remove(server_id_to_remove);
3244 self.language_server_paths_watched_for_rename
3245 .remove(server_id_to_remove);
3246 self.last_workspace_edits_by_language_server
3247 .remove(server_id_to_remove);
3248 self.language_servers.remove(server_id_to_remove);
3249 self.buffer_pull_diagnostics_result_ids
3250 .remove(server_id_to_remove);
3251 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3252 buffer_servers.remove(server_id_to_remove);
3253 }
3254 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3255 }
3256 servers_to_remove.into_iter().collect()
3257 }
3258
3259 fn rebuild_watched_paths_inner<'a>(
3260 &'a self,
3261 language_server_id: LanguageServerId,
3262 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3263 cx: &mut Context<LspStore>,
3264 ) -> LanguageServerWatchedPathsBuilder {
3265 let worktrees = self
3266 .worktree_store
3267 .read(cx)
3268 .worktrees()
3269 .filter_map(|worktree| {
3270 self.language_servers_for_worktree(worktree.read(cx).id())
3271 .find(|server| server.server_id() == language_server_id)
3272 .map(|_| worktree)
3273 })
3274 .collect::<Vec<_>>();
3275
3276 let mut worktree_globs = HashMap::default();
3277 let mut abs_globs = HashMap::default();
3278 log::trace!(
3279 "Processing new watcher paths for language server with id {}",
3280 language_server_id
3281 );
3282
3283 for watcher in watchers {
3284 if let Some((worktree, literal_prefix, pattern)) =
3285 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3286 {
3287 worktree.update(cx, |worktree, _| {
3288 if let Some((tree, glob)) =
3289 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3290 {
3291 tree.add_path_prefix_to_scan(literal_prefix);
3292 worktree_globs
3293 .entry(tree.id())
3294 .or_insert_with(GlobSetBuilder::new)
3295 .add(glob);
3296 }
3297 });
3298 } else {
3299 let (path, pattern) = match &watcher.glob_pattern {
3300 lsp::GlobPattern::String(s) => {
3301 let watcher_path = SanitizedPath::new(s);
3302 let path = glob_literal_prefix(watcher_path.as_path());
3303 let pattern = watcher_path
3304 .as_path()
3305 .strip_prefix(&path)
3306 .map(|p| p.to_string_lossy().into_owned())
3307 .unwrap_or_else(|e| {
3308 debug_panic!(
3309 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3310 s,
3311 path.display(),
3312 e
3313 );
3314 watcher_path.as_path().to_string_lossy().into_owned()
3315 });
3316 (path, pattern)
3317 }
3318 lsp::GlobPattern::Relative(rp) => {
3319 let Ok(mut base_uri) = match &rp.base_uri {
3320 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3321 lsp::OneOf::Right(base_uri) => base_uri,
3322 }
3323 .to_file_path() else {
3324 continue;
3325 };
3326
3327 let path = glob_literal_prefix(Path::new(&rp.pattern));
3328 let pattern = Path::new(&rp.pattern)
3329 .strip_prefix(&path)
3330 .map(|p| p.to_string_lossy().into_owned())
3331 .unwrap_or_else(|e| {
3332 debug_panic!(
3333 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3334 rp.pattern,
3335 path.display(),
3336 e
3337 );
3338 rp.pattern.clone()
3339 });
3340 base_uri.push(path);
3341 (base_uri, pattern)
3342 }
3343 };
3344
3345 if let Some(glob) = Glob::new(&pattern).log_err() {
3346 if !path
3347 .components()
3348 .any(|c| matches!(c, path::Component::Normal(_)))
3349 {
3350 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3351 // rather than adding a new watcher for `/`.
3352 for worktree in &worktrees {
3353 worktree_globs
3354 .entry(worktree.read(cx).id())
3355 .or_insert_with(GlobSetBuilder::new)
3356 .add(glob.clone());
3357 }
3358 } else {
3359 abs_globs
3360 .entry(path.into())
3361 .or_insert_with(GlobSetBuilder::new)
3362 .add(glob);
3363 }
3364 }
3365 }
3366 }
3367
3368 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3369 for (worktree_id, builder) in worktree_globs {
3370 if let Ok(globset) = builder.build() {
3371 watch_builder.watch_worktree(worktree_id, globset);
3372 }
3373 }
3374 for (abs_path, builder) in abs_globs {
3375 if let Ok(globset) = builder.build() {
3376 watch_builder.watch_abs_path(abs_path, globset);
3377 }
3378 }
3379 watch_builder
3380 }
3381
3382 fn worktree_and_path_for_file_watcher(
3383 worktrees: &[Entity<Worktree>],
3384 watcher: &FileSystemWatcher,
3385 cx: &App,
3386 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3387 worktrees.iter().find_map(|worktree| {
3388 let tree = worktree.read(cx);
3389 let worktree_root_path = tree.abs_path();
3390 let path_style = tree.path_style();
3391 match &watcher.glob_pattern {
3392 lsp::GlobPattern::String(s) => {
3393 let watcher_path = SanitizedPath::new(s);
3394 let relative = watcher_path
3395 .as_path()
3396 .strip_prefix(&worktree_root_path)
3397 .ok()?;
3398 let literal_prefix = glob_literal_prefix(relative);
3399 Some((
3400 worktree.clone(),
3401 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3402 relative.to_string_lossy().into_owned(),
3403 ))
3404 }
3405 lsp::GlobPattern::Relative(rp) => {
3406 let base_uri = match &rp.base_uri {
3407 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3408 lsp::OneOf::Right(base_uri) => base_uri,
3409 }
3410 .to_file_path()
3411 .ok()?;
3412 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3413 let mut literal_prefix = relative.to_owned();
3414 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3415 Some((
3416 worktree.clone(),
3417 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3418 rp.pattern.clone(),
3419 ))
3420 }
3421 }
3422 })
3423 }
3424
3425 fn rebuild_watched_paths(
3426 &mut self,
3427 language_server_id: LanguageServerId,
3428 cx: &mut Context<LspStore>,
3429 ) {
3430 let Some(registrations) = self
3431 .language_server_dynamic_registrations
3432 .get(&language_server_id)
3433 else {
3434 return;
3435 };
3436
3437 let watch_builder = self.rebuild_watched_paths_inner(
3438 language_server_id,
3439 registrations.did_change_watched_files.values().flatten(),
3440 cx,
3441 );
3442 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3443 self.language_server_watched_paths
3444 .insert(language_server_id, watcher);
3445
3446 cx.notify();
3447 }
3448
3449 fn on_lsp_did_change_watched_files(
3450 &mut self,
3451 language_server_id: LanguageServerId,
3452 registration_id: &str,
3453 params: DidChangeWatchedFilesRegistrationOptions,
3454 cx: &mut Context<LspStore>,
3455 ) {
3456 let registrations = self
3457 .language_server_dynamic_registrations
3458 .entry(language_server_id)
3459 .or_default();
3460
3461 registrations
3462 .did_change_watched_files
3463 .insert(registration_id.to_string(), params.watchers);
3464
3465 self.rebuild_watched_paths(language_server_id, cx);
3466 }
3467
3468 fn on_lsp_unregister_did_change_watched_files(
3469 &mut self,
3470 language_server_id: LanguageServerId,
3471 registration_id: &str,
3472 cx: &mut Context<LspStore>,
3473 ) {
3474 let registrations = self
3475 .language_server_dynamic_registrations
3476 .entry(language_server_id)
3477 .or_default();
3478
3479 if registrations
3480 .did_change_watched_files
3481 .remove(registration_id)
3482 .is_some()
3483 {
3484 log::info!(
3485 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3486 language_server_id,
3487 registration_id
3488 );
3489 } else {
3490 log::warn!(
3491 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3492 language_server_id,
3493 registration_id
3494 );
3495 }
3496
3497 self.rebuild_watched_paths(language_server_id, cx);
3498 }
3499
3500 async fn initialization_options_for_adapter(
3501 adapter: Arc<dyn LspAdapter>,
3502 delegate: &Arc<dyn LspAdapterDelegate>,
3503 ) -> Result<Option<serde_json::Value>> {
3504 let Some(mut initialization_config) =
3505 adapter.clone().initialization_options(delegate).await?
3506 else {
3507 return Ok(None);
3508 };
3509
3510 for other_adapter in delegate.registered_lsp_adapters() {
3511 if other_adapter.name() == adapter.name() {
3512 continue;
3513 }
3514 if let Ok(Some(target_config)) = other_adapter
3515 .clone()
3516 .additional_initialization_options(adapter.name(), delegate)
3517 .await
3518 {
3519 merge_json_value_into(target_config.clone(), &mut initialization_config);
3520 }
3521 }
3522
3523 Ok(Some(initialization_config))
3524 }
3525
3526 async fn workspace_configuration_for_adapter(
3527 adapter: Arc<dyn LspAdapter>,
3528 delegate: &Arc<dyn LspAdapterDelegate>,
3529 toolchain: Option<Toolchain>,
3530 cx: &mut AsyncApp,
3531 ) -> Result<serde_json::Value> {
3532 let mut workspace_config = adapter
3533 .clone()
3534 .workspace_configuration(delegate, toolchain, cx)
3535 .await?;
3536
3537 for other_adapter in delegate.registered_lsp_adapters() {
3538 if other_adapter.name() == adapter.name() {
3539 continue;
3540 }
3541 if let Ok(Some(target_config)) = other_adapter
3542 .clone()
3543 .additional_workspace_configuration(adapter.name(), delegate, cx)
3544 .await
3545 {
3546 merge_json_value_into(target_config.clone(), &mut workspace_config);
3547 }
3548 }
3549
3550 Ok(workspace_config)
3551 }
3552
3553 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3554 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3555 Some(server.clone())
3556 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3557 Some(Arc::clone(server))
3558 } else {
3559 None
3560 }
3561 }
3562}
3563
3564fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3565 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3566 cx.emit(LspStoreEvent::LanguageServerUpdate {
3567 language_server_id: server.server_id(),
3568 name: Some(server.name()),
3569 message: proto::update_language_server::Variant::MetadataUpdated(
3570 proto::ServerMetadataUpdated {
3571 capabilities: Some(capabilities),
3572 binary: Some(proto::LanguageServerBinaryInfo {
3573 path: server.binary().path.to_string_lossy().into_owned(),
3574 arguments: server
3575 .binary()
3576 .arguments
3577 .iter()
3578 .map(|arg| arg.to_string_lossy().into_owned())
3579 .collect(),
3580 }),
3581 configuration: serde_json::to_string(server.configuration()).ok(),
3582 workspace_folders: server
3583 .workspace_folders()
3584 .iter()
3585 .map(|uri| uri.to_string())
3586 .collect(),
3587 },
3588 ),
3589 });
3590 }
3591}
3592
3593#[derive(Debug)]
3594pub struct FormattableBuffer {
3595 handle: Entity<Buffer>,
3596 abs_path: Option<PathBuf>,
3597 env: Option<HashMap<String, String>>,
3598 ranges: Option<Vec<Range<Anchor>>>,
3599}
3600
3601pub struct RemoteLspStore {
3602 upstream_client: Option<AnyProtoClient>,
3603 upstream_project_id: u64,
3604}
3605
3606pub(crate) enum LspStoreMode {
3607 Local(LocalLspStore), // ssh host and collab host
3608 Remote(RemoteLspStore), // collab guest
3609}
3610
3611impl LspStoreMode {
3612 fn is_local(&self) -> bool {
3613 matches!(self, LspStoreMode::Local(_))
3614 }
3615}
3616
3617pub struct LspStore {
3618 mode: LspStoreMode,
3619 last_formatting_failure: Option<String>,
3620 downstream_client: Option<(AnyProtoClient, u64)>,
3621 nonce: u128,
3622 buffer_store: Entity<BufferStore>,
3623 worktree_store: Entity<WorktreeStore>,
3624 pub languages: Arc<LanguageRegistry>,
3625 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3626 active_entry: Option<ProjectEntryId>,
3627 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3628 _maintain_buffer_languages: Task<()>,
3629 diagnostic_summaries:
3630 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3631 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3632 lsp_data: HashMap<BufferId, BufferLspData>,
3633 next_hint_id: Arc<AtomicUsize>,
3634}
3635
3636#[derive(Debug)]
3637pub struct BufferLspData {
3638 buffer_version: Global,
3639 document_colors: Option<DocumentColorData>,
3640 code_lens: Option<CodeLensData>,
3641 inlay_hints: BufferInlayHints,
3642 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3643 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3644}
3645
3646#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3647struct LspKey {
3648 request_type: TypeId,
3649 server_queried: Option<LanguageServerId>,
3650}
3651
3652impl BufferLspData {
3653 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3654 Self {
3655 buffer_version: buffer.read(cx).version(),
3656 document_colors: None,
3657 code_lens: None,
3658 inlay_hints: BufferInlayHints::new(buffer, cx),
3659 lsp_requests: HashMap::default(),
3660 chunk_lsp_requests: HashMap::default(),
3661 }
3662 }
3663
3664 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3665 if let Some(document_colors) = &mut self.document_colors {
3666 document_colors.colors.remove(&for_server);
3667 document_colors.cache_version += 1;
3668 }
3669
3670 if let Some(code_lens) = &mut self.code_lens {
3671 code_lens.lens.remove(&for_server);
3672 }
3673
3674 self.inlay_hints.remove_server_data(for_server);
3675 }
3676
3677 #[cfg(any(test, feature = "test-support"))]
3678 pub fn inlay_hints(&self) -> &BufferInlayHints {
3679 &self.inlay_hints
3680 }
3681}
3682
3683#[derive(Debug, Default, Clone)]
3684pub struct DocumentColors {
3685 pub colors: HashSet<DocumentColor>,
3686 pub cache_version: Option<usize>,
3687}
3688
3689type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3690type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3691
3692#[derive(Debug, Default)]
3693struct DocumentColorData {
3694 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3695 cache_version: usize,
3696 colors_update: Option<(Global, DocumentColorTask)>,
3697}
3698
3699#[derive(Debug, Default)]
3700struct CodeLensData {
3701 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3702 update: Option<(Global, CodeLensTask)>,
3703}
3704
3705#[derive(Debug)]
3706pub enum LspStoreEvent {
3707 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3708 LanguageServerRemoved(LanguageServerId),
3709 LanguageServerUpdate {
3710 language_server_id: LanguageServerId,
3711 name: Option<LanguageServerName>,
3712 message: proto::update_language_server::Variant,
3713 },
3714 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3715 LanguageServerPrompt(LanguageServerPromptRequest),
3716 LanguageDetected {
3717 buffer: Entity<Buffer>,
3718 new_language: Option<Arc<Language>>,
3719 },
3720 Notification(String),
3721 RefreshInlayHints {
3722 server_id: LanguageServerId,
3723 request_id: Option<usize>,
3724 },
3725 RefreshCodeLens,
3726 DiagnosticsUpdated {
3727 server_id: LanguageServerId,
3728 paths: Vec<ProjectPath>,
3729 },
3730 DiskBasedDiagnosticsStarted {
3731 language_server_id: LanguageServerId,
3732 },
3733 DiskBasedDiagnosticsFinished {
3734 language_server_id: LanguageServerId,
3735 },
3736 SnippetEdit {
3737 buffer_id: BufferId,
3738 edits: Vec<(lsp::Range, Snippet)>,
3739 most_recent_edit: clock::Lamport,
3740 },
3741}
3742
3743#[derive(Clone, Debug, Serialize)]
3744pub struct LanguageServerStatus {
3745 pub name: LanguageServerName,
3746 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3747 pub has_pending_diagnostic_updates: bool,
3748 pub progress_tokens: HashSet<ProgressToken>,
3749 pub worktree: Option<WorktreeId>,
3750 pub binary: Option<LanguageServerBinary>,
3751 pub configuration: Option<Value>,
3752 pub workspace_folders: BTreeSet<Uri>,
3753}
3754
3755#[derive(Clone, Debug)]
3756struct CoreSymbol {
3757 pub language_server_name: LanguageServerName,
3758 pub source_worktree_id: WorktreeId,
3759 pub source_language_server_id: LanguageServerId,
3760 pub path: SymbolLocation,
3761 pub name: String,
3762 pub kind: lsp::SymbolKind,
3763 pub range: Range<Unclipped<PointUtf16>>,
3764}
3765
3766#[derive(Clone, Debug, PartialEq, Eq)]
3767pub enum SymbolLocation {
3768 InProject(ProjectPath),
3769 OutsideProject {
3770 abs_path: Arc<Path>,
3771 signature: [u8; 32],
3772 },
3773}
3774
3775impl SymbolLocation {
3776 fn file_name(&self) -> Option<&str> {
3777 match self {
3778 Self::InProject(path) => path.path.file_name(),
3779 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3780 }
3781 }
3782}
3783
3784impl LspStore {
3785 pub fn init(client: &AnyProtoClient) {
3786 client.add_entity_request_handler(Self::handle_lsp_query);
3787 client.add_entity_message_handler(Self::handle_lsp_query_response);
3788 client.add_entity_request_handler(Self::handle_restart_language_servers);
3789 client.add_entity_request_handler(Self::handle_stop_language_servers);
3790 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3791 client.add_entity_message_handler(Self::handle_start_language_server);
3792 client.add_entity_message_handler(Self::handle_update_language_server);
3793 client.add_entity_message_handler(Self::handle_language_server_log);
3794 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3795 client.add_entity_request_handler(Self::handle_format_buffers);
3796 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3797 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3798 client.add_entity_request_handler(Self::handle_apply_code_action);
3799 client.add_entity_request_handler(Self::handle_get_project_symbols);
3800 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3801 client.add_entity_request_handler(Self::handle_get_color_presentation);
3802 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3803 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3804 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3805 client.add_entity_request_handler(Self::handle_on_type_formatting);
3806 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3807 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3808 client.add_entity_request_handler(Self::handle_rename_project_entry);
3809 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3810 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3811 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3812 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3813 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3814 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3815 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3816
3817 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3818 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3819 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3820 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3821 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3822 client.add_entity_request_handler(
3823 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3824 );
3825 client.add_entity_request_handler(
3826 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3827 );
3828 client.add_entity_request_handler(
3829 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3830 );
3831 }
3832
3833 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3834 match &self.mode {
3835 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3836 _ => None,
3837 }
3838 }
3839
3840 pub fn as_local(&self) -> Option<&LocalLspStore> {
3841 match &self.mode {
3842 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3843 _ => None,
3844 }
3845 }
3846
3847 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3848 match &mut self.mode {
3849 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3850 _ => None,
3851 }
3852 }
3853
3854 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3855 match &self.mode {
3856 LspStoreMode::Remote(RemoteLspStore {
3857 upstream_client: Some(upstream_client),
3858 upstream_project_id,
3859 ..
3860 }) => Some((upstream_client.clone(), *upstream_project_id)),
3861
3862 LspStoreMode::Remote(RemoteLspStore {
3863 upstream_client: None,
3864 ..
3865 }) => None,
3866 LspStoreMode::Local(_) => None,
3867 }
3868 }
3869
3870 pub fn new_local(
3871 buffer_store: Entity<BufferStore>,
3872 worktree_store: Entity<WorktreeStore>,
3873 prettier_store: Entity<PrettierStore>,
3874 toolchain_store: Entity<LocalToolchainStore>,
3875 environment: Entity<ProjectEnvironment>,
3876 manifest_tree: Entity<ManifestTree>,
3877 languages: Arc<LanguageRegistry>,
3878 http_client: Arc<dyn HttpClient>,
3879 fs: Arc<dyn Fs>,
3880 cx: &mut Context<Self>,
3881 ) -> Self {
3882 let yarn = YarnPathStore::new(fs.clone(), cx);
3883 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3884 .detach();
3885 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3886 .detach();
3887 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3888 .detach();
3889 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3890 .detach();
3891 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3892 .detach();
3893 subscribe_to_binary_statuses(&languages, cx).detach();
3894
3895 let _maintain_workspace_config = {
3896 let (sender, receiver) = watch::channel();
3897 (Self::maintain_workspace_config(receiver, cx), sender)
3898 };
3899
3900 Self {
3901 mode: LspStoreMode::Local(LocalLspStore {
3902 weak: cx.weak_entity(),
3903 worktree_store: worktree_store.clone(),
3904
3905 supplementary_language_servers: Default::default(),
3906 languages: languages.clone(),
3907 language_server_ids: Default::default(),
3908 language_servers: Default::default(),
3909 last_workspace_edits_by_language_server: Default::default(),
3910 language_server_watched_paths: Default::default(),
3911 language_server_paths_watched_for_rename: Default::default(),
3912 language_server_dynamic_registrations: Default::default(),
3913 buffers_being_formatted: Default::default(),
3914 buffer_snapshots: Default::default(),
3915 prettier_store,
3916 environment,
3917 http_client,
3918 fs,
3919 yarn,
3920 next_diagnostic_group_id: Default::default(),
3921 diagnostics: Default::default(),
3922 _subscription: cx.on_app_quit(|this, cx| {
3923 this.as_local_mut()
3924 .unwrap()
3925 .shutdown_language_servers_on_quit(cx)
3926 }),
3927 lsp_tree: LanguageServerTree::new(
3928 manifest_tree,
3929 languages.clone(),
3930 toolchain_store.clone(),
3931 ),
3932 toolchain_store,
3933 registered_buffers: HashMap::default(),
3934 buffers_opened_in_servers: HashMap::default(),
3935 buffer_pull_diagnostics_result_ids: HashMap::default(),
3936 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3937 .manifest_file_names(),
3938 }),
3939 last_formatting_failure: None,
3940 downstream_client: None,
3941 buffer_store,
3942 worktree_store,
3943 languages: languages.clone(),
3944 language_server_statuses: Default::default(),
3945 nonce: StdRng::from_os_rng().random(),
3946 diagnostic_summaries: HashMap::default(),
3947 lsp_server_capabilities: HashMap::default(),
3948 lsp_data: HashMap::default(),
3949 next_hint_id: Arc::default(),
3950 active_entry: None,
3951 _maintain_workspace_config,
3952 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3953 }
3954 }
3955
3956 fn send_lsp_proto_request<R: LspCommand>(
3957 &self,
3958 buffer: Entity<Buffer>,
3959 client: AnyProtoClient,
3960 upstream_project_id: u64,
3961 request: R,
3962 cx: &mut Context<LspStore>,
3963 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3964 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3965 return Task::ready(Ok(R::Response::default()));
3966 }
3967 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3968 cx.spawn(async move |this, cx| {
3969 let response = client.request(message).await?;
3970 let this = this.upgrade().context("project dropped")?;
3971 request
3972 .response_from_proto(response, this, buffer, cx.clone())
3973 .await
3974 })
3975 }
3976
3977 pub(super) fn new_remote(
3978 buffer_store: Entity<BufferStore>,
3979 worktree_store: Entity<WorktreeStore>,
3980 languages: Arc<LanguageRegistry>,
3981 upstream_client: AnyProtoClient,
3982 project_id: u64,
3983 cx: &mut Context<Self>,
3984 ) -> Self {
3985 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3986 .detach();
3987 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3988 .detach();
3989 subscribe_to_binary_statuses(&languages, cx).detach();
3990 let _maintain_workspace_config = {
3991 let (sender, receiver) = watch::channel();
3992 (Self::maintain_workspace_config(receiver, cx), sender)
3993 };
3994 Self {
3995 mode: LspStoreMode::Remote(RemoteLspStore {
3996 upstream_client: Some(upstream_client),
3997 upstream_project_id: project_id,
3998 }),
3999 downstream_client: None,
4000 last_formatting_failure: None,
4001 buffer_store,
4002 worktree_store,
4003 languages: languages.clone(),
4004 language_server_statuses: Default::default(),
4005 nonce: StdRng::from_os_rng().random(),
4006 diagnostic_summaries: HashMap::default(),
4007 lsp_server_capabilities: HashMap::default(),
4008 next_hint_id: Arc::default(),
4009 lsp_data: HashMap::default(),
4010 active_entry: None,
4011
4012 _maintain_workspace_config,
4013 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4014 }
4015 }
4016
4017 fn on_buffer_store_event(
4018 &mut self,
4019 _: Entity<BufferStore>,
4020 event: &BufferStoreEvent,
4021 cx: &mut Context<Self>,
4022 ) {
4023 match event {
4024 BufferStoreEvent::BufferAdded(buffer) => {
4025 self.on_buffer_added(buffer, cx).log_err();
4026 }
4027 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4028 let buffer_id = buffer.read(cx).remote_id();
4029 if let Some(local) = self.as_local_mut()
4030 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4031 {
4032 local.reset_buffer(buffer, old_file, cx);
4033
4034 if local.registered_buffers.contains_key(&buffer_id) {
4035 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4036 }
4037 }
4038
4039 self.detect_language_for_buffer(buffer, cx);
4040 if let Some(local) = self.as_local_mut() {
4041 local.initialize_buffer(buffer, cx);
4042 if local.registered_buffers.contains_key(&buffer_id) {
4043 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4044 }
4045 }
4046 }
4047 _ => {}
4048 }
4049 }
4050
4051 fn on_worktree_store_event(
4052 &mut self,
4053 _: Entity<WorktreeStore>,
4054 event: &WorktreeStoreEvent,
4055 cx: &mut Context<Self>,
4056 ) {
4057 match event {
4058 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4059 if !worktree.read(cx).is_local() {
4060 return;
4061 }
4062 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4063 worktree::Event::UpdatedEntries(changes) => {
4064 this.update_local_worktree_language_servers(&worktree, changes, cx);
4065 }
4066 worktree::Event::UpdatedGitRepositories(_)
4067 | worktree::Event::DeletedEntry(_) => {}
4068 })
4069 .detach()
4070 }
4071 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4072 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4073 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4074 }
4075 WorktreeStoreEvent::WorktreeReleased(..)
4076 | WorktreeStoreEvent::WorktreeOrderChanged
4077 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4078 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4079 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4080 }
4081 }
4082
4083 fn on_prettier_store_event(
4084 &mut self,
4085 _: Entity<PrettierStore>,
4086 event: &PrettierStoreEvent,
4087 cx: &mut Context<Self>,
4088 ) {
4089 match event {
4090 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4091 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4092 }
4093 PrettierStoreEvent::LanguageServerAdded {
4094 new_server_id,
4095 name,
4096 prettier_server,
4097 } => {
4098 self.register_supplementary_language_server(
4099 *new_server_id,
4100 name.clone(),
4101 prettier_server.clone(),
4102 cx,
4103 );
4104 }
4105 }
4106 }
4107
4108 fn on_toolchain_store_event(
4109 &mut self,
4110 _: Entity<LocalToolchainStore>,
4111 event: &ToolchainStoreEvent,
4112 _: &mut Context<Self>,
4113 ) {
4114 if let ToolchainStoreEvent::ToolchainActivated = event {
4115 self.request_workspace_config_refresh()
4116 }
4117 }
4118
4119 fn request_workspace_config_refresh(&mut self) {
4120 *self._maintain_workspace_config.1.borrow_mut() = ();
4121 }
4122
4123 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4124 self.as_local().map(|local| local.prettier_store.clone())
4125 }
4126
4127 fn on_buffer_event(
4128 &mut self,
4129 buffer: Entity<Buffer>,
4130 event: &language::BufferEvent,
4131 cx: &mut Context<Self>,
4132 ) {
4133 match event {
4134 language::BufferEvent::Edited => {
4135 self.on_buffer_edited(buffer, cx);
4136 }
4137
4138 language::BufferEvent::Saved => {
4139 self.on_buffer_saved(buffer, cx);
4140 }
4141
4142 _ => {}
4143 }
4144 }
4145
4146 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4147 buffer
4148 .read(cx)
4149 .set_language_registry(self.languages.clone());
4150
4151 cx.subscribe(buffer, |this, buffer, event, cx| {
4152 this.on_buffer_event(buffer, event, cx);
4153 })
4154 .detach();
4155
4156 self.detect_language_for_buffer(buffer, cx);
4157 if let Some(local) = self.as_local_mut() {
4158 local.initialize_buffer(buffer, cx);
4159 }
4160
4161 Ok(())
4162 }
4163
4164 pub(crate) fn register_buffer_with_language_servers(
4165 &mut self,
4166 buffer: &Entity<Buffer>,
4167 only_register_servers: HashSet<LanguageServerSelector>,
4168 ignore_refcounts: bool,
4169 cx: &mut Context<Self>,
4170 ) -> OpenLspBufferHandle {
4171 let buffer_id = buffer.read(cx).remote_id();
4172 let handle = cx.new(|_| buffer.clone());
4173 if let Some(local) = self.as_local_mut() {
4174 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4175 if !ignore_refcounts {
4176 *refcount += 1;
4177 }
4178
4179 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4180 // 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
4181 // 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
4182 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4183 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4184 return handle;
4185 };
4186 if !file.is_local() {
4187 return handle;
4188 }
4189
4190 if ignore_refcounts || *refcount == 1 {
4191 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4192 }
4193 if !ignore_refcounts {
4194 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4195 let refcount = {
4196 let local = lsp_store.as_local_mut().unwrap();
4197 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4198 debug_panic!("bad refcounting");
4199 return;
4200 };
4201
4202 *refcount -= 1;
4203 *refcount
4204 };
4205 if refcount == 0 {
4206 lsp_store.lsp_data.remove(&buffer_id);
4207 let local = lsp_store.as_local_mut().unwrap();
4208 local.registered_buffers.remove(&buffer_id);
4209 local.buffers_opened_in_servers.remove(&buffer_id);
4210 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4211 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4212 }
4213 }
4214 })
4215 .detach();
4216 }
4217 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4218 let buffer_id = buffer.read(cx).remote_id().to_proto();
4219 cx.background_spawn(async move {
4220 upstream_client
4221 .request(proto::RegisterBufferWithLanguageServers {
4222 project_id: upstream_project_id,
4223 buffer_id,
4224 only_servers: only_register_servers
4225 .into_iter()
4226 .map(|selector| {
4227 let selector = match selector {
4228 LanguageServerSelector::Id(language_server_id) => {
4229 proto::language_server_selector::Selector::ServerId(
4230 language_server_id.to_proto(),
4231 )
4232 }
4233 LanguageServerSelector::Name(language_server_name) => {
4234 proto::language_server_selector::Selector::Name(
4235 language_server_name.to_string(),
4236 )
4237 }
4238 };
4239 proto::LanguageServerSelector {
4240 selector: Some(selector),
4241 }
4242 })
4243 .collect(),
4244 })
4245 .await
4246 })
4247 .detach();
4248 } else {
4249 // Our remote connection got closed
4250 }
4251 handle
4252 }
4253
4254 fn maintain_buffer_languages(
4255 languages: Arc<LanguageRegistry>,
4256 cx: &mut Context<Self>,
4257 ) -> Task<()> {
4258 let mut subscription = languages.subscribe();
4259 let mut prev_reload_count = languages.reload_count();
4260 cx.spawn(async move |this, cx| {
4261 while let Some(()) = subscription.next().await {
4262 if let Some(this) = this.upgrade() {
4263 // If the language registry has been reloaded, then remove and
4264 // re-assign the languages on all open buffers.
4265 let reload_count = languages.reload_count();
4266 if reload_count > prev_reload_count {
4267 prev_reload_count = reload_count;
4268 this.update(cx, |this, cx| {
4269 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4270 for buffer in buffer_store.buffers() {
4271 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4272 {
4273 buffer
4274 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4275 if let Some(local) = this.as_local_mut() {
4276 local.reset_buffer(&buffer, &f, cx);
4277
4278 if local
4279 .registered_buffers
4280 .contains_key(&buffer.read(cx).remote_id())
4281 && let Some(file_url) =
4282 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4283 {
4284 local.unregister_buffer_from_language_servers(
4285 &buffer, &file_url, cx,
4286 );
4287 }
4288 }
4289 }
4290 }
4291 });
4292 })
4293 .ok();
4294 }
4295
4296 this.update(cx, |this, cx| {
4297 let mut plain_text_buffers = Vec::new();
4298 let mut buffers_with_unknown_injections = Vec::new();
4299 for handle in this.buffer_store.read(cx).buffers() {
4300 let buffer = handle.read(cx);
4301 if buffer.language().is_none()
4302 || buffer.language() == Some(&*language::PLAIN_TEXT)
4303 {
4304 plain_text_buffers.push(handle);
4305 } else if buffer.contains_unknown_injections() {
4306 buffers_with_unknown_injections.push(handle);
4307 }
4308 }
4309
4310 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4311 // and reused later in the invisible worktrees.
4312 plain_text_buffers.sort_by_key(|buffer| {
4313 Reverse(
4314 File::from_dyn(buffer.read(cx).file())
4315 .map(|file| file.worktree.read(cx).is_visible()),
4316 )
4317 });
4318
4319 for buffer in plain_text_buffers {
4320 this.detect_language_for_buffer(&buffer, cx);
4321 if let Some(local) = this.as_local_mut() {
4322 local.initialize_buffer(&buffer, cx);
4323 if local
4324 .registered_buffers
4325 .contains_key(&buffer.read(cx).remote_id())
4326 {
4327 local.register_buffer_with_language_servers(
4328 &buffer,
4329 HashSet::default(),
4330 cx,
4331 );
4332 }
4333 }
4334 }
4335
4336 for buffer in buffers_with_unknown_injections {
4337 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4338 }
4339 })
4340 .ok();
4341 }
4342 }
4343 })
4344 }
4345
4346 fn detect_language_for_buffer(
4347 &mut self,
4348 buffer_handle: &Entity<Buffer>,
4349 cx: &mut Context<Self>,
4350 ) -> Option<language::AvailableLanguage> {
4351 // If the buffer has a language, set it and start the language server if we haven't already.
4352 let buffer = buffer_handle.read(cx);
4353 let file = buffer.file()?;
4354
4355 let content = buffer.as_rope();
4356 let available_language = self.languages.language_for_file(file, Some(content), cx);
4357 if let Some(available_language) = &available_language {
4358 if let Some(Ok(Ok(new_language))) = self
4359 .languages
4360 .load_language(available_language)
4361 .now_or_never()
4362 {
4363 self.set_language_for_buffer(buffer_handle, new_language, cx);
4364 }
4365 } else {
4366 cx.emit(LspStoreEvent::LanguageDetected {
4367 buffer: buffer_handle.clone(),
4368 new_language: None,
4369 });
4370 }
4371
4372 available_language
4373 }
4374
4375 pub(crate) fn set_language_for_buffer(
4376 &mut self,
4377 buffer_entity: &Entity<Buffer>,
4378 new_language: Arc<Language>,
4379 cx: &mut Context<Self>,
4380 ) {
4381 let buffer = buffer_entity.read(cx);
4382 let buffer_file = buffer.file().cloned();
4383 let buffer_id = buffer.remote_id();
4384 if let Some(local_store) = self.as_local_mut()
4385 && local_store.registered_buffers.contains_key(&buffer_id)
4386 && let Some(abs_path) =
4387 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4388 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4389 {
4390 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4391 }
4392 buffer_entity.update(cx, |buffer, cx| {
4393 if buffer
4394 .language()
4395 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4396 {
4397 buffer.set_language(Some(new_language.clone()), cx);
4398 }
4399 });
4400
4401 let settings =
4402 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4403 let buffer_file = File::from_dyn(buffer_file.as_ref());
4404
4405 let worktree_id = if let Some(file) = buffer_file {
4406 let worktree = file.worktree.clone();
4407
4408 if let Some(local) = self.as_local_mut()
4409 && local.registered_buffers.contains_key(&buffer_id)
4410 {
4411 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4412 }
4413 Some(worktree.read(cx).id())
4414 } else {
4415 None
4416 };
4417
4418 if settings.prettier.allowed
4419 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4420 {
4421 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4422 if let Some(prettier_store) = prettier_store {
4423 prettier_store.update(cx, |prettier_store, cx| {
4424 prettier_store.install_default_prettier(
4425 worktree_id,
4426 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4427 cx,
4428 )
4429 })
4430 }
4431 }
4432
4433 cx.emit(LspStoreEvent::LanguageDetected {
4434 buffer: buffer_entity.clone(),
4435 new_language: Some(new_language),
4436 })
4437 }
4438
4439 pub fn buffer_store(&self) -> Entity<BufferStore> {
4440 self.buffer_store.clone()
4441 }
4442
4443 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4444 self.active_entry = active_entry;
4445 }
4446
4447 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4448 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4449 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4450 {
4451 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4452 summaries
4453 .iter()
4454 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4455 });
4456 if let Some(summary) = summaries.next() {
4457 client
4458 .send(proto::UpdateDiagnosticSummary {
4459 project_id: downstream_project_id,
4460 worktree_id: worktree.id().to_proto(),
4461 summary: Some(summary),
4462 more_summaries: summaries.collect(),
4463 })
4464 .log_err();
4465 }
4466 }
4467 }
4468
4469 fn is_capable_for_proto_request<R>(
4470 &self,
4471 buffer: &Entity<Buffer>,
4472 request: &R,
4473 cx: &App,
4474 ) -> bool
4475 where
4476 R: LspCommand,
4477 {
4478 self.check_if_capable_for_proto_request(
4479 buffer,
4480 |capabilities| {
4481 request.check_capabilities(AdapterServerCapabilities {
4482 server_capabilities: capabilities.clone(),
4483 code_action_kinds: None,
4484 })
4485 },
4486 cx,
4487 )
4488 }
4489
4490 fn check_if_capable_for_proto_request<F>(
4491 &self,
4492 buffer: &Entity<Buffer>,
4493 check: F,
4494 cx: &App,
4495 ) -> bool
4496 where
4497 F: FnMut(&lsp::ServerCapabilities) -> bool,
4498 {
4499 let Some(language) = buffer.read(cx).language().cloned() else {
4500 return false;
4501 };
4502 let relevant_language_servers = self
4503 .languages
4504 .lsp_adapters(&language.name())
4505 .into_iter()
4506 .map(|lsp_adapter| lsp_adapter.name())
4507 .collect::<HashSet<_>>();
4508 self.language_server_statuses
4509 .iter()
4510 .filter_map(|(server_id, server_status)| {
4511 relevant_language_servers
4512 .contains(&server_status.name)
4513 .then_some(server_id)
4514 })
4515 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4516 .any(check)
4517 }
4518
4519 fn all_capable_for_proto_request<F>(
4520 &self,
4521 buffer: &Entity<Buffer>,
4522 mut check: F,
4523 cx: &App,
4524 ) -> Vec<lsp::LanguageServerId>
4525 where
4526 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4527 {
4528 let Some(language) = buffer.read(cx).language().cloned() else {
4529 return Vec::default();
4530 };
4531 let relevant_language_servers = self
4532 .languages
4533 .lsp_adapters(&language.name())
4534 .into_iter()
4535 .map(|lsp_adapter| lsp_adapter.name())
4536 .collect::<HashSet<_>>();
4537 self.language_server_statuses
4538 .iter()
4539 .filter_map(|(server_id, server_status)| {
4540 relevant_language_servers
4541 .contains(&server_status.name)
4542 .then_some((server_id, &server_status.name))
4543 })
4544 .filter_map(|(server_id, server_name)| {
4545 self.lsp_server_capabilities
4546 .get(server_id)
4547 .map(|c| (server_id, server_name, c))
4548 })
4549 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4550 .map(|(server_id, _, _)| *server_id)
4551 .collect()
4552 }
4553
4554 pub fn request_lsp<R>(
4555 &mut self,
4556 buffer: Entity<Buffer>,
4557 server: LanguageServerToQuery,
4558 request: R,
4559 cx: &mut Context<Self>,
4560 ) -> Task<Result<R::Response>>
4561 where
4562 R: LspCommand,
4563 <R::LspRequest as lsp::request::Request>::Result: Send,
4564 <R::LspRequest as lsp::request::Request>::Params: Send,
4565 {
4566 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4567 return self.send_lsp_proto_request(
4568 buffer,
4569 upstream_client,
4570 upstream_project_id,
4571 request,
4572 cx,
4573 );
4574 }
4575
4576 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4577 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4578 local
4579 .language_servers_for_buffer(buffer, cx)
4580 .find(|(_, server)| {
4581 request.check_capabilities(server.adapter_server_capabilities())
4582 })
4583 .map(|(_, server)| server.clone())
4584 }),
4585 LanguageServerToQuery::Other(id) => self
4586 .language_server_for_local_buffer(buffer, id, cx)
4587 .and_then(|(_, server)| {
4588 request
4589 .check_capabilities(server.adapter_server_capabilities())
4590 .then(|| Arc::clone(server))
4591 }),
4592 }) else {
4593 return Task::ready(Ok(Default::default()));
4594 };
4595
4596 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4597
4598 let Some(file) = file else {
4599 return Task::ready(Ok(Default::default()));
4600 };
4601
4602 let lsp_params = match request.to_lsp_params_or_response(
4603 &file.abs_path(cx),
4604 buffer.read(cx),
4605 &language_server,
4606 cx,
4607 ) {
4608 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4609 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4610 Err(err) => {
4611 let message = format!(
4612 "{} via {} failed: {}",
4613 request.display_name(),
4614 language_server.name(),
4615 err
4616 );
4617 // rust-analyzer likes to error with this when its still loading up
4618 if !message.ends_with("content modified") {
4619 log::warn!("{message}");
4620 }
4621 return Task::ready(Err(anyhow!(message)));
4622 }
4623 };
4624
4625 let status = request.status();
4626 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4627 return Task::ready(Ok(Default::default()));
4628 }
4629 cx.spawn(async move |this, cx| {
4630 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4631
4632 let id = lsp_request.id();
4633 let _cleanup = if status.is_some() {
4634 cx.update(|cx| {
4635 this.update(cx, |this, cx| {
4636 this.on_lsp_work_start(
4637 language_server.server_id(),
4638 ProgressToken::Number(id),
4639 LanguageServerProgress {
4640 is_disk_based_diagnostics_progress: false,
4641 is_cancellable: false,
4642 title: None,
4643 message: status.clone(),
4644 percentage: None,
4645 last_update_at: cx.background_executor().now(),
4646 },
4647 cx,
4648 );
4649 })
4650 })
4651 .log_err();
4652
4653 Some(defer(|| {
4654 cx.update(|cx| {
4655 this.update(cx, |this, cx| {
4656 this.on_lsp_work_end(
4657 language_server.server_id(),
4658 ProgressToken::Number(id),
4659 cx,
4660 );
4661 })
4662 })
4663 .log_err();
4664 }))
4665 } else {
4666 None
4667 };
4668
4669 let result = lsp_request.await.into_response();
4670
4671 let response = result.map_err(|err| {
4672 let message = format!(
4673 "{} via {} failed: {}",
4674 request.display_name(),
4675 language_server.name(),
4676 err
4677 );
4678 // rust-analyzer likes to error with this when its still loading up
4679 if !message.ends_with("content modified") {
4680 log::warn!("{message}");
4681 }
4682 anyhow::anyhow!(message)
4683 })?;
4684
4685 request
4686 .response_from_lsp(
4687 response,
4688 this.upgrade().context("no app context")?,
4689 buffer,
4690 language_server.server_id(),
4691 cx.clone(),
4692 )
4693 .await
4694 })
4695 }
4696
4697 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4698 let mut language_formatters_to_check = Vec::new();
4699 for buffer in self.buffer_store.read(cx).buffers() {
4700 let buffer = buffer.read(cx);
4701 let buffer_file = File::from_dyn(buffer.file());
4702 let buffer_language = buffer.language();
4703 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4704 if buffer_language.is_some() {
4705 language_formatters_to_check.push((
4706 buffer_file.map(|f| f.worktree_id(cx)),
4707 settings.into_owned(),
4708 ));
4709 }
4710 }
4711
4712 self.request_workspace_config_refresh();
4713
4714 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4715 prettier_store.update(cx, |prettier_store, cx| {
4716 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4717 })
4718 }
4719
4720 cx.notify();
4721 }
4722
4723 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4724 let buffer_store = self.buffer_store.clone();
4725 let Some(local) = self.as_local_mut() else {
4726 return;
4727 };
4728 let mut adapters = BTreeMap::default();
4729 let get_adapter = {
4730 let languages = local.languages.clone();
4731 let environment = local.environment.clone();
4732 let weak = local.weak.clone();
4733 let worktree_store = local.worktree_store.clone();
4734 let http_client = local.http_client.clone();
4735 let fs = local.fs.clone();
4736 move |worktree_id, cx: &mut App| {
4737 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4738 Some(LocalLspAdapterDelegate::new(
4739 languages.clone(),
4740 &environment,
4741 weak.clone(),
4742 &worktree,
4743 http_client.clone(),
4744 fs.clone(),
4745 cx,
4746 ))
4747 }
4748 };
4749
4750 let mut messages_to_report = Vec::new();
4751 let (new_tree, to_stop) = {
4752 let mut rebase = local.lsp_tree.rebase();
4753 let buffers = buffer_store
4754 .read(cx)
4755 .buffers()
4756 .filter_map(|buffer| {
4757 let raw_buffer = buffer.read(cx);
4758 if !local
4759 .registered_buffers
4760 .contains_key(&raw_buffer.remote_id())
4761 {
4762 return None;
4763 }
4764 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4765 let language = raw_buffer.language().cloned()?;
4766 Some((file, language, raw_buffer.remote_id()))
4767 })
4768 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4769 for (file, language, buffer_id) in buffers {
4770 let worktree_id = file.worktree_id(cx);
4771 let Some(worktree) = local
4772 .worktree_store
4773 .read(cx)
4774 .worktree_for_id(worktree_id, cx)
4775 else {
4776 continue;
4777 };
4778
4779 if let Some((_, apply)) = local.reuse_existing_language_server(
4780 rebase.server_tree(),
4781 &worktree,
4782 &language.name(),
4783 cx,
4784 ) {
4785 (apply)(rebase.server_tree());
4786 } else if let Some(lsp_delegate) = adapters
4787 .entry(worktree_id)
4788 .or_insert_with(|| get_adapter(worktree_id, cx))
4789 .clone()
4790 {
4791 let delegate =
4792 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4793 let path = file
4794 .path()
4795 .parent()
4796 .map(Arc::from)
4797 .unwrap_or_else(|| file.path().clone());
4798 let worktree_path = ProjectPath { worktree_id, path };
4799 let abs_path = file.abs_path(cx);
4800 let nodes = rebase
4801 .walk(
4802 worktree_path,
4803 language.name(),
4804 language.manifest(),
4805 delegate.clone(),
4806 cx,
4807 )
4808 .collect::<Vec<_>>();
4809 for node in nodes {
4810 let server_id = node.server_id_or_init(|disposition| {
4811 let path = &disposition.path;
4812 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4813 let key = LanguageServerSeed {
4814 worktree_id,
4815 name: disposition.server_name.clone(),
4816 settings: disposition.settings.clone(),
4817 toolchain: local.toolchain_store.read(cx).active_toolchain(
4818 path.worktree_id,
4819 &path.path,
4820 language.name(),
4821 ),
4822 };
4823 local.language_server_ids.remove(&key);
4824
4825 let server_id = local.get_or_insert_language_server(
4826 &worktree,
4827 lsp_delegate.clone(),
4828 disposition,
4829 &language.name(),
4830 cx,
4831 );
4832 if let Some(state) = local.language_servers.get(&server_id)
4833 && let Ok(uri) = uri
4834 {
4835 state.add_workspace_folder(uri);
4836 };
4837 server_id
4838 });
4839
4840 if let Some(language_server_id) = server_id {
4841 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4842 language_server_id,
4843 name: node.name(),
4844 message:
4845 proto::update_language_server::Variant::RegisteredForBuffer(
4846 proto::RegisteredForBuffer {
4847 buffer_abs_path: abs_path
4848 .to_string_lossy()
4849 .into_owned(),
4850 buffer_id: buffer_id.to_proto(),
4851 },
4852 ),
4853 });
4854 }
4855 }
4856 } else {
4857 continue;
4858 }
4859 }
4860 rebase.finish()
4861 };
4862 for message in messages_to_report {
4863 cx.emit(message);
4864 }
4865 local.lsp_tree = new_tree;
4866 for (id, _) in to_stop {
4867 self.stop_local_language_server(id, cx).detach();
4868 }
4869 }
4870
4871 pub fn apply_code_action(
4872 &self,
4873 buffer_handle: Entity<Buffer>,
4874 mut action: CodeAction,
4875 push_to_history: bool,
4876 cx: &mut Context<Self>,
4877 ) -> Task<Result<ProjectTransaction>> {
4878 if let Some((upstream_client, project_id)) = self.upstream_client() {
4879 let request = proto::ApplyCodeAction {
4880 project_id,
4881 buffer_id: buffer_handle.read(cx).remote_id().into(),
4882 action: Some(Self::serialize_code_action(&action)),
4883 };
4884 let buffer_store = self.buffer_store();
4885 cx.spawn(async move |_, cx| {
4886 let response = upstream_client
4887 .request(request)
4888 .await?
4889 .transaction
4890 .context("missing transaction")?;
4891
4892 buffer_store
4893 .update(cx, |buffer_store, cx| {
4894 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4895 })?
4896 .await
4897 })
4898 } else if self.mode.is_local() {
4899 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4900 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4901 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4902 }) else {
4903 return Task::ready(Ok(ProjectTransaction::default()));
4904 };
4905 cx.spawn(async move |this, cx| {
4906 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4907 .await
4908 .context("resolving a code action")?;
4909 if let Some(edit) = action.lsp_action.edit()
4910 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4911 return LocalLspStore::deserialize_workspace_edit(
4912 this.upgrade().context("no app present")?,
4913 edit.clone(),
4914 push_to_history,
4915
4916 lang_server.clone(),
4917 cx,
4918 )
4919 .await;
4920 }
4921
4922 if let Some(command) = action.lsp_action.command() {
4923 let server_capabilities = lang_server.capabilities();
4924 let available_commands = server_capabilities
4925 .execute_command_provider
4926 .as_ref()
4927 .map(|options| options.commands.as_slice())
4928 .unwrap_or_default();
4929 if available_commands.contains(&command.command) {
4930 this.update(cx, |this, _| {
4931 this.as_local_mut()
4932 .unwrap()
4933 .last_workspace_edits_by_language_server
4934 .remove(&lang_server.server_id());
4935 })?;
4936
4937 let _result = lang_server
4938 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4939 command: command.command.clone(),
4940 arguments: command.arguments.clone().unwrap_or_default(),
4941 ..lsp::ExecuteCommandParams::default()
4942 })
4943 .await.into_response()
4944 .context("execute command")?;
4945
4946 return this.update(cx, |this, _| {
4947 this.as_local_mut()
4948 .unwrap()
4949 .last_workspace_edits_by_language_server
4950 .remove(&lang_server.server_id())
4951 .unwrap_or_default()
4952 });
4953 } else {
4954 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4955 }
4956 }
4957
4958 Ok(ProjectTransaction::default())
4959 })
4960 } else {
4961 Task::ready(Err(anyhow!("no upstream client and not local")))
4962 }
4963 }
4964
4965 pub fn apply_code_action_kind(
4966 &mut self,
4967 buffers: HashSet<Entity<Buffer>>,
4968 kind: CodeActionKind,
4969 push_to_history: bool,
4970 cx: &mut Context<Self>,
4971 ) -> Task<anyhow::Result<ProjectTransaction>> {
4972 if self.as_local().is_some() {
4973 cx.spawn(async move |lsp_store, cx| {
4974 let buffers = buffers.into_iter().collect::<Vec<_>>();
4975 let result = LocalLspStore::execute_code_action_kind_locally(
4976 lsp_store.clone(),
4977 buffers,
4978 kind,
4979 push_to_history,
4980 cx,
4981 )
4982 .await;
4983 lsp_store.update(cx, |lsp_store, _| {
4984 lsp_store.update_last_formatting_failure(&result);
4985 })?;
4986 result
4987 })
4988 } else if let Some((client, project_id)) = self.upstream_client() {
4989 let buffer_store = self.buffer_store();
4990 cx.spawn(async move |lsp_store, cx| {
4991 let result = client
4992 .request(proto::ApplyCodeActionKind {
4993 project_id,
4994 kind: kind.as_str().to_owned(),
4995 buffer_ids: buffers
4996 .iter()
4997 .map(|buffer| {
4998 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4999 })
5000 .collect::<Result<_>>()?,
5001 })
5002 .await
5003 .and_then(|result| result.transaction.context("missing transaction"));
5004 lsp_store.update(cx, |lsp_store, _| {
5005 lsp_store.update_last_formatting_failure(&result);
5006 })?;
5007
5008 let transaction_response = result?;
5009 buffer_store
5010 .update(cx, |buffer_store, cx| {
5011 buffer_store.deserialize_project_transaction(
5012 transaction_response,
5013 push_to_history,
5014 cx,
5015 )
5016 })?
5017 .await
5018 })
5019 } else {
5020 Task::ready(Ok(ProjectTransaction::default()))
5021 }
5022 }
5023
5024 pub fn resolved_hint(
5025 &mut self,
5026 buffer_id: BufferId,
5027 id: InlayId,
5028 cx: &mut Context<Self>,
5029 ) -> Option<ResolvedHint> {
5030 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5031
5032 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5033 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5034 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5035 let (server_id, resolve_data) = match &hint.resolve_state {
5036 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5037 ResolveState::Resolving => {
5038 return Some(ResolvedHint::Resolving(
5039 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5040 ));
5041 }
5042 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5043 };
5044
5045 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5046 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5047 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5048 id,
5049 cx.spawn(async move |lsp_store, cx| {
5050 let resolved_hint = resolve_task.await;
5051 lsp_store
5052 .update(cx, |lsp_store, _| {
5053 if let Some(old_inlay_hint) = lsp_store
5054 .lsp_data
5055 .get_mut(&buffer_id)
5056 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5057 {
5058 match resolved_hint {
5059 Ok(resolved_hint) => {
5060 *old_inlay_hint = resolved_hint;
5061 }
5062 Err(e) => {
5063 old_inlay_hint.resolve_state =
5064 ResolveState::CanResolve(server_id, resolve_data);
5065 log::error!("Inlay hint resolve failed: {e:#}");
5066 }
5067 }
5068 }
5069 })
5070 .ok();
5071 })
5072 .shared(),
5073 );
5074 debug_assert!(
5075 previous_task.is_none(),
5076 "Did not change hint's resolve state after spawning its resolve"
5077 );
5078 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5079 None
5080 }
5081
5082 fn resolve_inlay_hint(
5083 &self,
5084 mut hint: InlayHint,
5085 buffer: Entity<Buffer>,
5086 server_id: LanguageServerId,
5087 cx: &mut Context<Self>,
5088 ) -> Task<anyhow::Result<InlayHint>> {
5089 if let Some((upstream_client, project_id)) = self.upstream_client() {
5090 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5091 {
5092 hint.resolve_state = ResolveState::Resolved;
5093 return Task::ready(Ok(hint));
5094 }
5095 let request = proto::ResolveInlayHint {
5096 project_id,
5097 buffer_id: buffer.read(cx).remote_id().into(),
5098 language_server_id: server_id.0 as u64,
5099 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5100 };
5101 cx.background_spawn(async move {
5102 let response = upstream_client
5103 .request(request)
5104 .await
5105 .context("inlay hints proto request")?;
5106 match response.hint {
5107 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5108 .context("inlay hints proto resolve response conversion"),
5109 None => Ok(hint),
5110 }
5111 })
5112 } else {
5113 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5114 self.language_server_for_local_buffer(buffer, server_id, cx)
5115 .map(|(_, server)| server.clone())
5116 }) else {
5117 return Task::ready(Ok(hint));
5118 };
5119 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5120 return Task::ready(Ok(hint));
5121 }
5122 let buffer_snapshot = buffer.read(cx).snapshot();
5123 cx.spawn(async move |_, cx| {
5124 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5125 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5126 );
5127 let resolved_hint = resolve_task
5128 .await
5129 .into_response()
5130 .context("inlay hint resolve LSP request")?;
5131 let resolved_hint = InlayHints::lsp_to_project_hint(
5132 resolved_hint,
5133 &buffer,
5134 server_id,
5135 ResolveState::Resolved,
5136 false,
5137 cx,
5138 )
5139 .await?;
5140 Ok(resolved_hint)
5141 })
5142 }
5143 }
5144
5145 pub fn resolve_color_presentation(
5146 &mut self,
5147 mut color: DocumentColor,
5148 buffer: Entity<Buffer>,
5149 server_id: LanguageServerId,
5150 cx: &mut Context<Self>,
5151 ) -> Task<Result<DocumentColor>> {
5152 if color.resolved {
5153 return Task::ready(Ok(color));
5154 }
5155
5156 if let Some((upstream_client, project_id)) = self.upstream_client() {
5157 let start = color.lsp_range.start;
5158 let end = color.lsp_range.end;
5159 let request = proto::GetColorPresentation {
5160 project_id,
5161 server_id: server_id.to_proto(),
5162 buffer_id: buffer.read(cx).remote_id().into(),
5163 color: Some(proto::ColorInformation {
5164 red: color.color.red,
5165 green: color.color.green,
5166 blue: color.color.blue,
5167 alpha: color.color.alpha,
5168 lsp_range_start: Some(proto::PointUtf16 {
5169 row: start.line,
5170 column: start.character,
5171 }),
5172 lsp_range_end: Some(proto::PointUtf16 {
5173 row: end.line,
5174 column: end.character,
5175 }),
5176 }),
5177 };
5178 cx.background_spawn(async move {
5179 let response = upstream_client
5180 .request(request)
5181 .await
5182 .context("color presentation proto request")?;
5183 color.resolved = true;
5184 color.color_presentations = response
5185 .presentations
5186 .into_iter()
5187 .map(|presentation| ColorPresentation {
5188 label: SharedString::from(presentation.label),
5189 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5190 additional_text_edits: presentation
5191 .additional_text_edits
5192 .into_iter()
5193 .filter_map(deserialize_lsp_edit)
5194 .collect(),
5195 })
5196 .collect();
5197 Ok(color)
5198 })
5199 } else {
5200 let path = match buffer
5201 .update(cx, |buffer, cx| {
5202 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5203 })
5204 .context("buffer with the missing path")
5205 {
5206 Ok(path) => path,
5207 Err(e) => return Task::ready(Err(e)),
5208 };
5209 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5210 self.language_server_for_local_buffer(buffer, server_id, cx)
5211 .map(|(_, server)| server.clone())
5212 }) else {
5213 return Task::ready(Ok(color));
5214 };
5215 cx.background_spawn(async move {
5216 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5217 lsp::ColorPresentationParams {
5218 text_document: make_text_document_identifier(&path)?,
5219 color: color.color,
5220 range: color.lsp_range,
5221 work_done_progress_params: Default::default(),
5222 partial_result_params: Default::default(),
5223 },
5224 );
5225 color.color_presentations = resolve_task
5226 .await
5227 .into_response()
5228 .context("color presentation resolve LSP request")?
5229 .into_iter()
5230 .map(|presentation| ColorPresentation {
5231 label: SharedString::from(presentation.label),
5232 text_edit: presentation.text_edit,
5233 additional_text_edits: presentation
5234 .additional_text_edits
5235 .unwrap_or_default(),
5236 })
5237 .collect();
5238 color.resolved = true;
5239 Ok(color)
5240 })
5241 }
5242 }
5243
5244 pub(crate) fn linked_edits(
5245 &mut self,
5246 buffer: &Entity<Buffer>,
5247 position: Anchor,
5248 cx: &mut Context<Self>,
5249 ) -> Task<Result<Vec<Range<Anchor>>>> {
5250 let snapshot = buffer.read(cx).snapshot();
5251 let scope = snapshot.language_scope_at(position);
5252 let Some(server_id) = self
5253 .as_local()
5254 .and_then(|local| {
5255 buffer.update(cx, |buffer, cx| {
5256 local
5257 .language_servers_for_buffer(buffer, cx)
5258 .filter(|(_, server)| {
5259 LinkedEditingRange::check_server_capabilities(server.capabilities())
5260 })
5261 .filter(|(adapter, _)| {
5262 scope
5263 .as_ref()
5264 .map(|scope| scope.language_allowed(&adapter.name))
5265 .unwrap_or(true)
5266 })
5267 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5268 .next()
5269 })
5270 })
5271 .or_else(|| {
5272 self.upstream_client()
5273 .is_some()
5274 .then_some(LanguageServerToQuery::FirstCapable)
5275 })
5276 .filter(|_| {
5277 maybe!({
5278 let language = buffer.read(cx).language_at(position)?;
5279 Some(
5280 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5281 .linked_edits,
5282 )
5283 }) == Some(true)
5284 })
5285 else {
5286 return Task::ready(Ok(Vec::new()));
5287 };
5288
5289 self.request_lsp(
5290 buffer.clone(),
5291 server_id,
5292 LinkedEditingRange { position },
5293 cx,
5294 )
5295 }
5296
5297 fn apply_on_type_formatting(
5298 &mut self,
5299 buffer: Entity<Buffer>,
5300 position: Anchor,
5301 trigger: String,
5302 cx: &mut Context<Self>,
5303 ) -> Task<Result<Option<Transaction>>> {
5304 if let Some((client, project_id)) = self.upstream_client() {
5305 if !self.check_if_capable_for_proto_request(
5306 &buffer,
5307 |capabilities| {
5308 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5309 },
5310 cx,
5311 ) {
5312 return Task::ready(Ok(None));
5313 }
5314 let request = proto::OnTypeFormatting {
5315 project_id,
5316 buffer_id: buffer.read(cx).remote_id().into(),
5317 position: Some(serialize_anchor(&position)),
5318 trigger,
5319 version: serialize_version(&buffer.read(cx).version()),
5320 };
5321 cx.background_spawn(async move {
5322 client
5323 .request(request)
5324 .await?
5325 .transaction
5326 .map(language::proto::deserialize_transaction)
5327 .transpose()
5328 })
5329 } else if let Some(local) = self.as_local_mut() {
5330 let buffer_id = buffer.read(cx).remote_id();
5331 local.buffers_being_formatted.insert(buffer_id);
5332 cx.spawn(async move |this, cx| {
5333 let _cleanup = defer({
5334 let this = this.clone();
5335 let mut cx = cx.clone();
5336 move || {
5337 this.update(&mut cx, |this, _| {
5338 if let Some(local) = this.as_local_mut() {
5339 local.buffers_being_formatted.remove(&buffer_id);
5340 }
5341 })
5342 .ok();
5343 }
5344 });
5345
5346 buffer
5347 .update(cx, |buffer, _| {
5348 buffer.wait_for_edits(Some(position.timestamp))
5349 })?
5350 .await?;
5351 this.update(cx, |this, cx| {
5352 let position = position.to_point_utf16(buffer.read(cx));
5353 this.on_type_format(buffer, position, trigger, false, cx)
5354 })?
5355 .await
5356 })
5357 } else {
5358 Task::ready(Err(anyhow!("No upstream client or local language server")))
5359 }
5360 }
5361
5362 pub fn on_type_format<T: ToPointUtf16>(
5363 &mut self,
5364 buffer: Entity<Buffer>,
5365 position: T,
5366 trigger: String,
5367 push_to_history: bool,
5368 cx: &mut Context<Self>,
5369 ) -> Task<Result<Option<Transaction>>> {
5370 let position = position.to_point_utf16(buffer.read(cx));
5371 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5372 }
5373
5374 fn on_type_format_impl(
5375 &mut self,
5376 buffer: Entity<Buffer>,
5377 position: PointUtf16,
5378 trigger: String,
5379 push_to_history: bool,
5380 cx: &mut Context<Self>,
5381 ) -> Task<Result<Option<Transaction>>> {
5382 let options = buffer.update(cx, |buffer, cx| {
5383 lsp_command::lsp_formatting_options(
5384 language_settings(
5385 buffer.language_at(position).map(|l| l.name()),
5386 buffer.file(),
5387 cx,
5388 )
5389 .as_ref(),
5390 )
5391 });
5392
5393 cx.spawn(async move |this, cx| {
5394 if let Some(waiter) =
5395 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5396 {
5397 waiter.await?;
5398 }
5399 cx.update(|cx| {
5400 this.update(cx, |this, cx| {
5401 this.request_lsp(
5402 buffer.clone(),
5403 LanguageServerToQuery::FirstCapable,
5404 OnTypeFormatting {
5405 position,
5406 trigger,
5407 options,
5408 push_to_history,
5409 },
5410 cx,
5411 )
5412 })
5413 })??
5414 .await
5415 })
5416 }
5417
5418 pub fn definitions(
5419 &mut self,
5420 buffer: &Entity<Buffer>,
5421 position: PointUtf16,
5422 cx: &mut Context<Self>,
5423 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5424 if let Some((upstream_client, project_id)) = self.upstream_client() {
5425 let request = GetDefinitions { position };
5426 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5427 return Task::ready(Ok(None));
5428 }
5429 let request_task = upstream_client.request_lsp(
5430 project_id,
5431 None,
5432 LSP_REQUEST_TIMEOUT,
5433 cx.background_executor().clone(),
5434 request.to_proto(project_id, buffer.read(cx)),
5435 );
5436 let buffer = buffer.clone();
5437 cx.spawn(async move |weak_lsp_store, cx| {
5438 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5439 return Ok(None);
5440 };
5441 let Some(responses) = request_task.await? else {
5442 return Ok(None);
5443 };
5444 let actions = join_all(responses.payload.into_iter().map(|response| {
5445 GetDefinitions { position }.response_from_proto(
5446 response.response,
5447 lsp_store.clone(),
5448 buffer.clone(),
5449 cx.clone(),
5450 )
5451 }))
5452 .await;
5453
5454 Ok(Some(
5455 actions
5456 .into_iter()
5457 .collect::<Result<Vec<Vec<_>>>>()?
5458 .into_iter()
5459 .flatten()
5460 .dedup()
5461 .collect(),
5462 ))
5463 })
5464 } else {
5465 let definitions_task = self.request_multiple_lsp_locally(
5466 buffer,
5467 Some(position),
5468 GetDefinitions { position },
5469 cx,
5470 );
5471 cx.background_spawn(async move {
5472 Ok(Some(
5473 definitions_task
5474 .await
5475 .into_iter()
5476 .flat_map(|(_, definitions)| definitions)
5477 .dedup()
5478 .collect(),
5479 ))
5480 })
5481 }
5482 }
5483
5484 pub fn declarations(
5485 &mut self,
5486 buffer: &Entity<Buffer>,
5487 position: PointUtf16,
5488 cx: &mut Context<Self>,
5489 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5490 if let Some((upstream_client, project_id)) = self.upstream_client() {
5491 let request = GetDeclarations { position };
5492 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5493 return Task::ready(Ok(None));
5494 }
5495 let request_task = upstream_client.request_lsp(
5496 project_id,
5497 None,
5498 LSP_REQUEST_TIMEOUT,
5499 cx.background_executor().clone(),
5500 request.to_proto(project_id, buffer.read(cx)),
5501 );
5502 let buffer = buffer.clone();
5503 cx.spawn(async move |weak_lsp_store, cx| {
5504 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5505 return Ok(None);
5506 };
5507 let Some(responses) = request_task.await? else {
5508 return Ok(None);
5509 };
5510 let actions = join_all(responses.payload.into_iter().map(|response| {
5511 GetDeclarations { position }.response_from_proto(
5512 response.response,
5513 lsp_store.clone(),
5514 buffer.clone(),
5515 cx.clone(),
5516 )
5517 }))
5518 .await;
5519
5520 Ok(Some(
5521 actions
5522 .into_iter()
5523 .collect::<Result<Vec<Vec<_>>>>()?
5524 .into_iter()
5525 .flatten()
5526 .dedup()
5527 .collect(),
5528 ))
5529 })
5530 } else {
5531 let declarations_task = self.request_multiple_lsp_locally(
5532 buffer,
5533 Some(position),
5534 GetDeclarations { position },
5535 cx,
5536 );
5537 cx.background_spawn(async move {
5538 Ok(Some(
5539 declarations_task
5540 .await
5541 .into_iter()
5542 .flat_map(|(_, declarations)| declarations)
5543 .dedup()
5544 .collect(),
5545 ))
5546 })
5547 }
5548 }
5549
5550 pub fn type_definitions(
5551 &mut self,
5552 buffer: &Entity<Buffer>,
5553 position: PointUtf16,
5554 cx: &mut Context<Self>,
5555 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5556 if let Some((upstream_client, project_id)) = self.upstream_client() {
5557 let request = GetTypeDefinitions { position };
5558 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5559 return Task::ready(Ok(None));
5560 }
5561 let request_task = upstream_client.request_lsp(
5562 project_id,
5563 None,
5564 LSP_REQUEST_TIMEOUT,
5565 cx.background_executor().clone(),
5566 request.to_proto(project_id, buffer.read(cx)),
5567 );
5568 let buffer = buffer.clone();
5569 cx.spawn(async move |weak_lsp_store, cx| {
5570 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5571 return Ok(None);
5572 };
5573 let Some(responses) = request_task.await? else {
5574 return Ok(None);
5575 };
5576 let actions = join_all(responses.payload.into_iter().map(|response| {
5577 GetTypeDefinitions { position }.response_from_proto(
5578 response.response,
5579 lsp_store.clone(),
5580 buffer.clone(),
5581 cx.clone(),
5582 )
5583 }))
5584 .await;
5585
5586 Ok(Some(
5587 actions
5588 .into_iter()
5589 .collect::<Result<Vec<Vec<_>>>>()?
5590 .into_iter()
5591 .flatten()
5592 .dedup()
5593 .collect(),
5594 ))
5595 })
5596 } else {
5597 let type_definitions_task = self.request_multiple_lsp_locally(
5598 buffer,
5599 Some(position),
5600 GetTypeDefinitions { position },
5601 cx,
5602 );
5603 cx.background_spawn(async move {
5604 Ok(Some(
5605 type_definitions_task
5606 .await
5607 .into_iter()
5608 .flat_map(|(_, type_definitions)| type_definitions)
5609 .dedup()
5610 .collect(),
5611 ))
5612 })
5613 }
5614 }
5615
5616 pub fn implementations(
5617 &mut self,
5618 buffer: &Entity<Buffer>,
5619 position: PointUtf16,
5620 cx: &mut Context<Self>,
5621 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5622 if let Some((upstream_client, project_id)) = self.upstream_client() {
5623 let request = GetImplementations { position };
5624 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5625 return Task::ready(Ok(None));
5626 }
5627 let request_task = upstream_client.request_lsp(
5628 project_id,
5629 None,
5630 LSP_REQUEST_TIMEOUT,
5631 cx.background_executor().clone(),
5632 request.to_proto(project_id, buffer.read(cx)),
5633 );
5634 let buffer = buffer.clone();
5635 cx.spawn(async move |weak_lsp_store, cx| {
5636 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5637 return Ok(None);
5638 };
5639 let Some(responses) = request_task.await? else {
5640 return Ok(None);
5641 };
5642 let actions = join_all(responses.payload.into_iter().map(|response| {
5643 GetImplementations { position }.response_from_proto(
5644 response.response,
5645 lsp_store.clone(),
5646 buffer.clone(),
5647 cx.clone(),
5648 )
5649 }))
5650 .await;
5651
5652 Ok(Some(
5653 actions
5654 .into_iter()
5655 .collect::<Result<Vec<Vec<_>>>>()?
5656 .into_iter()
5657 .flatten()
5658 .dedup()
5659 .collect(),
5660 ))
5661 })
5662 } else {
5663 let implementations_task = self.request_multiple_lsp_locally(
5664 buffer,
5665 Some(position),
5666 GetImplementations { position },
5667 cx,
5668 );
5669 cx.background_spawn(async move {
5670 Ok(Some(
5671 implementations_task
5672 .await
5673 .into_iter()
5674 .flat_map(|(_, implementations)| implementations)
5675 .dedup()
5676 .collect(),
5677 ))
5678 })
5679 }
5680 }
5681
5682 pub fn references(
5683 &mut self,
5684 buffer: &Entity<Buffer>,
5685 position: PointUtf16,
5686 cx: &mut Context<Self>,
5687 ) -> Task<Result<Option<Vec<Location>>>> {
5688 if let Some((upstream_client, project_id)) = self.upstream_client() {
5689 let request = GetReferences { position };
5690 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5691 return Task::ready(Ok(None));
5692 }
5693
5694 let request_task = upstream_client.request_lsp(
5695 project_id,
5696 None,
5697 LSP_REQUEST_TIMEOUT,
5698 cx.background_executor().clone(),
5699 request.to_proto(project_id, buffer.read(cx)),
5700 );
5701 let buffer = buffer.clone();
5702 cx.spawn(async move |weak_lsp_store, cx| {
5703 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5704 return Ok(None);
5705 };
5706 let Some(responses) = request_task.await? else {
5707 return Ok(None);
5708 };
5709
5710 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5711 GetReferences { position }.response_from_proto(
5712 lsp_response.response,
5713 lsp_store.clone(),
5714 buffer.clone(),
5715 cx.clone(),
5716 )
5717 }))
5718 .await
5719 .into_iter()
5720 .collect::<Result<Vec<Vec<_>>>>()?
5721 .into_iter()
5722 .flatten()
5723 .dedup()
5724 .collect();
5725 Ok(Some(locations))
5726 })
5727 } else {
5728 let references_task = self.request_multiple_lsp_locally(
5729 buffer,
5730 Some(position),
5731 GetReferences { position },
5732 cx,
5733 );
5734 cx.background_spawn(async move {
5735 Ok(Some(
5736 references_task
5737 .await
5738 .into_iter()
5739 .flat_map(|(_, references)| references)
5740 .dedup()
5741 .collect(),
5742 ))
5743 })
5744 }
5745 }
5746
5747 pub fn code_actions(
5748 &mut self,
5749 buffer: &Entity<Buffer>,
5750 range: Range<Anchor>,
5751 kinds: Option<Vec<CodeActionKind>>,
5752 cx: &mut Context<Self>,
5753 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5754 if let Some((upstream_client, project_id)) = self.upstream_client() {
5755 let request = GetCodeActions {
5756 range: range.clone(),
5757 kinds: kinds.clone(),
5758 };
5759 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5760 return Task::ready(Ok(None));
5761 }
5762 let request_task = upstream_client.request_lsp(
5763 project_id,
5764 None,
5765 LSP_REQUEST_TIMEOUT,
5766 cx.background_executor().clone(),
5767 request.to_proto(project_id, buffer.read(cx)),
5768 );
5769 let buffer = buffer.clone();
5770 cx.spawn(async move |weak_lsp_store, cx| {
5771 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5772 return Ok(None);
5773 };
5774 let Some(responses) = request_task.await? else {
5775 return Ok(None);
5776 };
5777 let actions = join_all(responses.payload.into_iter().map(|response| {
5778 GetCodeActions {
5779 range: range.clone(),
5780 kinds: kinds.clone(),
5781 }
5782 .response_from_proto(
5783 response.response,
5784 lsp_store.clone(),
5785 buffer.clone(),
5786 cx.clone(),
5787 )
5788 }))
5789 .await;
5790
5791 Ok(Some(
5792 actions
5793 .into_iter()
5794 .collect::<Result<Vec<Vec<_>>>>()?
5795 .into_iter()
5796 .flatten()
5797 .collect(),
5798 ))
5799 })
5800 } else {
5801 let all_actions_task = self.request_multiple_lsp_locally(
5802 buffer,
5803 Some(range.start),
5804 GetCodeActions { range, kinds },
5805 cx,
5806 );
5807 cx.background_spawn(async move {
5808 Ok(Some(
5809 all_actions_task
5810 .await
5811 .into_iter()
5812 .flat_map(|(_, actions)| actions)
5813 .collect(),
5814 ))
5815 })
5816 }
5817 }
5818
5819 pub fn code_lens_actions(
5820 &mut self,
5821 buffer: &Entity<Buffer>,
5822 cx: &mut Context<Self>,
5823 ) -> CodeLensTask {
5824 let version_queried_for = buffer.read(cx).version();
5825 let buffer_id = buffer.read(cx).remote_id();
5826 let existing_servers = self.as_local().map(|local| {
5827 local
5828 .buffers_opened_in_servers
5829 .get(&buffer_id)
5830 .cloned()
5831 .unwrap_or_default()
5832 });
5833
5834 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5835 if let Some(cached_lens) = &lsp_data.code_lens {
5836 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5837 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5838 existing_servers != cached_lens.lens.keys().copied().collect()
5839 });
5840 if !has_different_servers {
5841 return Task::ready(Ok(Some(
5842 cached_lens.lens.values().flatten().cloned().collect(),
5843 )))
5844 .shared();
5845 }
5846 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5847 if !version_queried_for.changed_since(updating_for) {
5848 return running_update.clone();
5849 }
5850 }
5851 }
5852 }
5853
5854 let lens_lsp_data = self
5855 .latest_lsp_data(buffer, cx)
5856 .code_lens
5857 .get_or_insert_default();
5858 let buffer = buffer.clone();
5859 let query_version_queried_for = version_queried_for.clone();
5860 let new_task = cx
5861 .spawn(async move |lsp_store, cx| {
5862 cx.background_executor()
5863 .timer(Duration::from_millis(30))
5864 .await;
5865 let fetched_lens = lsp_store
5866 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5867 .map_err(Arc::new)?
5868 .await
5869 .context("fetching code lens")
5870 .map_err(Arc::new);
5871 let fetched_lens = match fetched_lens {
5872 Ok(fetched_lens) => fetched_lens,
5873 Err(e) => {
5874 lsp_store
5875 .update(cx, |lsp_store, _| {
5876 if let Some(lens_lsp_data) = lsp_store
5877 .lsp_data
5878 .get_mut(&buffer_id)
5879 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5880 {
5881 lens_lsp_data.update = None;
5882 }
5883 })
5884 .ok();
5885 return Err(e);
5886 }
5887 };
5888
5889 lsp_store
5890 .update(cx, |lsp_store, _| {
5891 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5892 let code_lens = lsp_data.code_lens.as_mut()?;
5893 if let Some(fetched_lens) = fetched_lens {
5894 if lsp_data.buffer_version == query_version_queried_for {
5895 code_lens.lens.extend(fetched_lens);
5896 } else if !lsp_data
5897 .buffer_version
5898 .changed_since(&query_version_queried_for)
5899 {
5900 lsp_data.buffer_version = query_version_queried_for;
5901 code_lens.lens = fetched_lens;
5902 }
5903 }
5904 code_lens.update = None;
5905 Some(code_lens.lens.values().flatten().cloned().collect())
5906 })
5907 .map_err(Arc::new)
5908 })
5909 .shared();
5910 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5911 new_task
5912 }
5913
5914 fn fetch_code_lens(
5915 &mut self,
5916 buffer: &Entity<Buffer>,
5917 cx: &mut Context<Self>,
5918 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5919 if let Some((upstream_client, project_id)) = self.upstream_client() {
5920 let request = GetCodeLens;
5921 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5922 return Task::ready(Ok(None));
5923 }
5924 let request_task = upstream_client.request_lsp(
5925 project_id,
5926 None,
5927 LSP_REQUEST_TIMEOUT,
5928 cx.background_executor().clone(),
5929 request.to_proto(project_id, buffer.read(cx)),
5930 );
5931 let buffer = buffer.clone();
5932 cx.spawn(async move |weak_lsp_store, cx| {
5933 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5934 return Ok(None);
5935 };
5936 let Some(responses) = request_task.await? else {
5937 return Ok(None);
5938 };
5939
5940 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5941 let lsp_store = lsp_store.clone();
5942 let buffer = buffer.clone();
5943 let cx = cx.clone();
5944 async move {
5945 (
5946 LanguageServerId::from_proto(response.server_id),
5947 GetCodeLens
5948 .response_from_proto(response.response, lsp_store, buffer, cx)
5949 .await,
5950 )
5951 }
5952 }))
5953 .await;
5954
5955 let mut has_errors = false;
5956 let code_lens_actions = code_lens_actions
5957 .into_iter()
5958 .filter_map(|(server_id, code_lens)| match code_lens {
5959 Ok(code_lens) => Some((server_id, code_lens)),
5960 Err(e) => {
5961 has_errors = true;
5962 log::error!("{e:#}");
5963 None
5964 }
5965 })
5966 .collect::<HashMap<_, _>>();
5967 anyhow::ensure!(
5968 !has_errors || !code_lens_actions.is_empty(),
5969 "Failed to fetch code lens"
5970 );
5971 Ok(Some(code_lens_actions))
5972 })
5973 } else {
5974 let code_lens_actions_task =
5975 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5976 cx.background_spawn(async move {
5977 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5978 })
5979 }
5980 }
5981
5982 #[inline(never)]
5983 pub fn completions(
5984 &self,
5985 buffer: &Entity<Buffer>,
5986 position: PointUtf16,
5987 context: CompletionContext,
5988 cx: &mut Context<Self>,
5989 ) -> Task<Result<Vec<CompletionResponse>>> {
5990 let language_registry = self.languages.clone();
5991
5992 if let Some((upstream_client, project_id)) = self.upstream_client() {
5993 let snapshot = buffer.read(cx).snapshot();
5994 let offset = position.to_offset(&snapshot);
5995 let scope = snapshot.language_scope_at(offset);
5996 let capable_lsps = self.all_capable_for_proto_request(
5997 buffer,
5998 |server_name, capabilities| {
5999 capabilities.completion_provider.is_some()
6000 && scope
6001 .as_ref()
6002 .map(|scope| scope.language_allowed(server_name))
6003 .unwrap_or(true)
6004 },
6005 cx,
6006 );
6007 if capable_lsps.is_empty() {
6008 return Task::ready(Ok(Vec::new()));
6009 }
6010
6011 let language = buffer.read(cx).language().cloned();
6012
6013 // In the future, we should provide project guests with the names of LSP adapters,
6014 // so that they can use the correct LSP adapter when computing labels. For now,
6015 // guests just use the first LSP adapter associated with the buffer's language.
6016 let lsp_adapter = language.as_ref().and_then(|language| {
6017 language_registry
6018 .lsp_adapters(&language.name())
6019 .first()
6020 .cloned()
6021 });
6022
6023 let buffer = buffer.clone();
6024
6025 cx.spawn(async move |this, cx| {
6026 let requests = join_all(
6027 capable_lsps
6028 .into_iter()
6029 .map(|id| {
6030 let request = GetCompletions {
6031 position,
6032 context: context.clone(),
6033 server_id: Some(id),
6034 };
6035 let buffer = buffer.clone();
6036 let language = language.clone();
6037 let lsp_adapter = lsp_adapter.clone();
6038 let upstream_client = upstream_client.clone();
6039 let response = this
6040 .update(cx, |this, cx| {
6041 this.send_lsp_proto_request(
6042 buffer,
6043 upstream_client,
6044 project_id,
6045 request,
6046 cx,
6047 )
6048 })
6049 .log_err();
6050 async move {
6051 let response = response?.await.log_err()?;
6052
6053 let completions = populate_labels_for_completions(
6054 response.completions,
6055 language,
6056 lsp_adapter,
6057 )
6058 .await;
6059
6060 Some(CompletionResponse {
6061 completions,
6062 display_options: CompletionDisplayOptions::default(),
6063 is_incomplete: response.is_incomplete,
6064 })
6065 }
6066 })
6067 .collect::<Vec<_>>(),
6068 );
6069 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6070 })
6071 } else if let Some(local) = self.as_local() {
6072 let snapshot = buffer.read(cx).snapshot();
6073 let offset = position.to_offset(&snapshot);
6074 let scope = snapshot.language_scope_at(offset);
6075 let language = snapshot.language().cloned();
6076 let completion_settings = language_settings(
6077 language.as_ref().map(|language| language.name()),
6078 buffer.read(cx).file(),
6079 cx,
6080 )
6081 .completions
6082 .clone();
6083 if !completion_settings.lsp {
6084 return Task::ready(Ok(Vec::new()));
6085 }
6086
6087 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6088 local
6089 .language_servers_for_buffer(buffer, cx)
6090 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6091 .filter(|(adapter, _)| {
6092 scope
6093 .as_ref()
6094 .map(|scope| scope.language_allowed(&adapter.name))
6095 .unwrap_or(true)
6096 })
6097 .map(|(_, server)| server.server_id())
6098 .collect()
6099 });
6100
6101 let buffer = buffer.clone();
6102 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6103 let lsp_timeout = if lsp_timeout > 0 {
6104 Some(Duration::from_millis(lsp_timeout))
6105 } else {
6106 None
6107 };
6108 cx.spawn(async move |this, cx| {
6109 let mut tasks = Vec::with_capacity(server_ids.len());
6110 this.update(cx, |lsp_store, cx| {
6111 for server_id in server_ids {
6112 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6113 let lsp_timeout = lsp_timeout
6114 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6115 let mut timeout = cx.background_spawn(async move {
6116 match lsp_timeout {
6117 Some(lsp_timeout) => {
6118 lsp_timeout.await;
6119 true
6120 },
6121 None => false,
6122 }
6123 }).fuse();
6124 let mut lsp_request = lsp_store.request_lsp(
6125 buffer.clone(),
6126 LanguageServerToQuery::Other(server_id),
6127 GetCompletions {
6128 position,
6129 context: context.clone(),
6130 server_id: Some(server_id),
6131 },
6132 cx,
6133 ).fuse();
6134 let new_task = cx.background_spawn(async move {
6135 select_biased! {
6136 response = lsp_request => anyhow::Ok(Some(response?)),
6137 timeout_happened = timeout => {
6138 if timeout_happened {
6139 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6140 Ok(None)
6141 } else {
6142 let completions = lsp_request.await?;
6143 Ok(Some(completions))
6144 }
6145 },
6146 }
6147 });
6148 tasks.push((lsp_adapter, new_task));
6149 }
6150 })?;
6151
6152 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6153 let completion_response = task.await.ok()??;
6154 let completions = populate_labels_for_completions(
6155 completion_response.completions,
6156 language.clone(),
6157 lsp_adapter,
6158 )
6159 .await;
6160 Some(CompletionResponse {
6161 completions,
6162 display_options: CompletionDisplayOptions::default(),
6163 is_incomplete: completion_response.is_incomplete,
6164 })
6165 });
6166
6167 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6168
6169 Ok(responses.into_iter().flatten().collect())
6170 })
6171 } else {
6172 Task::ready(Err(anyhow!("No upstream client or local language server")))
6173 }
6174 }
6175
6176 pub fn resolve_completions(
6177 &self,
6178 buffer: Entity<Buffer>,
6179 completion_indices: Vec<usize>,
6180 completions: Rc<RefCell<Box<[Completion]>>>,
6181 cx: &mut Context<Self>,
6182 ) -> Task<Result<bool>> {
6183 let client = self.upstream_client();
6184 let buffer_id = buffer.read(cx).remote_id();
6185 let buffer_snapshot = buffer.read(cx).snapshot();
6186
6187 if !self.check_if_capable_for_proto_request(
6188 &buffer,
6189 GetCompletions::can_resolve_completions,
6190 cx,
6191 ) {
6192 return Task::ready(Ok(false));
6193 }
6194 cx.spawn(async move |lsp_store, cx| {
6195 let mut did_resolve = false;
6196 if let Some((client, project_id)) = client {
6197 for completion_index in completion_indices {
6198 let server_id = {
6199 let completion = &completions.borrow()[completion_index];
6200 completion.source.server_id()
6201 };
6202 if let Some(server_id) = server_id {
6203 if Self::resolve_completion_remote(
6204 project_id,
6205 server_id,
6206 buffer_id,
6207 completions.clone(),
6208 completion_index,
6209 client.clone(),
6210 )
6211 .await
6212 .log_err()
6213 .is_some()
6214 {
6215 did_resolve = true;
6216 }
6217 } else {
6218 resolve_word_completion(
6219 &buffer_snapshot,
6220 &mut completions.borrow_mut()[completion_index],
6221 );
6222 }
6223 }
6224 } else {
6225 for completion_index in completion_indices {
6226 let server_id = {
6227 let completion = &completions.borrow()[completion_index];
6228 completion.source.server_id()
6229 };
6230 if let Some(server_id) = server_id {
6231 let server_and_adapter = lsp_store
6232 .read_with(cx, |lsp_store, _| {
6233 let server = lsp_store.language_server_for_id(server_id)?;
6234 let adapter =
6235 lsp_store.language_server_adapter_for_id(server.server_id())?;
6236 Some((server, adapter))
6237 })
6238 .ok()
6239 .flatten();
6240 let Some((server, adapter)) = server_and_adapter else {
6241 continue;
6242 };
6243
6244 let resolved = Self::resolve_completion_local(
6245 server,
6246 completions.clone(),
6247 completion_index,
6248 )
6249 .await
6250 .log_err()
6251 .is_some();
6252 if resolved {
6253 Self::regenerate_completion_labels(
6254 adapter,
6255 &buffer_snapshot,
6256 completions.clone(),
6257 completion_index,
6258 )
6259 .await
6260 .log_err();
6261 did_resolve = true;
6262 }
6263 } else {
6264 resolve_word_completion(
6265 &buffer_snapshot,
6266 &mut completions.borrow_mut()[completion_index],
6267 );
6268 }
6269 }
6270 }
6271
6272 Ok(did_resolve)
6273 })
6274 }
6275
6276 async fn resolve_completion_local(
6277 server: Arc<lsp::LanguageServer>,
6278 completions: Rc<RefCell<Box<[Completion]>>>,
6279 completion_index: usize,
6280 ) -> Result<()> {
6281 let server_id = server.server_id();
6282 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6283 return Ok(());
6284 }
6285
6286 let request = {
6287 let completion = &completions.borrow()[completion_index];
6288 match &completion.source {
6289 CompletionSource::Lsp {
6290 lsp_completion,
6291 resolved,
6292 server_id: completion_server_id,
6293 ..
6294 } => {
6295 if *resolved {
6296 return Ok(());
6297 }
6298 anyhow::ensure!(
6299 server_id == *completion_server_id,
6300 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6301 );
6302 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6303 }
6304 CompletionSource::BufferWord { .. }
6305 | CompletionSource::Dap { .. }
6306 | CompletionSource::Custom => {
6307 return Ok(());
6308 }
6309 }
6310 };
6311 let resolved_completion = request
6312 .await
6313 .into_response()
6314 .context("resolve completion")?;
6315
6316 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6317 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6318
6319 let mut completions = completions.borrow_mut();
6320 let completion = &mut completions[completion_index];
6321 if let CompletionSource::Lsp {
6322 lsp_completion,
6323 resolved,
6324 server_id: completion_server_id,
6325 ..
6326 } = &mut completion.source
6327 {
6328 if *resolved {
6329 return Ok(());
6330 }
6331 anyhow::ensure!(
6332 server_id == *completion_server_id,
6333 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6334 );
6335 *lsp_completion = Box::new(resolved_completion);
6336 *resolved = true;
6337 }
6338 Ok(())
6339 }
6340
6341 async fn regenerate_completion_labels(
6342 adapter: Arc<CachedLspAdapter>,
6343 snapshot: &BufferSnapshot,
6344 completions: Rc<RefCell<Box<[Completion]>>>,
6345 completion_index: usize,
6346 ) -> Result<()> {
6347 let completion_item = completions.borrow()[completion_index]
6348 .source
6349 .lsp_completion(true)
6350 .map(Cow::into_owned);
6351 if let Some(lsp_documentation) = completion_item
6352 .as_ref()
6353 .and_then(|completion_item| completion_item.documentation.clone())
6354 {
6355 let mut completions = completions.borrow_mut();
6356 let completion = &mut completions[completion_index];
6357 completion.documentation = Some(lsp_documentation.into());
6358 } else {
6359 let mut completions = completions.borrow_mut();
6360 let completion = &mut completions[completion_index];
6361 completion.documentation = Some(CompletionDocumentation::Undocumented);
6362 }
6363
6364 let mut new_label = match completion_item {
6365 Some(completion_item) => {
6366 // 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
6367 // So we have to update the label here anyway...
6368 let language = snapshot.language();
6369 match language {
6370 Some(language) => {
6371 adapter
6372 .labels_for_completions(
6373 std::slice::from_ref(&completion_item),
6374 language,
6375 )
6376 .await?
6377 }
6378 None => Vec::new(),
6379 }
6380 .pop()
6381 .flatten()
6382 .unwrap_or_else(|| {
6383 CodeLabel::fallback_for_completion(
6384 &completion_item,
6385 language.map(|language| language.as_ref()),
6386 )
6387 })
6388 }
6389 None => CodeLabel::plain(
6390 completions.borrow()[completion_index].new_text.clone(),
6391 None,
6392 ),
6393 };
6394 ensure_uniform_list_compatible_label(&mut new_label);
6395
6396 let mut completions = completions.borrow_mut();
6397 let completion = &mut completions[completion_index];
6398 if completion.label.filter_text() == new_label.filter_text() {
6399 completion.label = new_label;
6400 } else {
6401 log::error!(
6402 "Resolved completion changed display label from {} to {}. \
6403 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6404 completion.label.text(),
6405 new_label.text(),
6406 completion.label.filter_text(),
6407 new_label.filter_text()
6408 );
6409 }
6410
6411 Ok(())
6412 }
6413
6414 async fn resolve_completion_remote(
6415 project_id: u64,
6416 server_id: LanguageServerId,
6417 buffer_id: BufferId,
6418 completions: Rc<RefCell<Box<[Completion]>>>,
6419 completion_index: usize,
6420 client: AnyProtoClient,
6421 ) -> Result<()> {
6422 let lsp_completion = {
6423 let completion = &completions.borrow()[completion_index];
6424 match &completion.source {
6425 CompletionSource::Lsp {
6426 lsp_completion,
6427 resolved,
6428 server_id: completion_server_id,
6429 ..
6430 } => {
6431 anyhow::ensure!(
6432 server_id == *completion_server_id,
6433 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6434 );
6435 if *resolved {
6436 return Ok(());
6437 }
6438 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6439 }
6440 CompletionSource::Custom
6441 | CompletionSource::Dap { .. }
6442 | CompletionSource::BufferWord { .. } => {
6443 return Ok(());
6444 }
6445 }
6446 };
6447 let request = proto::ResolveCompletionDocumentation {
6448 project_id,
6449 language_server_id: server_id.0 as u64,
6450 lsp_completion,
6451 buffer_id: buffer_id.into(),
6452 };
6453
6454 let response = client
6455 .request(request)
6456 .await
6457 .context("completion documentation resolve proto request")?;
6458 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6459
6460 let documentation = if response.documentation.is_empty() {
6461 CompletionDocumentation::Undocumented
6462 } else if response.documentation_is_markdown {
6463 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6464 } else if response.documentation.lines().count() <= 1 {
6465 CompletionDocumentation::SingleLine(response.documentation.into())
6466 } else {
6467 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6468 };
6469
6470 let mut completions = completions.borrow_mut();
6471 let completion = &mut completions[completion_index];
6472 completion.documentation = Some(documentation);
6473 if let CompletionSource::Lsp {
6474 insert_range,
6475 lsp_completion,
6476 resolved,
6477 server_id: completion_server_id,
6478 lsp_defaults: _,
6479 } = &mut completion.source
6480 {
6481 let completion_insert_range = response
6482 .old_insert_start
6483 .and_then(deserialize_anchor)
6484 .zip(response.old_insert_end.and_then(deserialize_anchor));
6485 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6486
6487 if *resolved {
6488 return Ok(());
6489 }
6490 anyhow::ensure!(
6491 server_id == *completion_server_id,
6492 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6493 );
6494 *lsp_completion = Box::new(resolved_lsp_completion);
6495 *resolved = true;
6496 }
6497
6498 let replace_range = response
6499 .old_replace_start
6500 .and_then(deserialize_anchor)
6501 .zip(response.old_replace_end.and_then(deserialize_anchor));
6502 if let Some((old_replace_start, old_replace_end)) = replace_range
6503 && !response.new_text.is_empty()
6504 {
6505 completion.new_text = response.new_text;
6506 completion.replace_range = old_replace_start..old_replace_end;
6507 }
6508
6509 Ok(())
6510 }
6511
6512 pub fn apply_additional_edits_for_completion(
6513 &self,
6514 buffer_handle: Entity<Buffer>,
6515 completions: Rc<RefCell<Box<[Completion]>>>,
6516 completion_index: usize,
6517 push_to_history: bool,
6518 cx: &mut Context<Self>,
6519 ) -> Task<Result<Option<Transaction>>> {
6520 if let Some((client, project_id)) = self.upstream_client() {
6521 let buffer = buffer_handle.read(cx);
6522 let buffer_id = buffer.remote_id();
6523 cx.spawn(async move |_, cx| {
6524 let request = {
6525 let completion = completions.borrow()[completion_index].clone();
6526 proto::ApplyCompletionAdditionalEdits {
6527 project_id,
6528 buffer_id: buffer_id.into(),
6529 completion: Some(Self::serialize_completion(&CoreCompletion {
6530 replace_range: completion.replace_range,
6531 new_text: completion.new_text,
6532 source: completion.source,
6533 })),
6534 }
6535 };
6536
6537 if let Some(transaction) = client.request(request).await?.transaction {
6538 let transaction = language::proto::deserialize_transaction(transaction)?;
6539 buffer_handle
6540 .update(cx, |buffer, _| {
6541 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6542 })?
6543 .await?;
6544 if push_to_history {
6545 buffer_handle.update(cx, |buffer, _| {
6546 buffer.push_transaction(transaction.clone(), Instant::now());
6547 buffer.finalize_last_transaction();
6548 })?;
6549 }
6550 Ok(Some(transaction))
6551 } else {
6552 Ok(None)
6553 }
6554 })
6555 } else {
6556 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6557 let completion = &completions.borrow()[completion_index];
6558 let server_id = completion.source.server_id()?;
6559 Some(
6560 self.language_server_for_local_buffer(buffer, server_id, cx)?
6561 .1
6562 .clone(),
6563 )
6564 }) else {
6565 return Task::ready(Ok(None));
6566 };
6567
6568 cx.spawn(async move |this, cx| {
6569 Self::resolve_completion_local(
6570 server.clone(),
6571 completions.clone(),
6572 completion_index,
6573 )
6574 .await
6575 .context("resolving completion")?;
6576 let completion = completions.borrow()[completion_index].clone();
6577 let additional_text_edits = completion
6578 .source
6579 .lsp_completion(true)
6580 .as_ref()
6581 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6582 if let Some(edits) = additional_text_edits {
6583 let edits = this
6584 .update(cx, |this, cx| {
6585 this.as_local_mut().unwrap().edits_from_lsp(
6586 &buffer_handle,
6587 edits,
6588 server.server_id(),
6589 None,
6590 cx,
6591 )
6592 })?
6593 .await?;
6594
6595 buffer_handle.update(cx, |buffer, cx| {
6596 buffer.finalize_last_transaction();
6597 buffer.start_transaction();
6598
6599 for (range, text) in edits {
6600 let primary = &completion.replace_range;
6601
6602 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6603 // and the primary completion is just an insertion (empty range), then this is likely
6604 // an auto-import scenario and should not be considered overlapping
6605 // https://github.com/zed-industries/zed/issues/26136
6606 let is_file_start_auto_import = {
6607 let snapshot = buffer.snapshot();
6608 let primary_start_point = primary.start.to_point(&snapshot);
6609 let range_start_point = range.start.to_point(&snapshot);
6610
6611 let result = primary_start_point.row == 0
6612 && primary_start_point.column == 0
6613 && range_start_point.row == 0
6614 && range_start_point.column == 0;
6615
6616 result
6617 };
6618
6619 let has_overlap = if is_file_start_auto_import {
6620 false
6621 } else {
6622 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6623 && primary.end.cmp(&range.start, buffer).is_ge();
6624 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6625 && range.end.cmp(&primary.end, buffer).is_ge();
6626 let result = start_within || end_within;
6627 result
6628 };
6629
6630 //Skip additional edits which overlap with the primary completion edit
6631 //https://github.com/zed-industries/zed/pull/1871
6632 if !has_overlap {
6633 buffer.edit([(range, text)], None, cx);
6634 }
6635 }
6636
6637 let transaction = if buffer.end_transaction(cx).is_some() {
6638 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6639 if !push_to_history {
6640 buffer.forget_transaction(transaction.id);
6641 }
6642 Some(transaction)
6643 } else {
6644 None
6645 };
6646 Ok(transaction)
6647 })?
6648 } else {
6649 Ok(None)
6650 }
6651 })
6652 }
6653 }
6654
6655 pub fn pull_diagnostics(
6656 &mut self,
6657 buffer: Entity<Buffer>,
6658 cx: &mut Context<Self>,
6659 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6660 let buffer_id = buffer.read(cx).remote_id();
6661
6662 if let Some((client, upstream_project_id)) = self.upstream_client() {
6663 let mut suitable_capabilities = None;
6664 // Are we capable for proto request?
6665 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6666 &buffer,
6667 |capabilities| {
6668 if let Some(caps) = &capabilities.diagnostic_provider {
6669 suitable_capabilities = Some(caps.clone());
6670 true
6671 } else {
6672 false
6673 }
6674 },
6675 cx,
6676 );
6677 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6678 let Some(dynamic_caps) = suitable_capabilities else {
6679 return Task::ready(Ok(None));
6680 };
6681 assert!(any_server_has_diagnostics_provider);
6682
6683 let request = GetDocumentDiagnostics {
6684 previous_result_id: None,
6685 dynamic_caps,
6686 };
6687 let request_task = client.request_lsp(
6688 upstream_project_id,
6689 None,
6690 LSP_REQUEST_TIMEOUT,
6691 cx.background_executor().clone(),
6692 request.to_proto(upstream_project_id, buffer.read(cx)),
6693 );
6694 cx.background_spawn(async move {
6695 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6696 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6697 // Do not attempt to further process the dummy responses here.
6698 let _response = request_task.await?;
6699 Ok(None)
6700 })
6701 } else {
6702 let servers = buffer.update(cx, |buffer, cx| {
6703 self.language_servers_for_local_buffer(buffer, cx)
6704 .map(|(_, server)| server.clone())
6705 .collect::<Vec<_>>()
6706 });
6707
6708 let pull_diagnostics = servers
6709 .into_iter()
6710 .flat_map(|server| {
6711 let result = maybe!({
6712 let local = self.as_local()?;
6713 let server_id = server.server_id();
6714 let providers_with_identifiers = local
6715 .language_server_dynamic_registrations
6716 .get(&server_id)
6717 .into_iter()
6718 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6719 .collect::<Vec<_>>();
6720 Some(
6721 providers_with_identifiers
6722 .into_iter()
6723 .map(|dynamic_caps| {
6724 let result_id = self.result_id(server_id, buffer_id, cx);
6725 self.request_lsp(
6726 buffer.clone(),
6727 LanguageServerToQuery::Other(server_id),
6728 GetDocumentDiagnostics {
6729 previous_result_id: result_id,
6730 dynamic_caps,
6731 },
6732 cx,
6733 )
6734 })
6735 .collect::<Vec<_>>(),
6736 )
6737 });
6738
6739 result.unwrap_or_default()
6740 })
6741 .collect::<Vec<_>>();
6742
6743 cx.background_spawn(async move {
6744 let mut responses = Vec::new();
6745 for diagnostics in join_all(pull_diagnostics).await {
6746 responses.extend(diagnostics?);
6747 }
6748 Ok(Some(responses))
6749 })
6750 }
6751 }
6752
6753 pub fn applicable_inlay_chunks(
6754 &mut self,
6755 buffer: &Entity<Buffer>,
6756 ranges: &[Range<text::Anchor>],
6757 cx: &mut Context<Self>,
6758 ) -> Vec<Range<BufferRow>> {
6759 self.latest_lsp_data(buffer, cx)
6760 .inlay_hints
6761 .applicable_chunks(ranges)
6762 .map(|chunk| chunk.row_range())
6763 .collect()
6764 }
6765
6766 pub fn invalidate_inlay_hints<'a>(
6767 &'a mut self,
6768 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6769 ) {
6770 for buffer_id in for_buffers {
6771 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6772 lsp_data.inlay_hints.clear();
6773 }
6774 }
6775 }
6776
6777 pub fn inlay_hints(
6778 &mut self,
6779 invalidate: InvalidationStrategy,
6780 buffer: Entity<Buffer>,
6781 ranges: Vec<Range<text::Anchor>>,
6782 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6783 cx: &mut Context<Self>,
6784 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6785 let next_hint_id = self.next_hint_id.clone();
6786 let lsp_data = self.latest_lsp_data(&buffer, cx);
6787 let query_version = lsp_data.buffer_version.clone();
6788 let mut lsp_refresh_requested = false;
6789 let for_server = if let InvalidationStrategy::RefreshRequested {
6790 server_id,
6791 request_id,
6792 } = invalidate
6793 {
6794 let invalidated = lsp_data
6795 .inlay_hints
6796 .invalidate_for_server_refresh(server_id, request_id);
6797 lsp_refresh_requested = invalidated;
6798 Some(server_id)
6799 } else {
6800 None
6801 };
6802 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6803 let known_chunks = known_chunks
6804 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6805 .map(|(_, known_chunks)| known_chunks)
6806 .unwrap_or_default();
6807
6808 let mut hint_fetch_tasks = Vec::new();
6809 let mut cached_inlay_hints = None;
6810 let mut ranges_to_query = None;
6811 let applicable_chunks = existing_inlay_hints
6812 .applicable_chunks(ranges.as_slice())
6813 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6814 .collect::<Vec<_>>();
6815 if applicable_chunks.is_empty() {
6816 return HashMap::default();
6817 }
6818
6819 for row_chunk in applicable_chunks {
6820 match (
6821 existing_inlay_hints
6822 .cached_hints(&row_chunk)
6823 .filter(|_| !lsp_refresh_requested)
6824 .cloned(),
6825 existing_inlay_hints
6826 .fetched_hints(&row_chunk)
6827 .as_ref()
6828 .filter(|_| !lsp_refresh_requested)
6829 .cloned(),
6830 ) {
6831 (None, None) => {
6832 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6833 continue;
6834 };
6835 ranges_to_query
6836 .get_or_insert_with(Vec::new)
6837 .push((row_chunk, chunk_range));
6838 }
6839 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6840 (Some(cached_hints), None) => {
6841 for (server_id, cached_hints) in cached_hints {
6842 if for_server.is_none_or(|for_server| for_server == server_id) {
6843 cached_inlay_hints
6844 .get_or_insert_with(HashMap::default)
6845 .entry(row_chunk.row_range())
6846 .or_insert_with(HashMap::default)
6847 .entry(server_id)
6848 .or_insert_with(Vec::new)
6849 .extend(cached_hints);
6850 }
6851 }
6852 }
6853 (Some(cached_hints), Some(fetched_hints)) => {
6854 hint_fetch_tasks.push((row_chunk, fetched_hints));
6855 for (server_id, cached_hints) in cached_hints {
6856 if for_server.is_none_or(|for_server| for_server == server_id) {
6857 cached_inlay_hints
6858 .get_or_insert_with(HashMap::default)
6859 .entry(row_chunk.row_range())
6860 .or_insert_with(HashMap::default)
6861 .entry(server_id)
6862 .or_insert_with(Vec::new)
6863 .extend(cached_hints);
6864 }
6865 }
6866 }
6867 }
6868 }
6869
6870 if hint_fetch_tasks.is_empty()
6871 && ranges_to_query
6872 .as_ref()
6873 .is_none_or(|ranges| ranges.is_empty())
6874 && let Some(cached_inlay_hints) = cached_inlay_hints
6875 {
6876 cached_inlay_hints
6877 .into_iter()
6878 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6879 .collect()
6880 } else {
6881 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6882 let next_hint_id = next_hint_id.clone();
6883 let buffer = buffer.clone();
6884 let query_version = query_version.clone();
6885 let new_inlay_hints = cx
6886 .spawn(async move |lsp_store, cx| {
6887 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6888 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6889 })?;
6890 new_fetch_task
6891 .await
6892 .and_then(|new_hints_by_server| {
6893 lsp_store.update(cx, |lsp_store, cx| {
6894 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6895 let update_cache = lsp_data.buffer_version == query_version;
6896 if new_hints_by_server.is_empty() {
6897 if update_cache {
6898 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6899 }
6900 HashMap::default()
6901 } else {
6902 new_hints_by_server
6903 .into_iter()
6904 .map(|(server_id, new_hints)| {
6905 let new_hints = new_hints
6906 .into_iter()
6907 .map(|new_hint| {
6908 (
6909 InlayId::Hint(next_hint_id.fetch_add(
6910 1,
6911 atomic::Ordering::AcqRel,
6912 )),
6913 new_hint,
6914 )
6915 })
6916 .collect::<Vec<_>>();
6917 if update_cache {
6918 lsp_data.inlay_hints.insert_new_hints(
6919 chunk,
6920 server_id,
6921 new_hints.clone(),
6922 );
6923 }
6924 (server_id, new_hints)
6925 })
6926 .collect()
6927 }
6928 })
6929 })
6930 .map_err(Arc::new)
6931 })
6932 .shared();
6933
6934 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6935 *fetch_task = Some(new_inlay_hints.clone());
6936 hint_fetch_tasks.push((chunk, new_inlay_hints));
6937 }
6938
6939 cached_inlay_hints
6940 .unwrap_or_default()
6941 .into_iter()
6942 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6943 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6944 (
6945 chunk.row_range(),
6946 cx.spawn(async move |_, _| {
6947 hints_fetch.await.map_err(|e| {
6948 if e.error_code() != ErrorCode::Internal {
6949 anyhow!(e.error_code())
6950 } else {
6951 anyhow!("{e:#}")
6952 }
6953 })
6954 }),
6955 )
6956 }))
6957 .collect()
6958 }
6959 }
6960
6961 fn fetch_inlay_hints(
6962 &mut self,
6963 for_server: Option<LanguageServerId>,
6964 buffer: &Entity<Buffer>,
6965 range: Range<Anchor>,
6966 cx: &mut Context<Self>,
6967 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6968 let request = InlayHints {
6969 range: range.clone(),
6970 };
6971 if let Some((upstream_client, project_id)) = self.upstream_client() {
6972 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6973 return Task::ready(Ok(HashMap::default()));
6974 }
6975 let request_task = upstream_client.request_lsp(
6976 project_id,
6977 for_server.map(|id| id.to_proto()),
6978 LSP_REQUEST_TIMEOUT,
6979 cx.background_executor().clone(),
6980 request.to_proto(project_id, buffer.read(cx)),
6981 );
6982 let buffer = buffer.clone();
6983 cx.spawn(async move |weak_lsp_store, cx| {
6984 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6985 return Ok(HashMap::default());
6986 };
6987 let Some(responses) = request_task.await? else {
6988 return Ok(HashMap::default());
6989 };
6990
6991 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6992 let lsp_store = lsp_store.clone();
6993 let buffer = buffer.clone();
6994 let cx = cx.clone();
6995 let request = request.clone();
6996 async move {
6997 (
6998 LanguageServerId::from_proto(response.server_id),
6999 request
7000 .response_from_proto(response.response, lsp_store, buffer, cx)
7001 .await,
7002 )
7003 }
7004 }))
7005 .await;
7006
7007 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7008 let mut has_errors = false;
7009 let inlay_hints = inlay_hints
7010 .into_iter()
7011 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7012 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7013 Err(e) => {
7014 has_errors = true;
7015 log::error!("{e:#}");
7016 None
7017 }
7018 })
7019 .map(|(server_id, mut new_hints)| {
7020 new_hints.retain(|hint| {
7021 hint.position.is_valid(&buffer_snapshot)
7022 && range.start.is_valid(&buffer_snapshot)
7023 && range.end.is_valid(&buffer_snapshot)
7024 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7025 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7026 });
7027 (server_id, new_hints)
7028 })
7029 .collect::<HashMap<_, _>>();
7030 anyhow::ensure!(
7031 !has_errors || !inlay_hints.is_empty(),
7032 "Failed to fetch inlay hints"
7033 );
7034 Ok(inlay_hints)
7035 })
7036 } else {
7037 let inlay_hints_task = match for_server {
7038 Some(server_id) => {
7039 let server_task = self.request_lsp(
7040 buffer.clone(),
7041 LanguageServerToQuery::Other(server_id),
7042 request,
7043 cx,
7044 );
7045 cx.background_spawn(async move {
7046 let mut responses = Vec::new();
7047 match server_task.await {
7048 Ok(response) => responses.push((server_id, response)),
7049 // rust-analyzer likes to error with this when its still loading up
7050 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7051 Err(e) => log::error!(
7052 "Error handling response for inlay hints request: {e:#}"
7053 ),
7054 }
7055 responses
7056 })
7057 }
7058 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7059 };
7060 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7061 cx.background_spawn(async move {
7062 Ok(inlay_hints_task
7063 .await
7064 .into_iter()
7065 .map(|(server_id, mut new_hints)| {
7066 new_hints.retain(|hint| {
7067 hint.position.is_valid(&buffer_snapshot)
7068 && range.start.is_valid(&buffer_snapshot)
7069 && range.end.is_valid(&buffer_snapshot)
7070 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7071 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7072 });
7073 (server_id, new_hints)
7074 })
7075 .collect())
7076 })
7077 }
7078 }
7079
7080 pub fn pull_diagnostics_for_buffer(
7081 &mut self,
7082 buffer: Entity<Buffer>,
7083 cx: &mut Context<Self>,
7084 ) -> Task<anyhow::Result<()>> {
7085 let diagnostics = self.pull_diagnostics(buffer, cx);
7086 cx.spawn(async move |lsp_store, cx| {
7087 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7088 return Ok(());
7089 };
7090 lsp_store.update(cx, |lsp_store, cx| {
7091 if lsp_store.as_local().is_none() {
7092 return;
7093 }
7094
7095 let mut unchanged_buffers = HashSet::default();
7096 let mut changed_buffers = HashSet::default();
7097 let server_diagnostics_updates = diagnostics
7098 .into_iter()
7099 .filter_map(|diagnostics_set| match diagnostics_set {
7100 LspPullDiagnostics::Response {
7101 server_id,
7102 uri,
7103 diagnostics,
7104 } => Some((server_id, uri, diagnostics)),
7105 LspPullDiagnostics::Default => None,
7106 })
7107 .fold(
7108 HashMap::default(),
7109 |mut acc, (server_id, uri, diagnostics)| {
7110 let (result_id, diagnostics) = match diagnostics {
7111 PulledDiagnostics::Unchanged { result_id } => {
7112 unchanged_buffers.insert(uri.clone());
7113 (Some(result_id), Vec::new())
7114 }
7115 PulledDiagnostics::Changed {
7116 result_id,
7117 diagnostics,
7118 } => {
7119 changed_buffers.insert(uri.clone());
7120 (result_id, diagnostics)
7121 }
7122 };
7123 let disk_based_sources = Cow::Owned(
7124 lsp_store
7125 .language_server_adapter_for_id(server_id)
7126 .as_ref()
7127 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7128 .unwrap_or(&[])
7129 .to_vec(),
7130 );
7131 acc.entry(server_id).or_insert_with(Vec::new).push(
7132 DocumentDiagnosticsUpdate {
7133 server_id,
7134 diagnostics: lsp::PublishDiagnosticsParams {
7135 uri,
7136 diagnostics,
7137 version: None,
7138 },
7139 result_id,
7140 disk_based_sources,
7141 },
7142 );
7143 acc
7144 },
7145 );
7146
7147 for diagnostic_updates in server_diagnostics_updates.into_values() {
7148 lsp_store
7149 .merge_lsp_diagnostics(
7150 DiagnosticSourceKind::Pulled,
7151 diagnostic_updates,
7152 |buffer, old_diagnostic, cx| {
7153 File::from_dyn(buffer.file())
7154 .and_then(|file| {
7155 let abs_path = file.as_local()?.abs_path(cx);
7156 lsp::Uri::from_file_path(abs_path).ok()
7157 })
7158 .is_none_or(|buffer_uri| {
7159 unchanged_buffers.contains(&buffer_uri)
7160 || match old_diagnostic.source_kind {
7161 DiagnosticSourceKind::Pulled => {
7162 !changed_buffers.contains(&buffer_uri)
7163 }
7164 DiagnosticSourceKind::Other
7165 | DiagnosticSourceKind::Pushed => true,
7166 }
7167 })
7168 },
7169 cx,
7170 )
7171 .log_err();
7172 }
7173 })
7174 })
7175 }
7176
7177 pub fn document_colors(
7178 &mut self,
7179 known_cache_version: Option<usize>,
7180 buffer: Entity<Buffer>,
7181 cx: &mut Context<Self>,
7182 ) -> Option<DocumentColorTask> {
7183 let version_queried_for = buffer.read(cx).version();
7184 let buffer_id = buffer.read(cx).remote_id();
7185
7186 let current_language_servers = self.as_local().map(|local| {
7187 local
7188 .buffers_opened_in_servers
7189 .get(&buffer_id)
7190 .cloned()
7191 .unwrap_or_default()
7192 });
7193
7194 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7195 if let Some(cached_colors) = &lsp_data.document_colors {
7196 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7197 let has_different_servers =
7198 current_language_servers.is_some_and(|current_language_servers| {
7199 current_language_servers
7200 != cached_colors.colors.keys().copied().collect()
7201 });
7202 if !has_different_servers {
7203 let cache_version = cached_colors.cache_version;
7204 if Some(cache_version) == known_cache_version {
7205 return None;
7206 } else {
7207 return Some(
7208 Task::ready(Ok(DocumentColors {
7209 colors: cached_colors
7210 .colors
7211 .values()
7212 .flatten()
7213 .cloned()
7214 .collect(),
7215 cache_version: Some(cache_version),
7216 }))
7217 .shared(),
7218 );
7219 }
7220 }
7221 }
7222 }
7223 }
7224
7225 let color_lsp_data = self
7226 .latest_lsp_data(&buffer, cx)
7227 .document_colors
7228 .get_or_insert_default();
7229 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7230 && !version_queried_for.changed_since(updating_for)
7231 {
7232 return Some(running_update.clone());
7233 }
7234 let buffer_version_queried_for = version_queried_for.clone();
7235 let new_task = cx
7236 .spawn(async move |lsp_store, cx| {
7237 cx.background_executor()
7238 .timer(Duration::from_millis(30))
7239 .await;
7240 let fetched_colors = lsp_store
7241 .update(cx, |lsp_store, cx| {
7242 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7243 })?
7244 .await
7245 .context("fetching document colors")
7246 .map_err(Arc::new);
7247 let fetched_colors = match fetched_colors {
7248 Ok(fetched_colors) => {
7249 if Some(true)
7250 == buffer
7251 .update(cx, |buffer, _| {
7252 buffer.version() != buffer_version_queried_for
7253 })
7254 .ok()
7255 {
7256 return Ok(DocumentColors::default());
7257 }
7258 fetched_colors
7259 }
7260 Err(e) => {
7261 lsp_store
7262 .update(cx, |lsp_store, _| {
7263 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7264 if let Some(document_colors) = &mut lsp_data.document_colors {
7265 document_colors.colors_update = None;
7266 }
7267 }
7268 })
7269 .ok();
7270 return Err(e);
7271 }
7272 };
7273
7274 lsp_store
7275 .update(cx, |lsp_store, cx| {
7276 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7277 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7278
7279 if let Some(fetched_colors) = fetched_colors {
7280 if lsp_data.buffer_version == buffer_version_queried_for {
7281 lsp_colors.colors.extend(fetched_colors);
7282 lsp_colors.cache_version += 1;
7283 } else if !lsp_data
7284 .buffer_version
7285 .changed_since(&buffer_version_queried_for)
7286 {
7287 lsp_data.buffer_version = buffer_version_queried_for;
7288 lsp_colors.colors = fetched_colors;
7289 lsp_colors.cache_version += 1;
7290 }
7291 }
7292 lsp_colors.colors_update = None;
7293 let colors = lsp_colors
7294 .colors
7295 .values()
7296 .flatten()
7297 .cloned()
7298 .collect::<HashSet<_>>();
7299 DocumentColors {
7300 colors,
7301 cache_version: Some(lsp_colors.cache_version),
7302 }
7303 })
7304 .map_err(Arc::new)
7305 })
7306 .shared();
7307 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7308 Some(new_task)
7309 }
7310
7311 fn fetch_document_colors_for_buffer(
7312 &mut self,
7313 buffer: &Entity<Buffer>,
7314 cx: &mut Context<Self>,
7315 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7316 if let Some((client, project_id)) = self.upstream_client() {
7317 let request = GetDocumentColor {};
7318 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7319 return Task::ready(Ok(None));
7320 }
7321
7322 let request_task = client.request_lsp(
7323 project_id,
7324 None,
7325 LSP_REQUEST_TIMEOUT,
7326 cx.background_executor().clone(),
7327 request.to_proto(project_id, buffer.read(cx)),
7328 );
7329 let buffer = buffer.clone();
7330 cx.spawn(async move |lsp_store, cx| {
7331 let Some(lsp_store) = lsp_store.upgrade() else {
7332 return Ok(None);
7333 };
7334 let colors = join_all(
7335 request_task
7336 .await
7337 .log_err()
7338 .flatten()
7339 .map(|response| response.payload)
7340 .unwrap_or_default()
7341 .into_iter()
7342 .map(|color_response| {
7343 let response = request.response_from_proto(
7344 color_response.response,
7345 lsp_store.clone(),
7346 buffer.clone(),
7347 cx.clone(),
7348 );
7349 async move {
7350 (
7351 LanguageServerId::from_proto(color_response.server_id),
7352 response.await.log_err().unwrap_or_default(),
7353 )
7354 }
7355 }),
7356 )
7357 .await
7358 .into_iter()
7359 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7360 acc.entry(server_id)
7361 .or_insert_with(HashSet::default)
7362 .extend(colors);
7363 acc
7364 });
7365 Ok(Some(colors))
7366 })
7367 } else {
7368 let document_colors_task =
7369 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7370 cx.background_spawn(async move {
7371 Ok(Some(
7372 document_colors_task
7373 .await
7374 .into_iter()
7375 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7376 acc.entry(server_id)
7377 .or_insert_with(HashSet::default)
7378 .extend(colors);
7379 acc
7380 })
7381 .into_iter()
7382 .collect(),
7383 ))
7384 })
7385 }
7386 }
7387
7388 pub fn signature_help<T: ToPointUtf16>(
7389 &mut self,
7390 buffer: &Entity<Buffer>,
7391 position: T,
7392 cx: &mut Context<Self>,
7393 ) -> Task<Option<Vec<SignatureHelp>>> {
7394 let position = position.to_point_utf16(buffer.read(cx));
7395
7396 if let Some((client, upstream_project_id)) = self.upstream_client() {
7397 let request = GetSignatureHelp { position };
7398 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7399 return Task::ready(None);
7400 }
7401 let request_task = client.request_lsp(
7402 upstream_project_id,
7403 None,
7404 LSP_REQUEST_TIMEOUT,
7405 cx.background_executor().clone(),
7406 request.to_proto(upstream_project_id, buffer.read(cx)),
7407 );
7408 let buffer = buffer.clone();
7409 cx.spawn(async move |weak_lsp_store, cx| {
7410 let lsp_store = weak_lsp_store.upgrade()?;
7411 let signatures = join_all(
7412 request_task
7413 .await
7414 .log_err()
7415 .flatten()
7416 .map(|response| response.payload)
7417 .unwrap_or_default()
7418 .into_iter()
7419 .map(|response| {
7420 let response = GetSignatureHelp { position }.response_from_proto(
7421 response.response,
7422 lsp_store.clone(),
7423 buffer.clone(),
7424 cx.clone(),
7425 );
7426 async move { response.await.log_err().flatten() }
7427 }),
7428 )
7429 .await
7430 .into_iter()
7431 .flatten()
7432 .collect();
7433 Some(signatures)
7434 })
7435 } else {
7436 let all_actions_task = self.request_multiple_lsp_locally(
7437 buffer,
7438 Some(position),
7439 GetSignatureHelp { position },
7440 cx,
7441 );
7442 cx.background_spawn(async move {
7443 Some(
7444 all_actions_task
7445 .await
7446 .into_iter()
7447 .flat_map(|(_, actions)| actions)
7448 .collect::<Vec<_>>(),
7449 )
7450 })
7451 }
7452 }
7453
7454 pub fn hover(
7455 &mut self,
7456 buffer: &Entity<Buffer>,
7457 position: PointUtf16,
7458 cx: &mut Context<Self>,
7459 ) -> Task<Option<Vec<Hover>>> {
7460 if let Some((client, upstream_project_id)) = self.upstream_client() {
7461 let request = GetHover { position };
7462 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7463 return Task::ready(None);
7464 }
7465 let request_task = client.request_lsp(
7466 upstream_project_id,
7467 None,
7468 LSP_REQUEST_TIMEOUT,
7469 cx.background_executor().clone(),
7470 request.to_proto(upstream_project_id, buffer.read(cx)),
7471 );
7472 let buffer = buffer.clone();
7473 cx.spawn(async move |weak_lsp_store, cx| {
7474 let lsp_store = weak_lsp_store.upgrade()?;
7475 let hovers = join_all(
7476 request_task
7477 .await
7478 .log_err()
7479 .flatten()
7480 .map(|response| response.payload)
7481 .unwrap_or_default()
7482 .into_iter()
7483 .map(|response| {
7484 let response = GetHover { position }.response_from_proto(
7485 response.response,
7486 lsp_store.clone(),
7487 buffer.clone(),
7488 cx.clone(),
7489 );
7490 async move {
7491 response
7492 .await
7493 .log_err()
7494 .flatten()
7495 .and_then(remove_empty_hover_blocks)
7496 }
7497 }),
7498 )
7499 .await
7500 .into_iter()
7501 .flatten()
7502 .collect();
7503 Some(hovers)
7504 })
7505 } else {
7506 let all_actions_task = self.request_multiple_lsp_locally(
7507 buffer,
7508 Some(position),
7509 GetHover { position },
7510 cx,
7511 );
7512 cx.background_spawn(async move {
7513 Some(
7514 all_actions_task
7515 .await
7516 .into_iter()
7517 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7518 .collect::<Vec<Hover>>(),
7519 )
7520 })
7521 }
7522 }
7523
7524 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7525 let language_registry = self.languages.clone();
7526
7527 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7528 let request = upstream_client.request(proto::GetProjectSymbols {
7529 project_id: *project_id,
7530 query: query.to_string(),
7531 });
7532 cx.foreground_executor().spawn(async move {
7533 let response = request.await?;
7534 let mut symbols = Vec::new();
7535 let core_symbols = response
7536 .symbols
7537 .into_iter()
7538 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7539 .collect::<Vec<_>>();
7540 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7541 .await;
7542 Ok(symbols)
7543 })
7544 } else if let Some(local) = self.as_local() {
7545 struct WorkspaceSymbolsResult {
7546 server_id: LanguageServerId,
7547 lsp_adapter: Arc<CachedLspAdapter>,
7548 worktree: WeakEntity<Worktree>,
7549 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7550 }
7551
7552 let mut requests = Vec::new();
7553 let mut requested_servers = BTreeSet::new();
7554 for (seed, state) in local.language_server_ids.iter() {
7555 let Some(worktree_handle) = self
7556 .worktree_store
7557 .read(cx)
7558 .worktree_for_id(seed.worktree_id, cx)
7559 else {
7560 continue;
7561 };
7562 let worktree = worktree_handle.read(cx);
7563 if !worktree.is_visible() {
7564 continue;
7565 }
7566
7567 if !requested_servers.insert(state.id) {
7568 continue;
7569 }
7570
7571 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7572 Some(LanguageServerState::Running {
7573 adapter, server, ..
7574 }) => (adapter.clone(), server),
7575
7576 _ => continue,
7577 };
7578 let supports_workspace_symbol_request =
7579 match server.capabilities().workspace_symbol_provider {
7580 Some(OneOf::Left(supported)) => supported,
7581 Some(OneOf::Right(_)) => true,
7582 None => false,
7583 };
7584 if !supports_workspace_symbol_request {
7585 continue;
7586 }
7587 let worktree_handle = worktree_handle.clone();
7588 let server_id = server.server_id();
7589 requests.push(
7590 server
7591 .request::<lsp::request::WorkspaceSymbolRequest>(
7592 lsp::WorkspaceSymbolParams {
7593 query: query.to_string(),
7594 ..Default::default()
7595 },
7596 )
7597 .map(move |response| {
7598 let lsp_symbols = response.into_response()
7599 .context("workspace symbols request")
7600 .log_err()
7601 .flatten()
7602 .map(|symbol_response| match symbol_response {
7603 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7604 flat_responses.into_iter().map(|lsp_symbol| {
7605 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7606 }).collect::<Vec<_>>()
7607 }
7608 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7609 nested_responses.into_iter().filter_map(|lsp_symbol| {
7610 let location = match lsp_symbol.location {
7611 OneOf::Left(location) => location,
7612 OneOf::Right(_) => {
7613 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7614 return None
7615 }
7616 };
7617 Some((lsp_symbol.name, lsp_symbol.kind, location))
7618 }).collect::<Vec<_>>()
7619 }
7620 }).unwrap_or_default();
7621
7622 WorkspaceSymbolsResult {
7623 server_id,
7624 lsp_adapter,
7625 worktree: worktree_handle.downgrade(),
7626 lsp_symbols,
7627 }
7628 }),
7629 );
7630 }
7631
7632 cx.spawn(async move |this, cx| {
7633 let responses = futures::future::join_all(requests).await;
7634 let this = match this.upgrade() {
7635 Some(this) => this,
7636 None => return Ok(Vec::new()),
7637 };
7638
7639 let mut symbols = Vec::new();
7640 for result in responses {
7641 let core_symbols = this.update(cx, |this, cx| {
7642 result
7643 .lsp_symbols
7644 .into_iter()
7645 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7646 let abs_path = symbol_location.uri.to_file_path().ok()?;
7647 let source_worktree = result.worktree.upgrade()?;
7648 let source_worktree_id = source_worktree.read(cx).id();
7649
7650 let path = if let Some((tree, rel_path)) =
7651 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7652 {
7653 let worktree_id = tree.read(cx).id();
7654 SymbolLocation::InProject(ProjectPath {
7655 worktree_id,
7656 path: rel_path,
7657 })
7658 } else {
7659 SymbolLocation::OutsideProject {
7660 signature: this.symbol_signature(&abs_path),
7661 abs_path: abs_path.into(),
7662 }
7663 };
7664
7665 Some(CoreSymbol {
7666 source_language_server_id: result.server_id,
7667 language_server_name: result.lsp_adapter.name.clone(),
7668 source_worktree_id,
7669 path,
7670 kind: symbol_kind,
7671 name: symbol_name,
7672 range: range_from_lsp(symbol_location.range),
7673 })
7674 })
7675 .collect()
7676 })?;
7677
7678 populate_labels_for_symbols(
7679 core_symbols,
7680 &language_registry,
7681 Some(result.lsp_adapter),
7682 &mut symbols,
7683 )
7684 .await;
7685 }
7686
7687 Ok(symbols)
7688 })
7689 } else {
7690 Task::ready(Err(anyhow!("No upstream client or local language server")))
7691 }
7692 }
7693
7694 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7695 let mut summary = DiagnosticSummary::default();
7696 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7697 summary.error_count += path_summary.error_count;
7698 summary.warning_count += path_summary.warning_count;
7699 }
7700 summary
7701 }
7702
7703 /// Returns the diagnostic summary for a specific project path.
7704 pub fn diagnostic_summary_for_path(
7705 &self,
7706 project_path: &ProjectPath,
7707 _: &App,
7708 ) -> DiagnosticSummary {
7709 if let Some(summaries) = self
7710 .diagnostic_summaries
7711 .get(&project_path.worktree_id)
7712 .and_then(|map| map.get(&project_path.path))
7713 {
7714 let (error_count, warning_count) = summaries.iter().fold(
7715 (0, 0),
7716 |(error_count, warning_count), (_language_server_id, summary)| {
7717 (
7718 error_count + summary.error_count,
7719 warning_count + summary.warning_count,
7720 )
7721 },
7722 );
7723
7724 DiagnosticSummary {
7725 error_count,
7726 warning_count,
7727 }
7728 } else {
7729 DiagnosticSummary::default()
7730 }
7731 }
7732
7733 pub fn diagnostic_summaries<'a>(
7734 &'a self,
7735 include_ignored: bool,
7736 cx: &'a App,
7737 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7738 self.worktree_store
7739 .read(cx)
7740 .visible_worktrees(cx)
7741 .filter_map(|worktree| {
7742 let worktree = worktree.read(cx);
7743 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7744 })
7745 .flat_map(move |(worktree, summaries)| {
7746 let worktree_id = worktree.id();
7747 summaries
7748 .iter()
7749 .filter(move |(path, _)| {
7750 include_ignored
7751 || worktree
7752 .entry_for_path(path.as_ref())
7753 .is_some_and(|entry| !entry.is_ignored)
7754 })
7755 .flat_map(move |(path, summaries)| {
7756 summaries.iter().map(move |(server_id, summary)| {
7757 (
7758 ProjectPath {
7759 worktree_id,
7760 path: path.clone(),
7761 },
7762 *server_id,
7763 *summary,
7764 )
7765 })
7766 })
7767 })
7768 }
7769
7770 pub fn on_buffer_edited(
7771 &mut self,
7772 buffer: Entity<Buffer>,
7773 cx: &mut Context<Self>,
7774 ) -> Option<()> {
7775 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7776 Some(
7777 self.as_local()?
7778 .language_servers_for_buffer(buffer, cx)
7779 .map(|i| i.1.clone())
7780 .collect(),
7781 )
7782 })?;
7783
7784 let buffer = buffer.read(cx);
7785 let file = File::from_dyn(buffer.file())?;
7786 let abs_path = file.as_local()?.abs_path(cx);
7787 let uri = lsp::Uri::from_file_path(&abs_path)
7788 .ok()
7789 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7790 .log_err()?;
7791 let next_snapshot = buffer.text_snapshot();
7792 for language_server in language_servers {
7793 let language_server = language_server.clone();
7794
7795 let buffer_snapshots = self
7796 .as_local_mut()?
7797 .buffer_snapshots
7798 .get_mut(&buffer.remote_id())
7799 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7800 let previous_snapshot = buffer_snapshots.last()?;
7801
7802 let build_incremental_change = || {
7803 buffer
7804 .edits_since::<Dimensions<PointUtf16, usize>>(
7805 previous_snapshot.snapshot.version(),
7806 )
7807 .map(|edit| {
7808 let edit_start = edit.new.start.0;
7809 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7810 let new_text = next_snapshot
7811 .text_for_range(edit.new.start.1..edit.new.end.1)
7812 .collect();
7813 lsp::TextDocumentContentChangeEvent {
7814 range: Some(lsp::Range::new(
7815 point_to_lsp(edit_start),
7816 point_to_lsp(edit_end),
7817 )),
7818 range_length: None,
7819 text: new_text,
7820 }
7821 })
7822 .collect()
7823 };
7824
7825 let document_sync_kind = language_server
7826 .capabilities()
7827 .text_document_sync
7828 .as_ref()
7829 .and_then(|sync| match sync {
7830 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7831 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7832 });
7833
7834 let content_changes: Vec<_> = match document_sync_kind {
7835 Some(lsp::TextDocumentSyncKind::FULL) => {
7836 vec![lsp::TextDocumentContentChangeEvent {
7837 range: None,
7838 range_length: None,
7839 text: next_snapshot.text(),
7840 }]
7841 }
7842 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7843 _ => {
7844 #[cfg(any(test, feature = "test-support"))]
7845 {
7846 build_incremental_change()
7847 }
7848
7849 #[cfg(not(any(test, feature = "test-support")))]
7850 {
7851 continue;
7852 }
7853 }
7854 };
7855
7856 let next_version = previous_snapshot.version + 1;
7857 buffer_snapshots.push(LspBufferSnapshot {
7858 version: next_version,
7859 snapshot: next_snapshot.clone(),
7860 });
7861
7862 language_server
7863 .notify::<lsp::notification::DidChangeTextDocument>(
7864 lsp::DidChangeTextDocumentParams {
7865 text_document: lsp::VersionedTextDocumentIdentifier::new(
7866 uri.clone(),
7867 next_version,
7868 ),
7869 content_changes,
7870 },
7871 )
7872 .ok();
7873 self.pull_workspace_diagnostics(language_server.server_id());
7874 }
7875
7876 None
7877 }
7878
7879 pub fn on_buffer_saved(
7880 &mut self,
7881 buffer: Entity<Buffer>,
7882 cx: &mut Context<Self>,
7883 ) -> Option<()> {
7884 let file = File::from_dyn(buffer.read(cx).file())?;
7885 let worktree_id = file.worktree_id(cx);
7886 let abs_path = file.as_local()?.abs_path(cx);
7887 let text_document = lsp::TextDocumentIdentifier {
7888 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7889 };
7890 let local = self.as_local()?;
7891
7892 for server in local.language_servers_for_worktree(worktree_id) {
7893 if let Some(include_text) = include_text(server.as_ref()) {
7894 let text = if include_text {
7895 Some(buffer.read(cx).text())
7896 } else {
7897 None
7898 };
7899 server
7900 .notify::<lsp::notification::DidSaveTextDocument>(
7901 lsp::DidSaveTextDocumentParams {
7902 text_document: text_document.clone(),
7903 text,
7904 },
7905 )
7906 .ok();
7907 }
7908 }
7909
7910 let language_servers = buffer.update(cx, |buffer, cx| {
7911 local.language_server_ids_for_buffer(buffer, cx)
7912 });
7913 for language_server_id in language_servers {
7914 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7915 }
7916
7917 None
7918 }
7919
7920 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7921 maybe!(async move {
7922 let mut refreshed_servers = HashSet::default();
7923 let servers = lsp_store
7924 .update(cx, |lsp_store, cx| {
7925 let local = lsp_store.as_local()?;
7926
7927 let servers = local
7928 .language_server_ids
7929 .iter()
7930 .filter_map(|(seed, state)| {
7931 let worktree = lsp_store
7932 .worktree_store
7933 .read(cx)
7934 .worktree_for_id(seed.worktree_id, cx);
7935 let delegate: Arc<dyn LspAdapterDelegate> =
7936 worktree.map(|worktree| {
7937 LocalLspAdapterDelegate::new(
7938 local.languages.clone(),
7939 &local.environment,
7940 cx.weak_entity(),
7941 &worktree,
7942 local.http_client.clone(),
7943 local.fs.clone(),
7944 cx,
7945 )
7946 })?;
7947 let server_id = state.id;
7948
7949 let states = local.language_servers.get(&server_id)?;
7950
7951 match states {
7952 LanguageServerState::Starting { .. } => None,
7953 LanguageServerState::Running {
7954 adapter, server, ..
7955 } => {
7956 let adapter = adapter.clone();
7957 let server = server.clone();
7958 refreshed_servers.insert(server.name());
7959 let toolchain = seed.toolchain.clone();
7960 Some(cx.spawn(async move |_, cx| {
7961 let settings =
7962 LocalLspStore::workspace_configuration_for_adapter(
7963 adapter.adapter.clone(),
7964 &delegate,
7965 toolchain,
7966 cx,
7967 )
7968 .await
7969 .ok()?;
7970 server
7971 .notify::<lsp::notification::DidChangeConfiguration>(
7972 lsp::DidChangeConfigurationParams { settings },
7973 )
7974 .ok()?;
7975 Some(())
7976 }))
7977 }
7978 }
7979 })
7980 .collect::<Vec<_>>();
7981
7982 Some(servers)
7983 })
7984 .ok()
7985 .flatten()?;
7986
7987 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7988 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7989 // to stop and unregister its language server wrapper.
7990 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7991 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7992 let _: Vec<Option<()>> = join_all(servers).await;
7993
7994 Some(())
7995 })
7996 .await;
7997 }
7998
7999 fn maintain_workspace_config(
8000 external_refresh_requests: watch::Receiver<()>,
8001 cx: &mut Context<Self>,
8002 ) -> Task<Result<()>> {
8003 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8004 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8005
8006 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8007 *settings_changed_tx.borrow_mut() = ();
8008 });
8009
8010 let mut joint_future =
8011 futures::stream::select(settings_changed_rx, external_refresh_requests);
8012 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8013 // - 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).
8014 // - 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.
8015 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8016 // - 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,
8017 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8018 cx.spawn(async move |this, cx| {
8019 while let Some(()) = joint_future.next().await {
8020 this.update(cx, |this, cx| {
8021 this.refresh_server_tree(cx);
8022 })
8023 .ok();
8024
8025 Self::refresh_workspace_configurations(&this, cx).await;
8026 }
8027
8028 drop(settings_observation);
8029 anyhow::Ok(())
8030 })
8031 }
8032
8033 pub fn language_servers_for_local_buffer<'a>(
8034 &'a self,
8035 buffer: &Buffer,
8036 cx: &mut App,
8037 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8038 let local = self.as_local();
8039 let language_server_ids = local
8040 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8041 .unwrap_or_default();
8042
8043 language_server_ids
8044 .into_iter()
8045 .filter_map(
8046 move |server_id| match local?.language_servers.get(&server_id)? {
8047 LanguageServerState::Running {
8048 adapter, server, ..
8049 } => Some((adapter, server)),
8050 _ => None,
8051 },
8052 )
8053 }
8054
8055 pub fn language_server_for_local_buffer<'a>(
8056 &'a self,
8057 buffer: &'a Buffer,
8058 server_id: LanguageServerId,
8059 cx: &'a mut App,
8060 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8061 self.as_local()?
8062 .language_servers_for_buffer(buffer, cx)
8063 .find(|(_, s)| s.server_id() == server_id)
8064 }
8065
8066 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8067 self.diagnostic_summaries.remove(&id_to_remove);
8068 if let Some(local) = self.as_local_mut() {
8069 let to_remove = local.remove_worktree(id_to_remove, cx);
8070 for server in to_remove {
8071 self.language_server_statuses.remove(&server);
8072 }
8073 }
8074 }
8075
8076 pub fn shared(
8077 &mut self,
8078 project_id: u64,
8079 downstream_client: AnyProtoClient,
8080 _: &mut Context<Self>,
8081 ) {
8082 self.downstream_client = Some((downstream_client.clone(), project_id));
8083
8084 for (server_id, status) in &self.language_server_statuses {
8085 if let Some(server) = self.language_server_for_id(*server_id) {
8086 downstream_client
8087 .send(proto::StartLanguageServer {
8088 project_id,
8089 server: Some(proto::LanguageServer {
8090 id: server_id.to_proto(),
8091 name: status.name.to_string(),
8092 worktree_id: status.worktree.map(|id| id.to_proto()),
8093 }),
8094 capabilities: serde_json::to_string(&server.capabilities())
8095 .expect("serializing server LSP capabilities"),
8096 })
8097 .log_err();
8098 }
8099 }
8100 }
8101
8102 pub fn disconnected_from_host(&mut self) {
8103 self.downstream_client.take();
8104 }
8105
8106 pub fn disconnected_from_ssh_remote(&mut self) {
8107 if let LspStoreMode::Remote(RemoteLspStore {
8108 upstream_client, ..
8109 }) = &mut self.mode
8110 {
8111 upstream_client.take();
8112 }
8113 }
8114
8115 pub(crate) fn set_language_server_statuses_from_proto(
8116 &mut self,
8117 project: WeakEntity<Project>,
8118 language_servers: Vec<proto::LanguageServer>,
8119 server_capabilities: Vec<String>,
8120 cx: &mut Context<Self>,
8121 ) {
8122 let lsp_logs = cx
8123 .try_global::<GlobalLogStore>()
8124 .map(|lsp_store| lsp_store.0.clone());
8125
8126 self.language_server_statuses = language_servers
8127 .into_iter()
8128 .zip(server_capabilities)
8129 .map(|(server, server_capabilities)| {
8130 let server_id = LanguageServerId(server.id as usize);
8131 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8132 self.lsp_server_capabilities
8133 .insert(server_id, server_capabilities);
8134 }
8135
8136 let name = LanguageServerName::from_proto(server.name);
8137 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8138
8139 if let Some(lsp_logs) = &lsp_logs {
8140 lsp_logs.update(cx, |lsp_logs, cx| {
8141 lsp_logs.add_language_server(
8142 // Only remote clients get their language servers set from proto
8143 LanguageServerKind::Remote {
8144 project: project.clone(),
8145 },
8146 server_id,
8147 Some(name.clone()),
8148 worktree,
8149 None,
8150 cx,
8151 );
8152 });
8153 }
8154
8155 (
8156 server_id,
8157 LanguageServerStatus {
8158 name,
8159 pending_work: Default::default(),
8160 has_pending_diagnostic_updates: false,
8161 progress_tokens: Default::default(),
8162 worktree,
8163 binary: None,
8164 configuration: None,
8165 workspace_folders: BTreeSet::new(),
8166 },
8167 )
8168 })
8169 .collect();
8170 }
8171
8172 #[cfg(test)]
8173 pub fn update_diagnostic_entries(
8174 &mut self,
8175 server_id: LanguageServerId,
8176 abs_path: PathBuf,
8177 result_id: Option<String>,
8178 version: Option<i32>,
8179 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8180 cx: &mut Context<Self>,
8181 ) -> anyhow::Result<()> {
8182 self.merge_diagnostic_entries(
8183 vec![DocumentDiagnosticsUpdate {
8184 diagnostics: DocumentDiagnostics {
8185 diagnostics,
8186 document_abs_path: abs_path,
8187 version,
8188 },
8189 result_id,
8190 server_id,
8191 disk_based_sources: Cow::Borrowed(&[]),
8192 }],
8193 |_, _, _| false,
8194 cx,
8195 )?;
8196 Ok(())
8197 }
8198
8199 pub fn merge_diagnostic_entries<'a>(
8200 &mut self,
8201 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8202 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8203 cx: &mut Context<Self>,
8204 ) -> anyhow::Result<()> {
8205 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8206 let mut updated_diagnostics_paths = HashMap::default();
8207 for mut update in diagnostic_updates {
8208 let abs_path = &update.diagnostics.document_abs_path;
8209 let server_id = update.server_id;
8210 let Some((worktree, relative_path)) =
8211 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8212 else {
8213 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8214 return Ok(());
8215 };
8216
8217 let worktree_id = worktree.read(cx).id();
8218 let project_path = ProjectPath {
8219 worktree_id,
8220 path: relative_path,
8221 };
8222
8223 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8224 let snapshot = buffer_handle.read(cx).snapshot();
8225 let buffer = buffer_handle.read(cx);
8226 let reused_diagnostics = buffer
8227 .buffer_diagnostics(Some(server_id))
8228 .iter()
8229 .filter(|v| merge(buffer, &v.diagnostic, cx))
8230 .map(|v| {
8231 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8232 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8233 DiagnosticEntry {
8234 range: start..end,
8235 diagnostic: v.diagnostic.clone(),
8236 }
8237 })
8238 .collect::<Vec<_>>();
8239
8240 self.as_local_mut()
8241 .context("cannot merge diagnostics on a remote LspStore")?
8242 .update_buffer_diagnostics(
8243 &buffer_handle,
8244 server_id,
8245 update.result_id,
8246 update.diagnostics.version,
8247 update.diagnostics.diagnostics.clone(),
8248 reused_diagnostics.clone(),
8249 cx,
8250 )?;
8251
8252 update.diagnostics.diagnostics.extend(reused_diagnostics);
8253 }
8254
8255 let updated = worktree.update(cx, |worktree, cx| {
8256 self.update_worktree_diagnostics(
8257 worktree.id(),
8258 server_id,
8259 project_path.path.clone(),
8260 update.diagnostics.diagnostics,
8261 cx,
8262 )
8263 })?;
8264 match updated {
8265 ControlFlow::Continue(new_summary) => {
8266 if let Some((project_id, new_summary)) = new_summary {
8267 match &mut diagnostics_summary {
8268 Some(diagnostics_summary) => {
8269 diagnostics_summary
8270 .more_summaries
8271 .push(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 }
8278 None => {
8279 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8280 project_id,
8281 worktree_id: worktree_id.to_proto(),
8282 summary: Some(proto::DiagnosticSummary {
8283 path: project_path.path.as_ref().to_proto(),
8284 language_server_id: server_id.0 as u64,
8285 error_count: new_summary.error_count,
8286 warning_count: new_summary.warning_count,
8287 }),
8288 more_summaries: Vec::new(),
8289 })
8290 }
8291 }
8292 }
8293 updated_diagnostics_paths
8294 .entry(server_id)
8295 .or_insert_with(Vec::new)
8296 .push(project_path);
8297 }
8298 ControlFlow::Break(()) => {}
8299 }
8300 }
8301
8302 if let Some((diagnostics_summary, (downstream_client, _))) =
8303 diagnostics_summary.zip(self.downstream_client.as_ref())
8304 {
8305 downstream_client.send(diagnostics_summary).log_err();
8306 }
8307 for (server_id, paths) in updated_diagnostics_paths {
8308 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8309 }
8310 Ok(())
8311 }
8312
8313 fn update_worktree_diagnostics(
8314 &mut self,
8315 worktree_id: WorktreeId,
8316 server_id: LanguageServerId,
8317 path_in_worktree: Arc<RelPath>,
8318 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8319 _: &mut Context<Worktree>,
8320 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8321 let local = match &mut self.mode {
8322 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8323 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8324 };
8325
8326 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8327 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8328 let summaries_by_server_id = summaries_for_tree
8329 .entry(path_in_worktree.clone())
8330 .or_default();
8331
8332 let old_summary = summaries_by_server_id
8333 .remove(&server_id)
8334 .unwrap_or_default();
8335
8336 let new_summary = DiagnosticSummary::new(&diagnostics);
8337 if new_summary.is_empty() {
8338 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8339 {
8340 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8341 diagnostics_by_server_id.remove(ix);
8342 }
8343 if diagnostics_by_server_id.is_empty() {
8344 diagnostics_for_tree.remove(&path_in_worktree);
8345 }
8346 }
8347 } else {
8348 summaries_by_server_id.insert(server_id, new_summary);
8349 let diagnostics_by_server_id = diagnostics_for_tree
8350 .entry(path_in_worktree.clone())
8351 .or_default();
8352 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8353 Ok(ix) => {
8354 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8355 }
8356 Err(ix) => {
8357 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8358 }
8359 }
8360 }
8361
8362 if !old_summary.is_empty() || !new_summary.is_empty() {
8363 if let Some((_, project_id)) = &self.downstream_client {
8364 Ok(ControlFlow::Continue(Some((
8365 *project_id,
8366 proto::DiagnosticSummary {
8367 path: path_in_worktree.to_proto(),
8368 language_server_id: server_id.0 as u64,
8369 error_count: new_summary.error_count as u32,
8370 warning_count: new_summary.warning_count as u32,
8371 },
8372 ))))
8373 } else {
8374 Ok(ControlFlow::Continue(None))
8375 }
8376 } else {
8377 Ok(ControlFlow::Break(()))
8378 }
8379 }
8380
8381 pub fn open_buffer_for_symbol(
8382 &mut self,
8383 symbol: &Symbol,
8384 cx: &mut Context<Self>,
8385 ) -> Task<Result<Entity<Buffer>>> {
8386 if let Some((client, project_id)) = self.upstream_client() {
8387 let request = client.request(proto::OpenBufferForSymbol {
8388 project_id,
8389 symbol: Some(Self::serialize_symbol(symbol)),
8390 });
8391 cx.spawn(async move |this, cx| {
8392 let response = request.await?;
8393 let buffer_id = BufferId::new(response.buffer_id)?;
8394 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8395 .await
8396 })
8397 } else if let Some(local) = self.as_local() {
8398 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8399 seed.worktree_id == symbol.source_worktree_id
8400 && state.id == symbol.source_language_server_id
8401 && symbol.language_server_name == seed.name
8402 });
8403 if !is_valid {
8404 return Task::ready(Err(anyhow!(
8405 "language server for worktree and language not found"
8406 )));
8407 };
8408
8409 let symbol_abs_path = match &symbol.path {
8410 SymbolLocation::InProject(project_path) => self
8411 .worktree_store
8412 .read(cx)
8413 .absolutize(&project_path, cx)
8414 .context("no such worktree"),
8415 SymbolLocation::OutsideProject {
8416 abs_path,
8417 signature: _,
8418 } => Ok(abs_path.to_path_buf()),
8419 };
8420 let symbol_abs_path = match symbol_abs_path {
8421 Ok(abs_path) => abs_path,
8422 Err(err) => return Task::ready(Err(err)),
8423 };
8424 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8425 uri
8426 } else {
8427 return Task::ready(Err(anyhow!("invalid symbol path")));
8428 };
8429
8430 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8431 } else {
8432 Task::ready(Err(anyhow!("no upstream client or local store")))
8433 }
8434 }
8435
8436 pub(crate) fn open_local_buffer_via_lsp(
8437 &mut self,
8438 abs_path: lsp::Uri,
8439 language_server_id: LanguageServerId,
8440 cx: &mut Context<Self>,
8441 ) -> Task<Result<Entity<Buffer>>> {
8442 cx.spawn(async move |lsp_store, cx| {
8443 // Escape percent-encoded string.
8444 let current_scheme = abs_path.scheme().to_owned();
8445 // Uri is immutable, so we can't modify the scheme
8446
8447 let abs_path = abs_path
8448 .to_file_path()
8449 .map_err(|()| anyhow!("can't convert URI to path"))?;
8450 let p = abs_path.clone();
8451 let yarn_worktree = lsp_store
8452 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8453 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8454 cx.spawn(async move |this, cx| {
8455 let t = this
8456 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8457 .ok()?;
8458 t.await
8459 })
8460 }),
8461 None => Task::ready(None),
8462 })?
8463 .await;
8464 let (worktree_root_target, known_relative_path) =
8465 if let Some((zip_root, relative_path)) = yarn_worktree {
8466 (zip_root, Some(relative_path))
8467 } else {
8468 (Arc::<Path>::from(abs_path.as_path()), None)
8469 };
8470 let (worktree, relative_path) = if let Some(result) =
8471 lsp_store.update(cx, |lsp_store, cx| {
8472 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8473 worktree_store.find_worktree(&worktree_root_target, cx)
8474 })
8475 })? {
8476 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8477 (result.0, relative_path)
8478 } else {
8479 let worktree = lsp_store
8480 .update(cx, |lsp_store, cx| {
8481 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8482 worktree_store.create_worktree(&worktree_root_target, false, cx)
8483 })
8484 })?
8485 .await?;
8486 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8487 lsp_store
8488 .update(cx, |lsp_store, cx| {
8489 if let Some(local) = lsp_store.as_local_mut() {
8490 local.register_language_server_for_invisible_worktree(
8491 &worktree,
8492 language_server_id,
8493 cx,
8494 )
8495 }
8496 })
8497 .ok();
8498 }
8499 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8500 let relative_path = if let Some(known_path) = known_relative_path {
8501 known_path
8502 } else {
8503 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8504 .into_arc()
8505 };
8506 (worktree, relative_path)
8507 };
8508 let project_path = ProjectPath {
8509 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8510 path: relative_path,
8511 };
8512 lsp_store
8513 .update(cx, |lsp_store, cx| {
8514 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8515 buffer_store.open_buffer(project_path, cx)
8516 })
8517 })?
8518 .await
8519 })
8520 }
8521
8522 fn request_multiple_lsp_locally<P, R>(
8523 &mut self,
8524 buffer: &Entity<Buffer>,
8525 position: Option<P>,
8526 request: R,
8527 cx: &mut Context<Self>,
8528 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8529 where
8530 P: ToOffset,
8531 R: LspCommand + Clone,
8532 <R::LspRequest as lsp::request::Request>::Result: Send,
8533 <R::LspRequest as lsp::request::Request>::Params: Send,
8534 {
8535 let Some(local) = self.as_local() else {
8536 return Task::ready(Vec::new());
8537 };
8538
8539 let snapshot = buffer.read(cx).snapshot();
8540 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8541
8542 let server_ids = buffer.update(cx, |buffer, cx| {
8543 local
8544 .language_servers_for_buffer(buffer, cx)
8545 .filter(|(adapter, _)| {
8546 scope
8547 .as_ref()
8548 .map(|scope| scope.language_allowed(&adapter.name))
8549 .unwrap_or(true)
8550 })
8551 .map(|(_, server)| server.server_id())
8552 .filter(|server_id| {
8553 self.as_local().is_none_or(|local| {
8554 local
8555 .buffers_opened_in_servers
8556 .get(&snapshot.remote_id())
8557 .is_some_and(|servers| servers.contains(server_id))
8558 })
8559 })
8560 .collect::<Vec<_>>()
8561 });
8562
8563 let mut response_results = server_ids
8564 .into_iter()
8565 .map(|server_id| {
8566 let task = self.request_lsp(
8567 buffer.clone(),
8568 LanguageServerToQuery::Other(server_id),
8569 request.clone(),
8570 cx,
8571 );
8572 async move { (server_id, task.await) }
8573 })
8574 .collect::<FuturesUnordered<_>>();
8575
8576 cx.background_spawn(async move {
8577 let mut responses = Vec::with_capacity(response_results.len());
8578 while let Some((server_id, response_result)) = response_results.next().await {
8579 match response_result {
8580 Ok(response) => responses.push((server_id, response)),
8581 // rust-analyzer likes to error with this when its still loading up
8582 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8583 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8584 }
8585 }
8586 responses
8587 })
8588 }
8589
8590 async fn handle_lsp_get_completions(
8591 this: Entity<Self>,
8592 envelope: TypedEnvelope<proto::GetCompletions>,
8593 mut cx: AsyncApp,
8594 ) -> Result<proto::GetCompletionsResponse> {
8595 let sender_id = envelope.original_sender_id().unwrap_or_default();
8596
8597 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8598 let buffer_handle = this.update(&mut cx, |this, cx| {
8599 this.buffer_store.read(cx).get_existing(buffer_id)
8600 })??;
8601 let request = GetCompletions::from_proto(
8602 envelope.payload,
8603 this.clone(),
8604 buffer_handle.clone(),
8605 cx.clone(),
8606 )
8607 .await?;
8608
8609 let server_to_query = match request.server_id {
8610 Some(server_id) => LanguageServerToQuery::Other(server_id),
8611 None => LanguageServerToQuery::FirstCapable,
8612 };
8613
8614 let response = this
8615 .update(&mut cx, |this, cx| {
8616 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8617 })?
8618 .await?;
8619 this.update(&mut cx, |this, cx| {
8620 Ok(GetCompletions::response_to_proto(
8621 response,
8622 this,
8623 sender_id,
8624 &buffer_handle.read(cx).version(),
8625 cx,
8626 ))
8627 })?
8628 }
8629
8630 async fn handle_lsp_command<T: LspCommand>(
8631 this: Entity<Self>,
8632 envelope: TypedEnvelope<T::ProtoRequest>,
8633 mut cx: AsyncApp,
8634 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8635 where
8636 <T::LspRequest as lsp::request::Request>::Params: Send,
8637 <T::LspRequest as lsp::request::Request>::Result: Send,
8638 {
8639 let sender_id = envelope.original_sender_id().unwrap_or_default();
8640 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8641 let buffer_handle = this.update(&mut cx, |this, cx| {
8642 this.buffer_store.read(cx).get_existing(buffer_id)
8643 })??;
8644 let request = T::from_proto(
8645 envelope.payload,
8646 this.clone(),
8647 buffer_handle.clone(),
8648 cx.clone(),
8649 )
8650 .await?;
8651 let response = this
8652 .update(&mut cx, |this, cx| {
8653 this.request_lsp(
8654 buffer_handle.clone(),
8655 LanguageServerToQuery::FirstCapable,
8656 request,
8657 cx,
8658 )
8659 })?
8660 .await?;
8661 this.update(&mut cx, |this, cx| {
8662 Ok(T::response_to_proto(
8663 response,
8664 this,
8665 sender_id,
8666 &buffer_handle.read(cx).version(),
8667 cx,
8668 ))
8669 })?
8670 }
8671
8672 async fn handle_lsp_query(
8673 lsp_store: Entity<Self>,
8674 envelope: TypedEnvelope<proto::LspQuery>,
8675 mut cx: AsyncApp,
8676 ) -> Result<proto::Ack> {
8677 use proto::lsp_query::Request;
8678 let sender_id = envelope.original_sender_id().unwrap_or_default();
8679 let lsp_query = envelope.payload;
8680 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8681 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8682 match lsp_query.request.context("invalid LSP query request")? {
8683 Request::GetReferences(get_references) => {
8684 let position = get_references.position.clone().and_then(deserialize_anchor);
8685 Self::query_lsp_locally::<GetReferences>(
8686 lsp_store,
8687 server_id,
8688 sender_id,
8689 lsp_request_id,
8690 get_references,
8691 position,
8692 &mut cx,
8693 )
8694 .await?;
8695 }
8696 Request::GetDocumentColor(get_document_color) => {
8697 Self::query_lsp_locally::<GetDocumentColor>(
8698 lsp_store,
8699 server_id,
8700 sender_id,
8701 lsp_request_id,
8702 get_document_color,
8703 None,
8704 &mut cx,
8705 )
8706 .await?;
8707 }
8708 Request::GetHover(get_hover) => {
8709 let position = get_hover.position.clone().and_then(deserialize_anchor);
8710 Self::query_lsp_locally::<GetHover>(
8711 lsp_store,
8712 server_id,
8713 sender_id,
8714 lsp_request_id,
8715 get_hover,
8716 position,
8717 &mut cx,
8718 )
8719 .await?;
8720 }
8721 Request::GetCodeActions(get_code_actions) => {
8722 Self::query_lsp_locally::<GetCodeActions>(
8723 lsp_store,
8724 server_id,
8725 sender_id,
8726 lsp_request_id,
8727 get_code_actions,
8728 None,
8729 &mut cx,
8730 )
8731 .await?;
8732 }
8733 Request::GetSignatureHelp(get_signature_help) => {
8734 let position = get_signature_help
8735 .position
8736 .clone()
8737 .and_then(deserialize_anchor);
8738 Self::query_lsp_locally::<GetSignatureHelp>(
8739 lsp_store,
8740 server_id,
8741 sender_id,
8742 lsp_request_id,
8743 get_signature_help,
8744 position,
8745 &mut cx,
8746 )
8747 .await?;
8748 }
8749 Request::GetCodeLens(get_code_lens) => {
8750 Self::query_lsp_locally::<GetCodeLens>(
8751 lsp_store,
8752 server_id,
8753 sender_id,
8754 lsp_request_id,
8755 get_code_lens,
8756 None,
8757 &mut cx,
8758 )
8759 .await?;
8760 }
8761 Request::GetDefinition(get_definition) => {
8762 let position = get_definition.position.clone().and_then(deserialize_anchor);
8763 Self::query_lsp_locally::<GetDefinitions>(
8764 lsp_store,
8765 server_id,
8766 sender_id,
8767 lsp_request_id,
8768 get_definition,
8769 position,
8770 &mut cx,
8771 )
8772 .await?;
8773 }
8774 Request::GetDeclaration(get_declaration) => {
8775 let position = get_declaration
8776 .position
8777 .clone()
8778 .and_then(deserialize_anchor);
8779 Self::query_lsp_locally::<GetDeclarations>(
8780 lsp_store,
8781 server_id,
8782 sender_id,
8783 lsp_request_id,
8784 get_declaration,
8785 position,
8786 &mut cx,
8787 )
8788 .await?;
8789 }
8790 Request::GetTypeDefinition(get_type_definition) => {
8791 let position = get_type_definition
8792 .position
8793 .clone()
8794 .and_then(deserialize_anchor);
8795 Self::query_lsp_locally::<GetTypeDefinitions>(
8796 lsp_store,
8797 server_id,
8798 sender_id,
8799 lsp_request_id,
8800 get_type_definition,
8801 position,
8802 &mut cx,
8803 )
8804 .await?;
8805 }
8806 Request::GetImplementation(get_implementation) => {
8807 let position = get_implementation
8808 .position
8809 .clone()
8810 .and_then(deserialize_anchor);
8811 Self::query_lsp_locally::<GetImplementations>(
8812 lsp_store,
8813 server_id,
8814 sender_id,
8815 lsp_request_id,
8816 get_implementation,
8817 position,
8818 &mut cx,
8819 )
8820 .await?;
8821 }
8822 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8823 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8824 let version = deserialize_version(get_document_diagnostics.buffer_version());
8825 let buffer = lsp_store.update(&mut cx, |this, cx| {
8826 this.buffer_store.read(cx).get_existing(buffer_id)
8827 })??;
8828 buffer
8829 .update(&mut cx, |buffer, _| {
8830 buffer.wait_for_version(version.clone())
8831 })?
8832 .await?;
8833 lsp_store.update(&mut cx, |lsp_store, cx| {
8834 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8835 let key = LspKey {
8836 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8837 server_queried: server_id,
8838 };
8839 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8840 ) {
8841 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8842 lsp_requests.clear();
8843 };
8844 }
8845
8846 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8847 existing_queries.insert(
8848 lsp_request_id,
8849 cx.spawn(async move |lsp_store, cx| {
8850 let diagnostics_pull = lsp_store
8851 .update(cx, |lsp_store, cx| {
8852 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8853 })
8854 .ok();
8855 if let Some(diagnostics_pull) = diagnostics_pull {
8856 match diagnostics_pull.await {
8857 Ok(()) => {}
8858 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8859 };
8860 }
8861 }),
8862 );
8863 })?;
8864 }
8865 Request::InlayHints(inlay_hints) => {
8866 let query_start = inlay_hints
8867 .start
8868 .clone()
8869 .and_then(deserialize_anchor)
8870 .context("invalid inlay hints range start")?;
8871 let query_end = inlay_hints
8872 .end
8873 .clone()
8874 .and_then(deserialize_anchor)
8875 .context("invalid inlay hints range end")?;
8876 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8877 &lsp_store,
8878 server_id,
8879 lsp_request_id,
8880 &inlay_hints,
8881 query_start..query_end,
8882 &mut cx,
8883 )
8884 .await
8885 .context("preparing inlay hints request")?;
8886 Self::query_lsp_locally::<InlayHints>(
8887 lsp_store,
8888 server_id,
8889 sender_id,
8890 lsp_request_id,
8891 inlay_hints,
8892 None,
8893 &mut cx,
8894 )
8895 .await
8896 .context("querying for inlay hints")?
8897 }
8898 }
8899 Ok(proto::Ack {})
8900 }
8901
8902 async fn handle_lsp_query_response(
8903 lsp_store: Entity<Self>,
8904 envelope: TypedEnvelope<proto::LspQueryResponse>,
8905 cx: AsyncApp,
8906 ) -> Result<()> {
8907 lsp_store.read_with(&cx, |lsp_store, _| {
8908 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8909 upstream_client.handle_lsp_response(envelope.clone());
8910 }
8911 })?;
8912 Ok(())
8913 }
8914
8915 async fn handle_apply_code_action(
8916 this: Entity<Self>,
8917 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8918 mut cx: AsyncApp,
8919 ) -> Result<proto::ApplyCodeActionResponse> {
8920 let sender_id = envelope.original_sender_id().unwrap_or_default();
8921 let action =
8922 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8923 let apply_code_action = this.update(&mut cx, |this, cx| {
8924 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8925 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8926 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8927 })??;
8928
8929 let project_transaction = apply_code_action.await?;
8930 let project_transaction = this.update(&mut cx, |this, cx| {
8931 this.buffer_store.update(cx, |buffer_store, cx| {
8932 buffer_store.serialize_project_transaction_for_peer(
8933 project_transaction,
8934 sender_id,
8935 cx,
8936 )
8937 })
8938 })?;
8939 Ok(proto::ApplyCodeActionResponse {
8940 transaction: Some(project_transaction),
8941 })
8942 }
8943
8944 async fn handle_register_buffer_with_language_servers(
8945 this: Entity<Self>,
8946 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8947 mut cx: AsyncApp,
8948 ) -> Result<proto::Ack> {
8949 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8950 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8951 this.update(&mut cx, |this, cx| {
8952 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8953 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8954 project_id: upstream_project_id,
8955 buffer_id: buffer_id.to_proto(),
8956 only_servers: envelope.payload.only_servers,
8957 });
8958 }
8959
8960 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8961 anyhow::bail!("buffer is not open");
8962 };
8963
8964 let handle = this.register_buffer_with_language_servers(
8965 &buffer,
8966 envelope
8967 .payload
8968 .only_servers
8969 .into_iter()
8970 .filter_map(|selector| {
8971 Some(match selector.selector? {
8972 proto::language_server_selector::Selector::ServerId(server_id) => {
8973 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8974 }
8975 proto::language_server_selector::Selector::Name(name) => {
8976 LanguageServerSelector::Name(LanguageServerName(
8977 SharedString::from(name),
8978 ))
8979 }
8980 })
8981 })
8982 .collect(),
8983 false,
8984 cx,
8985 );
8986 this.buffer_store().update(cx, |buffer_store, _| {
8987 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8988 });
8989
8990 Ok(())
8991 })??;
8992 Ok(proto::Ack {})
8993 }
8994
8995 async fn handle_rename_project_entry(
8996 this: Entity<Self>,
8997 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8998 mut cx: AsyncApp,
8999 ) -> Result<proto::ProjectEntryResponse> {
9000 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9001 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9002 let new_path =
9003 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9004
9005 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9006 .update(&mut cx, |this, cx| {
9007 let (worktree, entry) = this
9008 .worktree_store
9009 .read(cx)
9010 .worktree_and_entry_for_id(entry_id, cx)?;
9011 let new_worktree = this
9012 .worktree_store
9013 .read(cx)
9014 .worktree_for_id(new_worktree_id, cx)?;
9015 Some((
9016 this.worktree_store.clone(),
9017 worktree,
9018 new_worktree,
9019 entry.clone(),
9020 ))
9021 })?
9022 .context("worktree not found")?;
9023 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9024 (worktree.absolutize(&old_entry.path), worktree.id())
9025 })?;
9026 let new_abs_path =
9027 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9028
9029 let _transaction = Self::will_rename_entry(
9030 this.downgrade(),
9031 old_worktree_id,
9032 &old_abs_path,
9033 &new_abs_path,
9034 old_entry.is_dir(),
9035 cx.clone(),
9036 )
9037 .await;
9038 let response = WorktreeStore::handle_rename_project_entry(
9039 worktree_store,
9040 envelope.payload,
9041 cx.clone(),
9042 )
9043 .await;
9044 this.read_with(&cx, |this, _| {
9045 this.did_rename_entry(
9046 old_worktree_id,
9047 &old_abs_path,
9048 &new_abs_path,
9049 old_entry.is_dir(),
9050 );
9051 })
9052 .ok();
9053 response
9054 }
9055
9056 async fn handle_update_diagnostic_summary(
9057 this: Entity<Self>,
9058 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9059 mut cx: AsyncApp,
9060 ) -> Result<()> {
9061 this.update(&mut cx, |lsp_store, cx| {
9062 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9063 let mut updated_diagnostics_paths = HashMap::default();
9064 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9065 for message_summary in envelope
9066 .payload
9067 .summary
9068 .into_iter()
9069 .chain(envelope.payload.more_summaries)
9070 {
9071 let project_path = ProjectPath {
9072 worktree_id,
9073 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9074 };
9075 let path = project_path.path.clone();
9076 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9077 let summary = DiagnosticSummary {
9078 error_count: message_summary.error_count as usize,
9079 warning_count: message_summary.warning_count as usize,
9080 };
9081
9082 if summary.is_empty() {
9083 if let Some(worktree_summaries) =
9084 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9085 && let Some(summaries) = worktree_summaries.get_mut(&path)
9086 {
9087 summaries.remove(&server_id);
9088 if summaries.is_empty() {
9089 worktree_summaries.remove(&path);
9090 }
9091 }
9092 } else {
9093 lsp_store
9094 .diagnostic_summaries
9095 .entry(worktree_id)
9096 .or_default()
9097 .entry(path)
9098 .or_default()
9099 .insert(server_id, summary);
9100 }
9101
9102 if let Some((_, project_id)) = &lsp_store.downstream_client {
9103 match &mut diagnostics_summary {
9104 Some(diagnostics_summary) => {
9105 diagnostics_summary
9106 .more_summaries
9107 .push(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 }
9114 None => {
9115 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9116 project_id: *project_id,
9117 worktree_id: worktree_id.to_proto(),
9118 summary: Some(proto::DiagnosticSummary {
9119 path: project_path.path.as_ref().to_proto(),
9120 language_server_id: server_id.0 as u64,
9121 error_count: summary.error_count as u32,
9122 warning_count: summary.warning_count as u32,
9123 }),
9124 more_summaries: Vec::new(),
9125 })
9126 }
9127 }
9128 }
9129 updated_diagnostics_paths
9130 .entry(server_id)
9131 .or_insert_with(Vec::new)
9132 .push(project_path);
9133 }
9134
9135 if let Some((diagnostics_summary, (downstream_client, _))) =
9136 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9137 {
9138 downstream_client.send(diagnostics_summary).log_err();
9139 }
9140 for (server_id, paths) in updated_diagnostics_paths {
9141 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9142 }
9143 Ok(())
9144 })?
9145 }
9146
9147 async fn handle_start_language_server(
9148 lsp_store: Entity<Self>,
9149 envelope: TypedEnvelope<proto::StartLanguageServer>,
9150 mut cx: AsyncApp,
9151 ) -> Result<()> {
9152 let server = envelope.payload.server.context("invalid server")?;
9153 let server_capabilities =
9154 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9155 .with_context(|| {
9156 format!(
9157 "incorrect server capabilities {}",
9158 envelope.payload.capabilities
9159 )
9160 })?;
9161 lsp_store.update(&mut cx, |lsp_store, cx| {
9162 let server_id = LanguageServerId(server.id as usize);
9163 let server_name = LanguageServerName::from_proto(server.name.clone());
9164 lsp_store
9165 .lsp_server_capabilities
9166 .insert(server_id, server_capabilities);
9167 lsp_store.language_server_statuses.insert(
9168 server_id,
9169 LanguageServerStatus {
9170 name: server_name.clone(),
9171 pending_work: Default::default(),
9172 has_pending_diagnostic_updates: false,
9173 progress_tokens: Default::default(),
9174 worktree: server.worktree_id.map(WorktreeId::from_proto),
9175 binary: None,
9176 configuration: None,
9177 workspace_folders: BTreeSet::new(),
9178 },
9179 );
9180 cx.emit(LspStoreEvent::LanguageServerAdded(
9181 server_id,
9182 server_name,
9183 server.worktree_id.map(WorktreeId::from_proto),
9184 ));
9185 cx.notify();
9186 })?;
9187 Ok(())
9188 }
9189
9190 async fn handle_update_language_server(
9191 lsp_store: Entity<Self>,
9192 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9193 mut cx: AsyncApp,
9194 ) -> Result<()> {
9195 lsp_store.update(&mut cx, |lsp_store, cx| {
9196 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9197
9198 match envelope.payload.variant.context("invalid variant")? {
9199 proto::update_language_server::Variant::WorkStart(payload) => {
9200 lsp_store.on_lsp_work_start(
9201 language_server_id,
9202 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9203 .context("invalid progress token value")?,
9204 LanguageServerProgress {
9205 title: payload.title,
9206 is_disk_based_diagnostics_progress: false,
9207 is_cancellable: payload.is_cancellable.unwrap_or(false),
9208 message: payload.message,
9209 percentage: payload.percentage.map(|p| p as usize),
9210 last_update_at: cx.background_executor().now(),
9211 },
9212 cx,
9213 );
9214 }
9215 proto::update_language_server::Variant::WorkProgress(payload) => {
9216 lsp_store.on_lsp_work_progress(
9217 language_server_id,
9218 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9219 .context("invalid progress token value")?,
9220 LanguageServerProgress {
9221 title: None,
9222 is_disk_based_diagnostics_progress: false,
9223 is_cancellable: payload.is_cancellable.unwrap_or(false),
9224 message: payload.message,
9225 percentage: payload.percentage.map(|p| p as usize),
9226 last_update_at: cx.background_executor().now(),
9227 },
9228 cx,
9229 );
9230 }
9231
9232 proto::update_language_server::Variant::WorkEnd(payload) => {
9233 lsp_store.on_lsp_work_end(
9234 language_server_id,
9235 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9236 .context("invalid progress token value")?,
9237 cx,
9238 );
9239 }
9240
9241 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9242 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9243 }
9244
9245 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9246 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9247 }
9248
9249 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9250 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9251 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9252 cx.emit(LspStoreEvent::LanguageServerUpdate {
9253 language_server_id,
9254 name: envelope
9255 .payload
9256 .server_name
9257 .map(SharedString::new)
9258 .map(LanguageServerName),
9259 message: non_lsp,
9260 });
9261 }
9262 }
9263
9264 Ok(())
9265 })?
9266 }
9267
9268 async fn handle_language_server_log(
9269 this: Entity<Self>,
9270 envelope: TypedEnvelope<proto::LanguageServerLog>,
9271 mut cx: AsyncApp,
9272 ) -> Result<()> {
9273 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9274 let log_type = envelope
9275 .payload
9276 .log_type
9277 .map(LanguageServerLogType::from_proto)
9278 .context("invalid language server log type")?;
9279
9280 let message = envelope.payload.message;
9281
9282 this.update(&mut cx, |_, cx| {
9283 cx.emit(LspStoreEvent::LanguageServerLog(
9284 language_server_id,
9285 log_type,
9286 message,
9287 ));
9288 })
9289 }
9290
9291 async fn handle_lsp_ext_cancel_flycheck(
9292 lsp_store: Entity<Self>,
9293 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9294 cx: AsyncApp,
9295 ) -> Result<proto::Ack> {
9296 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9297 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9298 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9299 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9300 } else {
9301 None
9302 }
9303 })?;
9304 if let Some(task) = task {
9305 task.context("handling lsp ext cancel flycheck")?;
9306 }
9307
9308 Ok(proto::Ack {})
9309 }
9310
9311 async fn handle_lsp_ext_run_flycheck(
9312 lsp_store: Entity<Self>,
9313 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9314 mut cx: AsyncApp,
9315 ) -> Result<proto::Ack> {
9316 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9317 lsp_store.update(&mut cx, |lsp_store, cx| {
9318 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9319 let text_document = if envelope.payload.current_file_only {
9320 let buffer_id = envelope
9321 .payload
9322 .buffer_id
9323 .map(|id| BufferId::new(id))
9324 .transpose()?;
9325 buffer_id
9326 .and_then(|buffer_id| {
9327 lsp_store
9328 .buffer_store()
9329 .read(cx)
9330 .get(buffer_id)
9331 .and_then(|buffer| {
9332 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9333 })
9334 .map(|path| make_text_document_identifier(&path))
9335 })
9336 .transpose()?
9337 } else {
9338 None
9339 };
9340 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9341 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9342 )?;
9343 }
9344 anyhow::Ok(())
9345 })??;
9346
9347 Ok(proto::Ack {})
9348 }
9349
9350 async fn handle_lsp_ext_clear_flycheck(
9351 lsp_store: Entity<Self>,
9352 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9353 cx: AsyncApp,
9354 ) -> Result<proto::Ack> {
9355 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9356 lsp_store
9357 .read_with(&cx, |lsp_store, _| {
9358 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9359 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9360 } else {
9361 None
9362 }
9363 })
9364 .context("handling lsp ext clear flycheck")?;
9365
9366 Ok(proto::Ack {})
9367 }
9368
9369 pub fn disk_based_diagnostics_started(
9370 &mut self,
9371 language_server_id: LanguageServerId,
9372 cx: &mut Context<Self>,
9373 ) {
9374 if let Some(language_server_status) =
9375 self.language_server_statuses.get_mut(&language_server_id)
9376 {
9377 language_server_status.has_pending_diagnostic_updates = true;
9378 }
9379
9380 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9381 cx.emit(LspStoreEvent::LanguageServerUpdate {
9382 language_server_id,
9383 name: self
9384 .language_server_adapter_for_id(language_server_id)
9385 .map(|adapter| adapter.name()),
9386 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9387 Default::default(),
9388 ),
9389 })
9390 }
9391
9392 pub fn disk_based_diagnostics_finished(
9393 &mut self,
9394 language_server_id: LanguageServerId,
9395 cx: &mut Context<Self>,
9396 ) {
9397 if let Some(language_server_status) =
9398 self.language_server_statuses.get_mut(&language_server_id)
9399 {
9400 language_server_status.has_pending_diagnostic_updates = false;
9401 }
9402
9403 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9404 cx.emit(LspStoreEvent::LanguageServerUpdate {
9405 language_server_id,
9406 name: self
9407 .language_server_adapter_for_id(language_server_id)
9408 .map(|adapter| adapter.name()),
9409 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9410 Default::default(),
9411 ),
9412 })
9413 }
9414
9415 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9416 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9417 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9418 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9419 // the language server might take some time to publish diagnostics.
9420 fn simulate_disk_based_diagnostics_events_if_needed(
9421 &mut self,
9422 language_server_id: LanguageServerId,
9423 cx: &mut Context<Self>,
9424 ) {
9425 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9426
9427 let Some(LanguageServerState::Running {
9428 simulate_disk_based_diagnostics_completion,
9429 adapter,
9430 ..
9431 }) = self
9432 .as_local_mut()
9433 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9434 else {
9435 return;
9436 };
9437
9438 if adapter.disk_based_diagnostics_progress_token.is_some() {
9439 return;
9440 }
9441
9442 let prev_task =
9443 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9444 cx.background_executor()
9445 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9446 .await;
9447
9448 this.update(cx, |this, cx| {
9449 this.disk_based_diagnostics_finished(language_server_id, cx);
9450
9451 if let Some(LanguageServerState::Running {
9452 simulate_disk_based_diagnostics_completion,
9453 ..
9454 }) = this.as_local_mut().and_then(|local_store| {
9455 local_store.language_servers.get_mut(&language_server_id)
9456 }) {
9457 *simulate_disk_based_diagnostics_completion = None;
9458 }
9459 })
9460 .ok();
9461 }));
9462
9463 if prev_task.is_none() {
9464 self.disk_based_diagnostics_started(language_server_id, cx);
9465 }
9466 }
9467
9468 pub fn language_server_statuses(
9469 &self,
9470 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9471 self.language_server_statuses
9472 .iter()
9473 .map(|(key, value)| (*key, value))
9474 }
9475
9476 pub(super) fn did_rename_entry(
9477 &self,
9478 worktree_id: WorktreeId,
9479 old_path: &Path,
9480 new_path: &Path,
9481 is_dir: bool,
9482 ) {
9483 maybe!({
9484 let local_store = self.as_local()?;
9485
9486 let old_uri = lsp::Uri::from_file_path(old_path)
9487 .ok()
9488 .map(|uri| uri.to_string())?;
9489 let new_uri = lsp::Uri::from_file_path(new_path)
9490 .ok()
9491 .map(|uri| uri.to_string())?;
9492
9493 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9494 let Some(filter) = local_store
9495 .language_server_paths_watched_for_rename
9496 .get(&language_server.server_id())
9497 else {
9498 continue;
9499 };
9500
9501 if filter.should_send_did_rename(&old_uri, is_dir) {
9502 language_server
9503 .notify::<DidRenameFiles>(RenameFilesParams {
9504 files: vec![FileRename {
9505 old_uri: old_uri.clone(),
9506 new_uri: new_uri.clone(),
9507 }],
9508 })
9509 .ok();
9510 }
9511 }
9512 Some(())
9513 });
9514 }
9515
9516 pub(super) fn will_rename_entry(
9517 this: WeakEntity<Self>,
9518 worktree_id: WorktreeId,
9519 old_path: &Path,
9520 new_path: &Path,
9521 is_dir: bool,
9522 cx: AsyncApp,
9523 ) -> Task<ProjectTransaction> {
9524 let old_uri = lsp::Uri::from_file_path(old_path)
9525 .ok()
9526 .map(|uri| uri.to_string());
9527 let new_uri = lsp::Uri::from_file_path(new_path)
9528 .ok()
9529 .map(|uri| uri.to_string());
9530 cx.spawn(async move |cx| {
9531 let mut tasks = vec![];
9532 this.update(cx, |this, cx| {
9533 let local_store = this.as_local()?;
9534 let old_uri = old_uri?;
9535 let new_uri = new_uri?;
9536 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9537 let Some(filter) = local_store
9538 .language_server_paths_watched_for_rename
9539 .get(&language_server.server_id())
9540 else {
9541 continue;
9542 };
9543
9544 if filter.should_send_will_rename(&old_uri, is_dir) {
9545 let apply_edit = cx.spawn({
9546 let old_uri = old_uri.clone();
9547 let new_uri = new_uri.clone();
9548 let language_server = language_server.clone();
9549 async move |this, cx| {
9550 let edit = language_server
9551 .request::<WillRenameFiles>(RenameFilesParams {
9552 files: vec![FileRename { old_uri, new_uri }],
9553 })
9554 .await
9555 .into_response()
9556 .context("will rename files")
9557 .log_err()
9558 .flatten()?;
9559
9560 let transaction = LocalLspStore::deserialize_workspace_edit(
9561 this.upgrade()?,
9562 edit,
9563 false,
9564 language_server.clone(),
9565 cx,
9566 )
9567 .await
9568 .ok()?;
9569 Some(transaction)
9570 }
9571 });
9572 tasks.push(apply_edit);
9573 }
9574 }
9575 Some(())
9576 })
9577 .ok()
9578 .flatten();
9579 let mut merged_transaction = ProjectTransaction::default();
9580 for task in tasks {
9581 // Await on tasks sequentially so that the order of application of edits is deterministic
9582 // (at least with regards to the order of registration of language servers)
9583 if let Some(transaction) = task.await {
9584 for (buffer, buffer_transaction) in transaction.0 {
9585 merged_transaction.0.insert(buffer, buffer_transaction);
9586 }
9587 }
9588 }
9589 merged_transaction
9590 })
9591 }
9592
9593 fn lsp_notify_abs_paths_changed(
9594 &mut self,
9595 server_id: LanguageServerId,
9596 changes: Vec<PathEvent>,
9597 ) {
9598 maybe!({
9599 let server = self.language_server_for_id(server_id)?;
9600 let changes = changes
9601 .into_iter()
9602 .filter_map(|event| {
9603 let typ = match event.kind? {
9604 PathEventKind::Created => lsp::FileChangeType::CREATED,
9605 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9606 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9607 };
9608 Some(lsp::FileEvent {
9609 uri: file_path_to_lsp_url(&event.path).log_err()?,
9610 typ,
9611 })
9612 })
9613 .collect::<Vec<_>>();
9614 if !changes.is_empty() {
9615 server
9616 .notify::<lsp::notification::DidChangeWatchedFiles>(
9617 lsp::DidChangeWatchedFilesParams { changes },
9618 )
9619 .ok();
9620 }
9621 Some(())
9622 });
9623 }
9624
9625 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9626 self.as_local()?.language_server_for_id(id)
9627 }
9628
9629 fn on_lsp_progress(
9630 &mut self,
9631 progress_params: lsp::ProgressParams,
9632 language_server_id: LanguageServerId,
9633 disk_based_diagnostics_progress_token: Option<String>,
9634 cx: &mut Context<Self>,
9635 ) {
9636 match progress_params.value {
9637 lsp::ProgressParamsValue::WorkDone(progress) => {
9638 self.handle_work_done_progress(
9639 progress,
9640 language_server_id,
9641 disk_based_diagnostics_progress_token,
9642 ProgressToken::from_lsp(progress_params.token),
9643 cx,
9644 );
9645 }
9646 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9647 let identifier = match progress_params.token {
9648 lsp::NumberOrString::Number(_) => None,
9649 lsp::NumberOrString::String(token) => token
9650 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9651 .map(|(_, id)| id.to_owned()),
9652 };
9653 if let Some(LanguageServerState::Running {
9654 workspace_diagnostics_refresh_tasks,
9655 ..
9656 }) = self
9657 .as_local_mut()
9658 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9659 && let Some(workspace_diagnostics) =
9660 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9661 {
9662 workspace_diagnostics.progress_tx.try_send(()).ok();
9663 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9664 }
9665 }
9666 }
9667 }
9668
9669 fn handle_work_done_progress(
9670 &mut self,
9671 progress: lsp::WorkDoneProgress,
9672 language_server_id: LanguageServerId,
9673 disk_based_diagnostics_progress_token: Option<String>,
9674 token: ProgressToken,
9675 cx: &mut Context<Self>,
9676 ) {
9677 let language_server_status =
9678 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9679 status
9680 } else {
9681 return;
9682 };
9683
9684 if !language_server_status.progress_tokens.contains(&token) {
9685 return;
9686 }
9687
9688 let is_disk_based_diagnostics_progress =
9689 if let (Some(disk_based_token), ProgressToken::String(token)) =
9690 (&disk_based_diagnostics_progress_token, &token)
9691 {
9692 token.starts_with(disk_based_token)
9693 } else {
9694 false
9695 };
9696
9697 match progress {
9698 lsp::WorkDoneProgress::Begin(report) => {
9699 if is_disk_based_diagnostics_progress {
9700 self.disk_based_diagnostics_started(language_server_id, cx);
9701 }
9702 self.on_lsp_work_start(
9703 language_server_id,
9704 token.clone(),
9705 LanguageServerProgress {
9706 title: Some(report.title),
9707 is_disk_based_diagnostics_progress,
9708 is_cancellable: report.cancellable.unwrap_or(false),
9709 message: report.message.clone(),
9710 percentage: report.percentage.map(|p| p as usize),
9711 last_update_at: cx.background_executor().now(),
9712 },
9713 cx,
9714 );
9715 }
9716 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9717 language_server_id,
9718 token,
9719 LanguageServerProgress {
9720 title: None,
9721 is_disk_based_diagnostics_progress,
9722 is_cancellable: report.cancellable.unwrap_or(false),
9723 message: report.message,
9724 percentage: report.percentage.map(|p| p as usize),
9725 last_update_at: cx.background_executor().now(),
9726 },
9727 cx,
9728 ),
9729 lsp::WorkDoneProgress::End(_) => {
9730 language_server_status.progress_tokens.remove(&token);
9731 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9732 if is_disk_based_diagnostics_progress {
9733 self.disk_based_diagnostics_finished(language_server_id, cx);
9734 }
9735 }
9736 }
9737 }
9738
9739 fn on_lsp_work_start(
9740 &mut self,
9741 language_server_id: LanguageServerId,
9742 token: ProgressToken,
9743 progress: LanguageServerProgress,
9744 cx: &mut Context<Self>,
9745 ) {
9746 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9747 status.pending_work.insert(token.clone(), progress.clone());
9748 cx.notify();
9749 }
9750 cx.emit(LspStoreEvent::LanguageServerUpdate {
9751 language_server_id,
9752 name: self
9753 .language_server_adapter_for_id(language_server_id)
9754 .map(|adapter| adapter.name()),
9755 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9756 token: Some(token.to_proto()),
9757 title: progress.title,
9758 message: progress.message,
9759 percentage: progress.percentage.map(|p| p as u32),
9760 is_cancellable: Some(progress.is_cancellable),
9761 }),
9762 })
9763 }
9764
9765 fn on_lsp_work_progress(
9766 &mut self,
9767 language_server_id: LanguageServerId,
9768 token: ProgressToken,
9769 progress: LanguageServerProgress,
9770 cx: &mut Context<Self>,
9771 ) {
9772 let mut did_update = false;
9773 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9774 match status.pending_work.entry(token.clone()) {
9775 btree_map::Entry::Vacant(entry) => {
9776 entry.insert(progress.clone());
9777 did_update = true;
9778 }
9779 btree_map::Entry::Occupied(mut entry) => {
9780 let entry = entry.get_mut();
9781 if (progress.last_update_at - entry.last_update_at)
9782 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9783 {
9784 entry.last_update_at = progress.last_update_at;
9785 if progress.message.is_some() {
9786 entry.message = progress.message.clone();
9787 }
9788 if progress.percentage.is_some() {
9789 entry.percentage = progress.percentage;
9790 }
9791 if progress.is_cancellable != entry.is_cancellable {
9792 entry.is_cancellable = progress.is_cancellable;
9793 }
9794 did_update = true;
9795 }
9796 }
9797 }
9798 }
9799
9800 if did_update {
9801 cx.emit(LspStoreEvent::LanguageServerUpdate {
9802 language_server_id,
9803 name: self
9804 .language_server_adapter_for_id(language_server_id)
9805 .map(|adapter| adapter.name()),
9806 message: proto::update_language_server::Variant::WorkProgress(
9807 proto::LspWorkProgress {
9808 token: Some(token.to_proto()),
9809 message: progress.message,
9810 percentage: progress.percentage.map(|p| p as u32),
9811 is_cancellable: Some(progress.is_cancellable),
9812 },
9813 ),
9814 })
9815 }
9816 }
9817
9818 fn on_lsp_work_end(
9819 &mut self,
9820 language_server_id: LanguageServerId,
9821 token: ProgressToken,
9822 cx: &mut Context<Self>,
9823 ) {
9824 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9825 if let Some(work) = status.pending_work.remove(&token)
9826 && !work.is_disk_based_diagnostics_progress
9827 {
9828 cx.emit(LspStoreEvent::RefreshInlayHints {
9829 server_id: language_server_id,
9830 request_id: None,
9831 });
9832 }
9833 cx.notify();
9834 }
9835
9836 cx.emit(LspStoreEvent::LanguageServerUpdate {
9837 language_server_id,
9838 name: self
9839 .language_server_adapter_for_id(language_server_id)
9840 .map(|adapter| adapter.name()),
9841 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9842 token: Some(token.to_proto()),
9843 }),
9844 })
9845 }
9846
9847 pub async fn handle_resolve_completion_documentation(
9848 this: Entity<Self>,
9849 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9850 mut cx: AsyncApp,
9851 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9852 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9853
9854 let completion = this
9855 .read_with(&cx, |this, cx| {
9856 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9857 let server = this
9858 .language_server_for_id(id)
9859 .with_context(|| format!("No language server {id}"))?;
9860
9861 anyhow::Ok(cx.background_spawn(async move {
9862 let can_resolve = server
9863 .capabilities()
9864 .completion_provider
9865 .as_ref()
9866 .and_then(|options| options.resolve_provider)
9867 .unwrap_or(false);
9868 if can_resolve {
9869 server
9870 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9871 .await
9872 .into_response()
9873 .context("resolve completion item")
9874 } else {
9875 anyhow::Ok(lsp_completion)
9876 }
9877 }))
9878 })??
9879 .await?;
9880
9881 let mut documentation_is_markdown = false;
9882 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9883 let documentation = match completion.documentation {
9884 Some(lsp::Documentation::String(text)) => text,
9885
9886 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9887 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9888 value
9889 }
9890
9891 _ => String::new(),
9892 };
9893
9894 // If we have a new buffer_id, that means we're talking to a new client
9895 // and want to check for new text_edits in the completion too.
9896 let mut old_replace_start = None;
9897 let mut old_replace_end = None;
9898 let mut old_insert_start = None;
9899 let mut old_insert_end = None;
9900 let mut new_text = String::default();
9901 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9902 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9903 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9904 anyhow::Ok(buffer.read(cx).snapshot())
9905 })??;
9906
9907 if let Some(text_edit) = completion.text_edit.as_ref() {
9908 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9909
9910 if let Some(mut edit) = edit {
9911 LineEnding::normalize(&mut edit.new_text);
9912
9913 new_text = edit.new_text;
9914 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9915 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9916 if let Some(insert_range) = edit.insert_range {
9917 old_insert_start = Some(serialize_anchor(&insert_range.start));
9918 old_insert_end = Some(serialize_anchor(&insert_range.end));
9919 }
9920 }
9921 }
9922 }
9923
9924 Ok(proto::ResolveCompletionDocumentationResponse {
9925 documentation,
9926 documentation_is_markdown,
9927 old_replace_start,
9928 old_replace_end,
9929 new_text,
9930 lsp_completion,
9931 old_insert_start,
9932 old_insert_end,
9933 })
9934 }
9935
9936 async fn handle_on_type_formatting(
9937 this: Entity<Self>,
9938 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9939 mut cx: AsyncApp,
9940 ) -> Result<proto::OnTypeFormattingResponse> {
9941 let on_type_formatting = this.update(&mut cx, |this, cx| {
9942 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9943 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9944 let position = envelope
9945 .payload
9946 .position
9947 .and_then(deserialize_anchor)
9948 .context("invalid position")?;
9949 anyhow::Ok(this.apply_on_type_formatting(
9950 buffer,
9951 position,
9952 envelope.payload.trigger.clone(),
9953 cx,
9954 ))
9955 })??;
9956
9957 let transaction = on_type_formatting
9958 .await?
9959 .as_ref()
9960 .map(language::proto::serialize_transaction);
9961 Ok(proto::OnTypeFormattingResponse { transaction })
9962 }
9963
9964 async fn handle_refresh_inlay_hints(
9965 lsp_store: Entity<Self>,
9966 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9967 mut cx: AsyncApp,
9968 ) -> Result<proto::Ack> {
9969 lsp_store.update(&mut cx, |_, cx| {
9970 cx.emit(LspStoreEvent::RefreshInlayHints {
9971 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9972 request_id: envelope.payload.request_id.map(|id| id as usize),
9973 });
9974 })?;
9975 Ok(proto::Ack {})
9976 }
9977
9978 async fn handle_pull_workspace_diagnostics(
9979 lsp_store: Entity<Self>,
9980 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9981 mut cx: AsyncApp,
9982 ) -> Result<proto::Ack> {
9983 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9984 lsp_store.update(&mut cx, |lsp_store, _| {
9985 lsp_store.pull_workspace_diagnostics(server_id);
9986 })?;
9987 Ok(proto::Ack {})
9988 }
9989
9990 async fn handle_get_color_presentation(
9991 lsp_store: Entity<Self>,
9992 envelope: TypedEnvelope<proto::GetColorPresentation>,
9993 mut cx: AsyncApp,
9994 ) -> Result<proto::GetColorPresentationResponse> {
9995 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9996 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9997 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9998 })??;
9999
10000 let color = envelope
10001 .payload
10002 .color
10003 .context("invalid color resolve request")?;
10004 let start = color
10005 .lsp_range_start
10006 .context("invalid color resolve request")?;
10007 let end = color
10008 .lsp_range_end
10009 .context("invalid color resolve request")?;
10010
10011 let color = DocumentColor {
10012 lsp_range: lsp::Range {
10013 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10014 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10015 },
10016 color: lsp::Color {
10017 red: color.red,
10018 green: color.green,
10019 blue: color.blue,
10020 alpha: color.alpha,
10021 },
10022 resolved: false,
10023 color_presentations: Vec::new(),
10024 };
10025 let resolved_color = lsp_store
10026 .update(&mut cx, |lsp_store, cx| {
10027 lsp_store.resolve_color_presentation(
10028 color,
10029 buffer.clone(),
10030 LanguageServerId(envelope.payload.server_id as usize),
10031 cx,
10032 )
10033 })?
10034 .await
10035 .context("resolving color presentation")?;
10036
10037 Ok(proto::GetColorPresentationResponse {
10038 presentations: resolved_color
10039 .color_presentations
10040 .into_iter()
10041 .map(|presentation| proto::ColorPresentation {
10042 label: presentation.label.to_string(),
10043 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10044 additional_text_edits: presentation
10045 .additional_text_edits
10046 .into_iter()
10047 .map(serialize_lsp_edit)
10048 .collect(),
10049 })
10050 .collect(),
10051 })
10052 }
10053
10054 async fn handle_resolve_inlay_hint(
10055 lsp_store: Entity<Self>,
10056 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10057 mut cx: AsyncApp,
10058 ) -> Result<proto::ResolveInlayHintResponse> {
10059 let proto_hint = envelope
10060 .payload
10061 .hint
10062 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10063 let hint = InlayHints::proto_to_project_hint(proto_hint)
10064 .context("resolved proto inlay hint conversion")?;
10065 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10066 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10067 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10068 })??;
10069 let response_hint = lsp_store
10070 .update(&mut cx, |lsp_store, cx| {
10071 lsp_store.resolve_inlay_hint(
10072 hint,
10073 buffer,
10074 LanguageServerId(envelope.payload.language_server_id as usize),
10075 cx,
10076 )
10077 })?
10078 .await
10079 .context("inlay hints fetch")?;
10080 Ok(proto::ResolveInlayHintResponse {
10081 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10082 })
10083 }
10084
10085 async fn handle_refresh_code_lens(
10086 this: Entity<Self>,
10087 _: TypedEnvelope<proto::RefreshCodeLens>,
10088 mut cx: AsyncApp,
10089 ) -> Result<proto::Ack> {
10090 this.update(&mut cx, |_, cx| {
10091 cx.emit(LspStoreEvent::RefreshCodeLens);
10092 })?;
10093 Ok(proto::Ack {})
10094 }
10095
10096 async fn handle_open_buffer_for_symbol(
10097 this: Entity<Self>,
10098 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10099 mut cx: AsyncApp,
10100 ) -> Result<proto::OpenBufferForSymbolResponse> {
10101 let peer_id = envelope.original_sender_id().unwrap_or_default();
10102 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10103 let symbol = Self::deserialize_symbol(symbol)?;
10104 this.read_with(&cx, |this, _| {
10105 if let SymbolLocation::OutsideProject {
10106 abs_path,
10107 signature,
10108 } = &symbol.path
10109 {
10110 let new_signature = this.symbol_signature(&abs_path);
10111 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10112 }
10113 Ok(())
10114 })??;
10115 let buffer = this
10116 .update(&mut cx, |this, cx| {
10117 this.open_buffer_for_symbol(
10118 &Symbol {
10119 language_server_name: symbol.language_server_name,
10120 source_worktree_id: symbol.source_worktree_id,
10121 source_language_server_id: symbol.source_language_server_id,
10122 path: symbol.path,
10123 name: symbol.name,
10124 kind: symbol.kind,
10125 range: symbol.range,
10126 label: CodeLabel::default(),
10127 },
10128 cx,
10129 )
10130 })?
10131 .await?;
10132
10133 this.update(&mut cx, |this, cx| {
10134 let is_private = buffer
10135 .read(cx)
10136 .file()
10137 .map(|f| f.is_private())
10138 .unwrap_or_default();
10139 if is_private {
10140 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10141 } else {
10142 this.buffer_store
10143 .update(cx, |buffer_store, cx| {
10144 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10145 })
10146 .detach_and_log_err(cx);
10147 let buffer_id = buffer.read(cx).remote_id().to_proto();
10148 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10149 }
10150 })?
10151 }
10152
10153 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10154 let mut hasher = Sha256::new();
10155 hasher.update(abs_path.to_string_lossy().as_bytes());
10156 hasher.update(self.nonce.to_be_bytes());
10157 hasher.finalize().as_slice().try_into().unwrap()
10158 }
10159
10160 pub async fn handle_get_project_symbols(
10161 this: Entity<Self>,
10162 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10163 mut cx: AsyncApp,
10164 ) -> Result<proto::GetProjectSymbolsResponse> {
10165 let symbols = this
10166 .update(&mut cx, |this, cx| {
10167 this.symbols(&envelope.payload.query, cx)
10168 })?
10169 .await?;
10170
10171 Ok(proto::GetProjectSymbolsResponse {
10172 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10173 })
10174 }
10175
10176 pub async fn handle_restart_language_servers(
10177 this: Entity<Self>,
10178 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10179 mut cx: AsyncApp,
10180 ) -> Result<proto::Ack> {
10181 this.update(&mut cx, |lsp_store, cx| {
10182 let buffers =
10183 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10184 lsp_store.restart_language_servers_for_buffers(
10185 buffers,
10186 envelope
10187 .payload
10188 .only_servers
10189 .into_iter()
10190 .filter_map(|selector| {
10191 Some(match selector.selector? {
10192 proto::language_server_selector::Selector::ServerId(server_id) => {
10193 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10194 }
10195 proto::language_server_selector::Selector::Name(name) => {
10196 LanguageServerSelector::Name(LanguageServerName(
10197 SharedString::from(name),
10198 ))
10199 }
10200 })
10201 })
10202 .collect(),
10203 cx,
10204 );
10205 })?;
10206
10207 Ok(proto::Ack {})
10208 }
10209
10210 pub async fn handle_stop_language_servers(
10211 lsp_store: Entity<Self>,
10212 envelope: TypedEnvelope<proto::StopLanguageServers>,
10213 mut cx: AsyncApp,
10214 ) -> Result<proto::Ack> {
10215 lsp_store.update(&mut cx, |lsp_store, cx| {
10216 if envelope.payload.all
10217 && envelope.payload.also_servers.is_empty()
10218 && envelope.payload.buffer_ids.is_empty()
10219 {
10220 lsp_store.stop_all_language_servers(cx);
10221 } else {
10222 let buffers =
10223 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10224 lsp_store
10225 .stop_language_servers_for_buffers(
10226 buffers,
10227 envelope
10228 .payload
10229 .also_servers
10230 .into_iter()
10231 .filter_map(|selector| {
10232 Some(match selector.selector? {
10233 proto::language_server_selector::Selector::ServerId(
10234 server_id,
10235 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10236 server_id,
10237 )),
10238 proto::language_server_selector::Selector::Name(name) => {
10239 LanguageServerSelector::Name(LanguageServerName(
10240 SharedString::from(name),
10241 ))
10242 }
10243 })
10244 })
10245 .collect(),
10246 cx,
10247 )
10248 .detach_and_log_err(cx);
10249 }
10250 })?;
10251
10252 Ok(proto::Ack {})
10253 }
10254
10255 pub async fn handle_cancel_language_server_work(
10256 lsp_store: Entity<Self>,
10257 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10258 mut cx: AsyncApp,
10259 ) -> Result<proto::Ack> {
10260 lsp_store.update(&mut cx, |lsp_store, cx| {
10261 if let Some(work) = envelope.payload.work {
10262 match work {
10263 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10264 let buffers =
10265 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10266 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10267 }
10268 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10269 let server_id = LanguageServerId::from_proto(work.language_server_id);
10270 let token = work
10271 .token
10272 .map(|token| {
10273 ProgressToken::from_proto(token)
10274 .context("invalid work progress token")
10275 })
10276 .transpose()?;
10277 lsp_store.cancel_language_server_work(server_id, token, cx);
10278 }
10279 }
10280 }
10281 anyhow::Ok(())
10282 })??;
10283
10284 Ok(proto::Ack {})
10285 }
10286
10287 fn buffer_ids_to_buffers(
10288 &mut self,
10289 buffer_ids: impl Iterator<Item = u64>,
10290 cx: &mut Context<Self>,
10291 ) -> Vec<Entity<Buffer>> {
10292 buffer_ids
10293 .into_iter()
10294 .flat_map(|buffer_id| {
10295 self.buffer_store
10296 .read(cx)
10297 .get(BufferId::new(buffer_id).log_err()?)
10298 })
10299 .collect::<Vec<_>>()
10300 }
10301
10302 async fn handle_apply_additional_edits_for_completion(
10303 this: Entity<Self>,
10304 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10305 mut cx: AsyncApp,
10306 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10307 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10308 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10309 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10310 let completion = Self::deserialize_completion(
10311 envelope.payload.completion.context("invalid completion")?,
10312 )?;
10313 anyhow::Ok((buffer, completion))
10314 })??;
10315
10316 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10317 this.apply_additional_edits_for_completion(
10318 buffer,
10319 Rc::new(RefCell::new(Box::new([Completion {
10320 replace_range: completion.replace_range,
10321 new_text: completion.new_text,
10322 source: completion.source,
10323 documentation: None,
10324 label: CodeLabel::default(),
10325 match_start: None,
10326 snippet_deduplication_key: None,
10327 insert_text_mode: None,
10328 icon_path: None,
10329 confirm: None,
10330 }]))),
10331 0,
10332 false,
10333 cx,
10334 )
10335 })?;
10336
10337 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10338 transaction: apply_additional_edits
10339 .await?
10340 .as_ref()
10341 .map(language::proto::serialize_transaction),
10342 })
10343 }
10344
10345 pub fn last_formatting_failure(&self) -> Option<&str> {
10346 self.last_formatting_failure.as_deref()
10347 }
10348
10349 pub fn reset_last_formatting_failure(&mut self) {
10350 self.last_formatting_failure = None;
10351 }
10352
10353 pub fn environment_for_buffer(
10354 &self,
10355 buffer: &Entity<Buffer>,
10356 cx: &mut Context<Self>,
10357 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10358 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10359 environment.update(cx, |env, cx| {
10360 env.buffer_environment(buffer, &self.worktree_store, cx)
10361 })
10362 } else {
10363 Task::ready(None).shared()
10364 }
10365 }
10366
10367 pub fn format(
10368 &mut self,
10369 buffers: HashSet<Entity<Buffer>>,
10370 target: LspFormatTarget,
10371 push_to_history: bool,
10372 trigger: FormatTrigger,
10373 cx: &mut Context<Self>,
10374 ) -> Task<anyhow::Result<ProjectTransaction>> {
10375 let logger = zlog::scoped!("format");
10376 if self.as_local().is_some() {
10377 zlog::trace!(logger => "Formatting locally");
10378 let logger = zlog::scoped!(logger => "local");
10379 let buffers = buffers
10380 .into_iter()
10381 .map(|buffer_handle| {
10382 let buffer = buffer_handle.read(cx);
10383 let buffer_abs_path = File::from_dyn(buffer.file())
10384 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10385
10386 (buffer_handle, buffer_abs_path, buffer.remote_id())
10387 })
10388 .collect::<Vec<_>>();
10389
10390 cx.spawn(async move |lsp_store, cx| {
10391 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10392
10393 for (handle, abs_path, id) in buffers {
10394 let env = lsp_store
10395 .update(cx, |lsp_store, cx| {
10396 lsp_store.environment_for_buffer(&handle, cx)
10397 })?
10398 .await;
10399
10400 let ranges = match &target {
10401 LspFormatTarget::Buffers => None,
10402 LspFormatTarget::Ranges(ranges) => {
10403 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10404 }
10405 };
10406
10407 formattable_buffers.push(FormattableBuffer {
10408 handle,
10409 abs_path,
10410 env,
10411 ranges,
10412 });
10413 }
10414 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10415
10416 let format_timer = zlog::time!(logger => "Formatting buffers");
10417 let result = LocalLspStore::format_locally(
10418 lsp_store.clone(),
10419 formattable_buffers,
10420 push_to_history,
10421 trigger,
10422 logger,
10423 cx,
10424 )
10425 .await;
10426 format_timer.end();
10427
10428 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10429
10430 lsp_store.update(cx, |lsp_store, _| {
10431 lsp_store.update_last_formatting_failure(&result);
10432 })?;
10433
10434 result
10435 })
10436 } else if let Some((client, project_id)) = self.upstream_client() {
10437 zlog::trace!(logger => "Formatting remotely");
10438 let logger = zlog::scoped!(logger => "remote");
10439 // Don't support formatting ranges via remote
10440 match target {
10441 LspFormatTarget::Buffers => {}
10442 LspFormatTarget::Ranges(_) => {
10443 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10444 return Task::ready(Ok(ProjectTransaction::default()));
10445 }
10446 }
10447
10448 let buffer_store = self.buffer_store();
10449 cx.spawn(async move |lsp_store, cx| {
10450 zlog::trace!(logger => "Sending remote format request");
10451 let request_timer = zlog::time!(logger => "remote format request");
10452 let result = client
10453 .request(proto::FormatBuffers {
10454 project_id,
10455 trigger: trigger as i32,
10456 buffer_ids: buffers
10457 .iter()
10458 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10459 .collect::<Result<_>>()?,
10460 })
10461 .await
10462 .and_then(|result| result.transaction.context("missing transaction"));
10463 request_timer.end();
10464
10465 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10466
10467 lsp_store.update(cx, |lsp_store, _| {
10468 lsp_store.update_last_formatting_failure(&result);
10469 })?;
10470
10471 let transaction_response = result?;
10472 let _timer = zlog::time!(logger => "deserializing project transaction");
10473 buffer_store
10474 .update(cx, |buffer_store, cx| {
10475 buffer_store.deserialize_project_transaction(
10476 transaction_response,
10477 push_to_history,
10478 cx,
10479 )
10480 })?
10481 .await
10482 })
10483 } else {
10484 zlog::trace!(logger => "Not formatting");
10485 Task::ready(Ok(ProjectTransaction::default()))
10486 }
10487 }
10488
10489 async fn handle_format_buffers(
10490 this: Entity<Self>,
10491 envelope: TypedEnvelope<proto::FormatBuffers>,
10492 mut cx: AsyncApp,
10493 ) -> Result<proto::FormatBuffersResponse> {
10494 let sender_id = envelope.original_sender_id().unwrap_or_default();
10495 let format = this.update(&mut cx, |this, cx| {
10496 let mut buffers = HashSet::default();
10497 for buffer_id in &envelope.payload.buffer_ids {
10498 let buffer_id = BufferId::new(*buffer_id)?;
10499 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10500 }
10501 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10502 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10503 })??;
10504
10505 let project_transaction = format.await?;
10506 let project_transaction = this.update(&mut cx, |this, cx| {
10507 this.buffer_store.update(cx, |buffer_store, cx| {
10508 buffer_store.serialize_project_transaction_for_peer(
10509 project_transaction,
10510 sender_id,
10511 cx,
10512 )
10513 })
10514 })?;
10515 Ok(proto::FormatBuffersResponse {
10516 transaction: Some(project_transaction),
10517 })
10518 }
10519
10520 async fn handle_apply_code_action_kind(
10521 this: Entity<Self>,
10522 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10523 mut cx: AsyncApp,
10524 ) -> Result<proto::ApplyCodeActionKindResponse> {
10525 let sender_id = envelope.original_sender_id().unwrap_or_default();
10526 let format = this.update(&mut cx, |this, cx| {
10527 let mut buffers = HashSet::default();
10528 for buffer_id in &envelope.payload.buffer_ids {
10529 let buffer_id = BufferId::new(*buffer_id)?;
10530 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10531 }
10532 let kind = match envelope.payload.kind.as_str() {
10533 "" => CodeActionKind::EMPTY,
10534 "quickfix" => CodeActionKind::QUICKFIX,
10535 "refactor" => CodeActionKind::REFACTOR,
10536 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10537 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10538 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10539 "source" => CodeActionKind::SOURCE,
10540 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10541 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10542 _ => anyhow::bail!(
10543 "Invalid code action kind {}",
10544 envelope.payload.kind.as_str()
10545 ),
10546 };
10547 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10548 })??;
10549
10550 let project_transaction = format.await?;
10551 let project_transaction = this.update(&mut cx, |this, cx| {
10552 this.buffer_store.update(cx, |buffer_store, cx| {
10553 buffer_store.serialize_project_transaction_for_peer(
10554 project_transaction,
10555 sender_id,
10556 cx,
10557 )
10558 })
10559 })?;
10560 Ok(proto::ApplyCodeActionKindResponse {
10561 transaction: Some(project_transaction),
10562 })
10563 }
10564
10565 async fn shutdown_language_server(
10566 server_state: Option<LanguageServerState>,
10567 name: LanguageServerName,
10568 cx: &mut AsyncApp,
10569 ) {
10570 let server = match server_state {
10571 Some(LanguageServerState::Starting { startup, .. }) => {
10572 let mut timer = cx
10573 .background_executor()
10574 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10575 .fuse();
10576
10577 select! {
10578 server = startup.fuse() => server,
10579 () = timer => {
10580 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10581 None
10582 },
10583 }
10584 }
10585
10586 Some(LanguageServerState::Running { server, .. }) => Some(server),
10587
10588 None => None,
10589 };
10590
10591 if let Some(server) = server
10592 && let Some(shutdown) = server.shutdown()
10593 {
10594 shutdown.await;
10595 }
10596 }
10597
10598 // Returns a list of all of the worktrees which no longer have a language server and the root path
10599 // for the stopped server
10600 fn stop_local_language_server(
10601 &mut self,
10602 server_id: LanguageServerId,
10603 cx: &mut Context<Self>,
10604 ) -> Task<()> {
10605 let local = match &mut self.mode {
10606 LspStoreMode::Local(local) => local,
10607 _ => {
10608 return Task::ready(());
10609 }
10610 };
10611
10612 // Remove this server ID from all entries in the given worktree.
10613 local
10614 .language_server_ids
10615 .retain(|_, state| state.id != server_id);
10616 self.buffer_store.update(cx, |buffer_store, cx| {
10617 for buffer in buffer_store.buffers() {
10618 buffer.update(cx, |buffer, cx| {
10619 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10620 buffer.set_completion_triggers(server_id, Default::default(), cx);
10621 });
10622 }
10623 });
10624
10625 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10626 summaries.retain(|path, summaries_by_server_id| {
10627 if summaries_by_server_id.remove(&server_id).is_some() {
10628 if let Some((client, project_id)) = self.downstream_client.clone() {
10629 client
10630 .send(proto::UpdateDiagnosticSummary {
10631 project_id,
10632 worktree_id: worktree_id.to_proto(),
10633 summary: Some(proto::DiagnosticSummary {
10634 path: path.as_ref().to_proto(),
10635 language_server_id: server_id.0 as u64,
10636 error_count: 0,
10637 warning_count: 0,
10638 }),
10639 more_summaries: Vec::new(),
10640 })
10641 .log_err();
10642 }
10643 !summaries_by_server_id.is_empty()
10644 } else {
10645 true
10646 }
10647 });
10648 }
10649
10650 let local = self.as_local_mut().unwrap();
10651 for diagnostics in local.diagnostics.values_mut() {
10652 diagnostics.retain(|_, diagnostics_by_server_id| {
10653 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10654 diagnostics_by_server_id.remove(ix);
10655 !diagnostics_by_server_id.is_empty()
10656 } else {
10657 true
10658 }
10659 });
10660 }
10661 local.language_server_watched_paths.remove(&server_id);
10662
10663 let server_state = local.language_servers.remove(&server_id);
10664 self.cleanup_lsp_data(server_id);
10665 let name = self
10666 .language_server_statuses
10667 .remove(&server_id)
10668 .map(|status| status.name)
10669 .or_else(|| {
10670 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10671 Some(adapter.name())
10672 } else {
10673 None
10674 }
10675 });
10676
10677 if let Some(name) = name {
10678 log::info!("stopping language server {name}");
10679 self.languages
10680 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10681 cx.notify();
10682
10683 return cx.spawn(async move |lsp_store, cx| {
10684 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10685 lsp_store
10686 .update(cx, |lsp_store, cx| {
10687 lsp_store
10688 .languages
10689 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10690 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10691 cx.notify();
10692 })
10693 .ok();
10694 });
10695 }
10696
10697 if server_state.is_some() {
10698 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10699 }
10700 Task::ready(())
10701 }
10702
10703 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10704 if let Some((client, project_id)) = self.upstream_client() {
10705 let request = client.request(proto::StopLanguageServers {
10706 project_id,
10707 buffer_ids: Vec::new(),
10708 also_servers: Vec::new(),
10709 all: true,
10710 });
10711 cx.background_spawn(request).detach_and_log_err(cx);
10712 } else {
10713 let Some(local) = self.as_local_mut() else {
10714 return;
10715 };
10716 let language_servers_to_stop = local
10717 .language_server_ids
10718 .values()
10719 .map(|state| state.id)
10720 .collect();
10721 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10722 let tasks = language_servers_to_stop
10723 .into_iter()
10724 .map(|server| self.stop_local_language_server(server, cx))
10725 .collect::<Vec<_>>();
10726 cx.background_spawn(async move {
10727 futures::future::join_all(tasks).await;
10728 })
10729 .detach();
10730 }
10731 }
10732
10733 pub fn restart_language_servers_for_buffers(
10734 &mut self,
10735 buffers: Vec<Entity<Buffer>>,
10736 only_restart_servers: HashSet<LanguageServerSelector>,
10737 cx: &mut Context<Self>,
10738 ) {
10739 if let Some((client, project_id)) = self.upstream_client() {
10740 let request = client.request(proto::RestartLanguageServers {
10741 project_id,
10742 buffer_ids: buffers
10743 .into_iter()
10744 .map(|b| b.read(cx).remote_id().to_proto())
10745 .collect(),
10746 only_servers: only_restart_servers
10747 .into_iter()
10748 .map(|selector| {
10749 let selector = match selector {
10750 LanguageServerSelector::Id(language_server_id) => {
10751 proto::language_server_selector::Selector::ServerId(
10752 language_server_id.to_proto(),
10753 )
10754 }
10755 LanguageServerSelector::Name(language_server_name) => {
10756 proto::language_server_selector::Selector::Name(
10757 language_server_name.to_string(),
10758 )
10759 }
10760 };
10761 proto::LanguageServerSelector {
10762 selector: Some(selector),
10763 }
10764 })
10765 .collect(),
10766 all: false,
10767 });
10768 cx.background_spawn(request).detach_and_log_err(cx);
10769 } else {
10770 let stop_task = if only_restart_servers.is_empty() {
10771 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10772 } else {
10773 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10774 };
10775 cx.spawn(async move |lsp_store, cx| {
10776 stop_task.await;
10777 lsp_store
10778 .update(cx, |lsp_store, cx| {
10779 for buffer in buffers {
10780 lsp_store.register_buffer_with_language_servers(
10781 &buffer,
10782 only_restart_servers.clone(),
10783 true,
10784 cx,
10785 );
10786 }
10787 })
10788 .ok()
10789 })
10790 .detach();
10791 }
10792 }
10793
10794 pub fn stop_language_servers_for_buffers(
10795 &mut self,
10796 buffers: Vec<Entity<Buffer>>,
10797 also_stop_servers: HashSet<LanguageServerSelector>,
10798 cx: &mut Context<Self>,
10799 ) -> Task<Result<()>> {
10800 if let Some((client, project_id)) = self.upstream_client() {
10801 let request = client.request(proto::StopLanguageServers {
10802 project_id,
10803 buffer_ids: buffers
10804 .into_iter()
10805 .map(|b| b.read(cx).remote_id().to_proto())
10806 .collect(),
10807 also_servers: also_stop_servers
10808 .into_iter()
10809 .map(|selector| {
10810 let selector = match selector {
10811 LanguageServerSelector::Id(language_server_id) => {
10812 proto::language_server_selector::Selector::ServerId(
10813 language_server_id.to_proto(),
10814 )
10815 }
10816 LanguageServerSelector::Name(language_server_name) => {
10817 proto::language_server_selector::Selector::Name(
10818 language_server_name.to_string(),
10819 )
10820 }
10821 };
10822 proto::LanguageServerSelector {
10823 selector: Some(selector),
10824 }
10825 })
10826 .collect(),
10827 all: false,
10828 });
10829 cx.background_spawn(async move {
10830 let _ = request.await?;
10831 Ok(())
10832 })
10833 } else {
10834 let task =
10835 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10836 cx.background_spawn(async move {
10837 task.await;
10838 Ok(())
10839 })
10840 }
10841 }
10842
10843 fn stop_local_language_servers_for_buffers(
10844 &mut self,
10845 buffers: &[Entity<Buffer>],
10846 also_stop_servers: HashSet<LanguageServerSelector>,
10847 cx: &mut Context<Self>,
10848 ) -> Task<()> {
10849 let Some(local) = self.as_local_mut() else {
10850 return Task::ready(());
10851 };
10852 let mut language_server_names_to_stop = BTreeSet::default();
10853 let mut language_servers_to_stop = also_stop_servers
10854 .into_iter()
10855 .flat_map(|selector| match selector {
10856 LanguageServerSelector::Id(id) => Some(id),
10857 LanguageServerSelector::Name(name) => {
10858 language_server_names_to_stop.insert(name);
10859 None
10860 }
10861 })
10862 .collect::<BTreeSet<_>>();
10863
10864 let mut covered_worktrees = HashSet::default();
10865 for buffer in buffers {
10866 buffer.update(cx, |buffer, cx| {
10867 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10868 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10869 && covered_worktrees.insert(worktree_id)
10870 {
10871 language_server_names_to_stop.retain(|name| {
10872 let old_ids_count = language_servers_to_stop.len();
10873 let all_language_servers_with_this_name = local
10874 .language_server_ids
10875 .iter()
10876 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10877 language_servers_to_stop.extend(all_language_servers_with_this_name);
10878 old_ids_count == language_servers_to_stop.len()
10879 });
10880 }
10881 });
10882 }
10883 for name in language_server_names_to_stop {
10884 language_servers_to_stop.extend(
10885 local
10886 .language_server_ids
10887 .iter()
10888 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10889 );
10890 }
10891
10892 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10893 let tasks = language_servers_to_stop
10894 .into_iter()
10895 .map(|server| self.stop_local_language_server(server, cx))
10896 .collect::<Vec<_>>();
10897
10898 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10899 }
10900
10901 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10902 let (worktree, relative_path) =
10903 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10904
10905 let project_path = ProjectPath {
10906 worktree_id: worktree.read(cx).id(),
10907 path: relative_path,
10908 };
10909
10910 Some(
10911 self.buffer_store()
10912 .read(cx)
10913 .get_by_path(&project_path)?
10914 .read(cx),
10915 )
10916 }
10917
10918 #[cfg(any(test, feature = "test-support"))]
10919 pub fn update_diagnostics(
10920 &mut self,
10921 server_id: LanguageServerId,
10922 diagnostics: lsp::PublishDiagnosticsParams,
10923 result_id: Option<String>,
10924 source_kind: DiagnosticSourceKind,
10925 disk_based_sources: &[String],
10926 cx: &mut Context<Self>,
10927 ) -> Result<()> {
10928 self.merge_lsp_diagnostics(
10929 source_kind,
10930 vec![DocumentDiagnosticsUpdate {
10931 diagnostics,
10932 result_id,
10933 server_id,
10934 disk_based_sources: Cow::Borrowed(disk_based_sources),
10935 }],
10936 |_, _, _| false,
10937 cx,
10938 )
10939 }
10940
10941 pub fn merge_lsp_diagnostics(
10942 &mut self,
10943 source_kind: DiagnosticSourceKind,
10944 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10945 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10946 cx: &mut Context<Self>,
10947 ) -> Result<()> {
10948 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10949 let updates = lsp_diagnostics
10950 .into_iter()
10951 .filter_map(|update| {
10952 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10953 Some(DocumentDiagnosticsUpdate {
10954 diagnostics: self.lsp_to_document_diagnostics(
10955 abs_path,
10956 source_kind,
10957 update.server_id,
10958 update.diagnostics,
10959 &update.disk_based_sources,
10960 ),
10961 result_id: update.result_id,
10962 server_id: update.server_id,
10963 disk_based_sources: update.disk_based_sources,
10964 })
10965 })
10966 .collect();
10967 self.merge_diagnostic_entries(updates, merge, cx)?;
10968 Ok(())
10969 }
10970
10971 fn lsp_to_document_diagnostics(
10972 &mut self,
10973 document_abs_path: PathBuf,
10974 source_kind: DiagnosticSourceKind,
10975 server_id: LanguageServerId,
10976 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10977 disk_based_sources: &[String],
10978 ) -> DocumentDiagnostics {
10979 let mut diagnostics = Vec::default();
10980 let mut primary_diagnostic_group_ids = HashMap::default();
10981 let mut sources_by_group_id = HashMap::default();
10982 let mut supporting_diagnostics = HashMap::default();
10983
10984 let adapter = self.language_server_adapter_for_id(server_id);
10985
10986 // Ensure that primary diagnostics are always the most severe
10987 lsp_diagnostics
10988 .diagnostics
10989 .sort_by_key(|item| item.severity);
10990
10991 for diagnostic in &lsp_diagnostics.diagnostics {
10992 let source = diagnostic.source.as_ref();
10993 let range = range_from_lsp(diagnostic.range);
10994 let is_supporting = diagnostic
10995 .related_information
10996 .as_ref()
10997 .is_some_and(|infos| {
10998 infos.iter().any(|info| {
10999 primary_diagnostic_group_ids.contains_key(&(
11000 source,
11001 diagnostic.code.clone(),
11002 range_from_lsp(info.location.range),
11003 ))
11004 })
11005 });
11006
11007 let is_unnecessary = diagnostic
11008 .tags
11009 .as_ref()
11010 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11011
11012 let underline = self
11013 .language_server_adapter_for_id(server_id)
11014 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11015
11016 if is_supporting {
11017 supporting_diagnostics.insert(
11018 (source, diagnostic.code.clone(), range),
11019 (diagnostic.severity, is_unnecessary),
11020 );
11021 } else {
11022 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11023 let is_disk_based =
11024 source.is_some_and(|source| disk_based_sources.contains(source));
11025
11026 sources_by_group_id.insert(group_id, source);
11027 primary_diagnostic_group_ids
11028 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11029
11030 diagnostics.push(DiagnosticEntry {
11031 range,
11032 diagnostic: Diagnostic {
11033 source: diagnostic.source.clone(),
11034 source_kind,
11035 code: diagnostic.code.clone(),
11036 code_description: diagnostic
11037 .code_description
11038 .as_ref()
11039 .and_then(|d| d.href.clone()),
11040 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11041 markdown: adapter.as_ref().and_then(|adapter| {
11042 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11043 }),
11044 message: diagnostic.message.trim().to_string(),
11045 group_id,
11046 is_primary: true,
11047 is_disk_based,
11048 is_unnecessary,
11049 underline,
11050 data: diagnostic.data.clone(),
11051 },
11052 });
11053 if let Some(infos) = &diagnostic.related_information {
11054 for info in infos {
11055 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11056 let range = range_from_lsp(info.location.range);
11057 diagnostics.push(DiagnosticEntry {
11058 range,
11059 diagnostic: Diagnostic {
11060 source: diagnostic.source.clone(),
11061 source_kind,
11062 code: diagnostic.code.clone(),
11063 code_description: diagnostic
11064 .code_description
11065 .as_ref()
11066 .and_then(|d| d.href.clone()),
11067 severity: DiagnosticSeverity::INFORMATION,
11068 markdown: adapter.as_ref().and_then(|adapter| {
11069 adapter.diagnostic_message_to_markdown(&info.message)
11070 }),
11071 message: info.message.trim().to_string(),
11072 group_id,
11073 is_primary: false,
11074 is_disk_based,
11075 is_unnecessary: false,
11076 underline,
11077 data: diagnostic.data.clone(),
11078 },
11079 });
11080 }
11081 }
11082 }
11083 }
11084 }
11085
11086 for entry in &mut diagnostics {
11087 let diagnostic = &mut entry.diagnostic;
11088 if !diagnostic.is_primary {
11089 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11090 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11091 source,
11092 diagnostic.code.clone(),
11093 entry.range.clone(),
11094 )) {
11095 if let Some(severity) = severity {
11096 diagnostic.severity = severity;
11097 }
11098 diagnostic.is_unnecessary = is_unnecessary;
11099 }
11100 }
11101 }
11102
11103 DocumentDiagnostics {
11104 diagnostics,
11105 document_abs_path,
11106 version: lsp_diagnostics.version,
11107 }
11108 }
11109
11110 fn insert_newly_running_language_server(
11111 &mut self,
11112 adapter: Arc<CachedLspAdapter>,
11113 language_server: Arc<LanguageServer>,
11114 server_id: LanguageServerId,
11115 key: LanguageServerSeed,
11116 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11117 cx: &mut Context<Self>,
11118 ) {
11119 let Some(local) = self.as_local_mut() else {
11120 return;
11121 };
11122 // If the language server for this key doesn't match the server id, don't store the
11123 // server. Which will cause it to be dropped, killing the process
11124 if local
11125 .language_server_ids
11126 .get(&key)
11127 .map(|state| state.id != server_id)
11128 .unwrap_or(false)
11129 {
11130 return;
11131 }
11132
11133 // Update language_servers collection with Running variant of LanguageServerState
11134 // indicating that the server is up and running and ready
11135 let workspace_folders = workspace_folders.lock().clone();
11136 language_server.set_workspace_folders(workspace_folders);
11137
11138 let workspace_diagnostics_refresh_tasks = language_server
11139 .capabilities()
11140 .diagnostic_provider
11141 .and_then(|provider| {
11142 local
11143 .language_server_dynamic_registrations
11144 .entry(server_id)
11145 .or_default()
11146 .diagnostics
11147 .entry(None)
11148 .or_insert(provider.clone());
11149 let workspace_refresher =
11150 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11151
11152 Some((None, workspace_refresher))
11153 })
11154 .into_iter()
11155 .collect();
11156 local.language_servers.insert(
11157 server_id,
11158 LanguageServerState::Running {
11159 workspace_diagnostics_refresh_tasks,
11160 adapter: adapter.clone(),
11161 server: language_server.clone(),
11162 simulate_disk_based_diagnostics_completion: None,
11163 },
11164 );
11165 local
11166 .languages
11167 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11168 if let Some(file_ops_caps) = language_server
11169 .capabilities()
11170 .workspace
11171 .as_ref()
11172 .and_then(|ws| ws.file_operations.as_ref())
11173 {
11174 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11175 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11176 if did_rename_caps.or(will_rename_caps).is_some() {
11177 let watcher = RenamePathsWatchedForServer::default()
11178 .with_did_rename_patterns(did_rename_caps)
11179 .with_will_rename_patterns(will_rename_caps);
11180 local
11181 .language_server_paths_watched_for_rename
11182 .insert(server_id, watcher);
11183 }
11184 }
11185
11186 self.language_server_statuses.insert(
11187 server_id,
11188 LanguageServerStatus {
11189 name: language_server.name(),
11190 pending_work: Default::default(),
11191 has_pending_diagnostic_updates: false,
11192 progress_tokens: Default::default(),
11193 worktree: Some(key.worktree_id),
11194 binary: Some(language_server.binary().clone()),
11195 configuration: Some(language_server.configuration().clone()),
11196 workspace_folders: language_server.workspace_folders(),
11197 },
11198 );
11199
11200 cx.emit(LspStoreEvent::LanguageServerAdded(
11201 server_id,
11202 language_server.name(),
11203 Some(key.worktree_id),
11204 ));
11205
11206 let server_capabilities = language_server.capabilities();
11207 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11208 downstream_client
11209 .send(proto::StartLanguageServer {
11210 project_id: *project_id,
11211 server: Some(proto::LanguageServer {
11212 id: server_id.to_proto(),
11213 name: language_server.name().to_string(),
11214 worktree_id: Some(key.worktree_id.to_proto()),
11215 }),
11216 capabilities: serde_json::to_string(&server_capabilities)
11217 .expect("serializing server LSP capabilities"),
11218 })
11219 .log_err();
11220 }
11221 self.lsp_server_capabilities
11222 .insert(server_id, server_capabilities);
11223
11224 // Tell the language server about every open buffer in the worktree that matches the language.
11225 // Also check for buffers in worktrees that reused this server
11226 let mut worktrees_using_server = vec![key.worktree_id];
11227 if let Some(local) = self.as_local() {
11228 // Find all worktrees that have this server in their language server tree
11229 for (worktree_id, servers) in &local.lsp_tree.instances {
11230 if *worktree_id != key.worktree_id {
11231 for server_map in servers.roots.values() {
11232 if server_map
11233 .values()
11234 .any(|(node, _)| node.id() == Some(server_id))
11235 {
11236 worktrees_using_server.push(*worktree_id);
11237 }
11238 }
11239 }
11240 }
11241 }
11242
11243 let mut buffer_paths_registered = Vec::new();
11244 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11245 let mut lsp_adapters = HashMap::default();
11246 for buffer_handle in buffer_store.buffers() {
11247 let buffer = buffer_handle.read(cx);
11248 let file = match File::from_dyn(buffer.file()) {
11249 Some(file) => file,
11250 None => continue,
11251 };
11252 let language = match buffer.language() {
11253 Some(language) => language,
11254 None => continue,
11255 };
11256
11257 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11258 || !lsp_adapters
11259 .entry(language.name())
11260 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11261 .iter()
11262 .any(|a| a.name == key.name)
11263 {
11264 continue;
11265 }
11266 // didOpen
11267 let file = match file.as_local() {
11268 Some(file) => file,
11269 None => continue,
11270 };
11271
11272 let local = self.as_local_mut().unwrap();
11273
11274 let buffer_id = buffer.remote_id();
11275 if local.registered_buffers.contains_key(&buffer_id) {
11276 let versions = local
11277 .buffer_snapshots
11278 .entry(buffer_id)
11279 .or_default()
11280 .entry(server_id)
11281 .and_modify(|_| {
11282 assert!(
11283 false,
11284 "There should not be an existing snapshot for a newly inserted buffer"
11285 )
11286 })
11287 .or_insert_with(|| {
11288 vec![LspBufferSnapshot {
11289 version: 0,
11290 snapshot: buffer.text_snapshot(),
11291 }]
11292 });
11293
11294 let snapshot = versions.last().unwrap();
11295 let version = snapshot.version;
11296 let initial_snapshot = &snapshot.snapshot;
11297 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11298 language_server.register_buffer(
11299 uri,
11300 adapter.language_id(&language.name()),
11301 version,
11302 initial_snapshot.text(),
11303 );
11304 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11305 local
11306 .buffers_opened_in_servers
11307 .entry(buffer_id)
11308 .or_default()
11309 .insert(server_id);
11310 }
11311 buffer_handle.update(cx, |buffer, cx| {
11312 buffer.set_completion_triggers(
11313 server_id,
11314 language_server
11315 .capabilities()
11316 .completion_provider
11317 .as_ref()
11318 .and_then(|provider| {
11319 provider
11320 .trigger_characters
11321 .as_ref()
11322 .map(|characters| characters.iter().cloned().collect())
11323 })
11324 .unwrap_or_default(),
11325 cx,
11326 )
11327 });
11328 }
11329 });
11330
11331 for (buffer_id, abs_path) in buffer_paths_registered {
11332 cx.emit(LspStoreEvent::LanguageServerUpdate {
11333 language_server_id: server_id,
11334 name: Some(adapter.name()),
11335 message: proto::update_language_server::Variant::RegisteredForBuffer(
11336 proto::RegisteredForBuffer {
11337 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11338 buffer_id: buffer_id.to_proto(),
11339 },
11340 ),
11341 });
11342 }
11343
11344 cx.notify();
11345 }
11346
11347 pub fn language_servers_running_disk_based_diagnostics(
11348 &self,
11349 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11350 self.language_server_statuses
11351 .iter()
11352 .filter_map(|(id, status)| {
11353 if status.has_pending_diagnostic_updates {
11354 Some(*id)
11355 } else {
11356 None
11357 }
11358 })
11359 }
11360
11361 pub(crate) fn cancel_language_server_work_for_buffers(
11362 &mut self,
11363 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11364 cx: &mut Context<Self>,
11365 ) {
11366 if let Some((client, project_id)) = self.upstream_client() {
11367 let request = client.request(proto::CancelLanguageServerWork {
11368 project_id,
11369 work: Some(proto::cancel_language_server_work::Work::Buffers(
11370 proto::cancel_language_server_work::Buffers {
11371 buffer_ids: buffers
11372 .into_iter()
11373 .map(|b| b.read(cx).remote_id().to_proto())
11374 .collect(),
11375 },
11376 )),
11377 });
11378 cx.background_spawn(request).detach_and_log_err(cx);
11379 } else if let Some(local) = self.as_local() {
11380 let servers = buffers
11381 .into_iter()
11382 .flat_map(|buffer| {
11383 buffer.update(cx, |buffer, cx| {
11384 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11385 })
11386 })
11387 .collect::<HashSet<_>>();
11388 for server_id in servers {
11389 self.cancel_language_server_work(server_id, None, cx);
11390 }
11391 }
11392 }
11393
11394 pub(crate) fn cancel_language_server_work(
11395 &mut self,
11396 server_id: LanguageServerId,
11397 token_to_cancel: Option<ProgressToken>,
11398 cx: &mut Context<Self>,
11399 ) {
11400 if let Some(local) = self.as_local() {
11401 let status = self.language_server_statuses.get(&server_id);
11402 let server = local.language_servers.get(&server_id);
11403 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11404 {
11405 for (token, progress) in &status.pending_work {
11406 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11407 && token != token_to_cancel
11408 {
11409 continue;
11410 }
11411 if progress.is_cancellable {
11412 server
11413 .notify::<lsp::notification::WorkDoneProgressCancel>(
11414 WorkDoneProgressCancelParams {
11415 token: token.to_lsp(),
11416 },
11417 )
11418 .ok();
11419 }
11420 }
11421 }
11422 } else if let Some((client, project_id)) = self.upstream_client() {
11423 let request = client.request(proto::CancelLanguageServerWork {
11424 project_id,
11425 work: Some(
11426 proto::cancel_language_server_work::Work::LanguageServerWork(
11427 proto::cancel_language_server_work::LanguageServerWork {
11428 language_server_id: server_id.to_proto(),
11429 token: token_to_cancel.map(|token| token.to_proto()),
11430 },
11431 ),
11432 ),
11433 });
11434 cx.background_spawn(request).detach_and_log_err(cx);
11435 }
11436 }
11437
11438 fn register_supplementary_language_server(
11439 &mut self,
11440 id: LanguageServerId,
11441 name: LanguageServerName,
11442 server: Arc<LanguageServer>,
11443 cx: &mut Context<Self>,
11444 ) {
11445 if let Some(local) = self.as_local_mut() {
11446 local
11447 .supplementary_language_servers
11448 .insert(id, (name.clone(), server));
11449 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11450 }
11451 }
11452
11453 fn unregister_supplementary_language_server(
11454 &mut self,
11455 id: LanguageServerId,
11456 cx: &mut Context<Self>,
11457 ) {
11458 if let Some(local) = self.as_local_mut() {
11459 local.supplementary_language_servers.remove(&id);
11460 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11461 }
11462 }
11463
11464 pub(crate) fn supplementary_language_servers(
11465 &self,
11466 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11467 self.as_local().into_iter().flat_map(|local| {
11468 local
11469 .supplementary_language_servers
11470 .iter()
11471 .map(|(id, (name, _))| (*id, name.clone()))
11472 })
11473 }
11474
11475 pub fn language_server_adapter_for_id(
11476 &self,
11477 id: LanguageServerId,
11478 ) -> Option<Arc<CachedLspAdapter>> {
11479 self.as_local()
11480 .and_then(|local| local.language_servers.get(&id))
11481 .and_then(|language_server_state| match language_server_state {
11482 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11483 _ => None,
11484 })
11485 }
11486
11487 pub(super) fn update_local_worktree_language_servers(
11488 &mut self,
11489 worktree_handle: &Entity<Worktree>,
11490 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11491 cx: &mut Context<Self>,
11492 ) {
11493 if changes.is_empty() {
11494 return;
11495 }
11496
11497 let Some(local) = self.as_local() else { return };
11498
11499 local.prettier_store.update(cx, |prettier_store, cx| {
11500 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11501 });
11502
11503 let worktree_id = worktree_handle.read(cx).id();
11504 let mut language_server_ids = local
11505 .language_server_ids
11506 .iter()
11507 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11508 .collect::<Vec<_>>();
11509 language_server_ids.sort();
11510 language_server_ids.dedup();
11511
11512 // let abs_path = worktree_handle.read(cx).abs_path();
11513 for server_id in &language_server_ids {
11514 if let Some(LanguageServerState::Running { server, .. }) =
11515 local.language_servers.get(server_id)
11516 && let Some(watched_paths) = local
11517 .language_server_watched_paths
11518 .get(server_id)
11519 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11520 {
11521 let params = lsp::DidChangeWatchedFilesParams {
11522 changes: changes
11523 .iter()
11524 .filter_map(|(path, _, change)| {
11525 if !watched_paths.is_match(path.as_std_path()) {
11526 return None;
11527 }
11528 let typ = match change {
11529 PathChange::Loaded => return None,
11530 PathChange::Added => lsp::FileChangeType::CREATED,
11531 PathChange::Removed => lsp::FileChangeType::DELETED,
11532 PathChange::Updated => lsp::FileChangeType::CHANGED,
11533 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11534 };
11535 let uri = lsp::Uri::from_file_path(
11536 worktree_handle.read(cx).absolutize(&path),
11537 )
11538 .ok()?;
11539 Some(lsp::FileEvent { uri, typ })
11540 })
11541 .collect(),
11542 };
11543 if !params.changes.is_empty() {
11544 server
11545 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11546 .ok();
11547 }
11548 }
11549 }
11550 for (path, _, _) in changes {
11551 if let Some(file_name) = path.file_name()
11552 && local.watched_manifest_filenames.contains(file_name)
11553 {
11554 self.request_workspace_config_refresh();
11555 break;
11556 }
11557 }
11558 }
11559
11560 pub fn wait_for_remote_buffer(
11561 &mut self,
11562 id: BufferId,
11563 cx: &mut Context<Self>,
11564 ) -> Task<Result<Entity<Buffer>>> {
11565 self.buffer_store.update(cx, |buffer_store, cx| {
11566 buffer_store.wait_for_remote_buffer(id, cx)
11567 })
11568 }
11569
11570 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11571 let mut result = proto::Symbol {
11572 language_server_name: symbol.language_server_name.0.to_string(),
11573 source_worktree_id: symbol.source_worktree_id.to_proto(),
11574 language_server_id: symbol.source_language_server_id.to_proto(),
11575 name: symbol.name.clone(),
11576 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11577 start: Some(proto::PointUtf16 {
11578 row: symbol.range.start.0.row,
11579 column: symbol.range.start.0.column,
11580 }),
11581 end: Some(proto::PointUtf16 {
11582 row: symbol.range.end.0.row,
11583 column: symbol.range.end.0.column,
11584 }),
11585 worktree_id: Default::default(),
11586 path: Default::default(),
11587 signature: Default::default(),
11588 };
11589 match &symbol.path {
11590 SymbolLocation::InProject(path) => {
11591 result.worktree_id = path.worktree_id.to_proto();
11592 result.path = path.path.to_proto();
11593 }
11594 SymbolLocation::OutsideProject {
11595 abs_path,
11596 signature,
11597 } => {
11598 result.path = abs_path.to_string_lossy().into_owned();
11599 result.signature = signature.to_vec();
11600 }
11601 }
11602 result
11603 }
11604
11605 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11606 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11607 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11608 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11609
11610 let path = if serialized_symbol.signature.is_empty() {
11611 SymbolLocation::InProject(ProjectPath {
11612 worktree_id,
11613 path: RelPath::from_proto(&serialized_symbol.path)
11614 .context("invalid symbol path")?,
11615 })
11616 } else {
11617 SymbolLocation::OutsideProject {
11618 abs_path: Path::new(&serialized_symbol.path).into(),
11619 signature: serialized_symbol
11620 .signature
11621 .try_into()
11622 .map_err(|_| anyhow!("invalid signature"))?,
11623 }
11624 };
11625
11626 let start = serialized_symbol.start.context("invalid start")?;
11627 let end = serialized_symbol.end.context("invalid end")?;
11628 Ok(CoreSymbol {
11629 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11630 source_worktree_id,
11631 source_language_server_id: LanguageServerId::from_proto(
11632 serialized_symbol.language_server_id,
11633 ),
11634 path,
11635 name: serialized_symbol.name,
11636 range: Unclipped(PointUtf16::new(start.row, start.column))
11637 ..Unclipped(PointUtf16::new(end.row, end.column)),
11638 kind,
11639 })
11640 }
11641
11642 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11643 let mut serialized_completion = proto::Completion {
11644 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11645 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11646 new_text: completion.new_text.clone(),
11647 ..proto::Completion::default()
11648 };
11649 match &completion.source {
11650 CompletionSource::Lsp {
11651 insert_range,
11652 server_id,
11653 lsp_completion,
11654 lsp_defaults,
11655 resolved,
11656 } => {
11657 let (old_insert_start, old_insert_end) = insert_range
11658 .as_ref()
11659 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11660 .unzip();
11661
11662 serialized_completion.old_insert_start = old_insert_start;
11663 serialized_completion.old_insert_end = old_insert_end;
11664 serialized_completion.source = proto::completion::Source::Lsp as i32;
11665 serialized_completion.server_id = server_id.0 as u64;
11666 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11667 serialized_completion.lsp_defaults = lsp_defaults
11668 .as_deref()
11669 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11670 serialized_completion.resolved = *resolved;
11671 }
11672 CompletionSource::BufferWord {
11673 word_range,
11674 resolved,
11675 } => {
11676 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11677 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11678 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11679 serialized_completion.resolved = *resolved;
11680 }
11681 CompletionSource::Custom => {
11682 serialized_completion.source = proto::completion::Source::Custom as i32;
11683 serialized_completion.resolved = true;
11684 }
11685 CompletionSource::Dap { sort_text } => {
11686 serialized_completion.source = proto::completion::Source::Dap as i32;
11687 serialized_completion.sort_text = Some(sort_text.clone());
11688 }
11689 }
11690
11691 serialized_completion
11692 }
11693
11694 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11695 let old_replace_start = completion
11696 .old_replace_start
11697 .and_then(deserialize_anchor)
11698 .context("invalid old start")?;
11699 let old_replace_end = completion
11700 .old_replace_end
11701 .and_then(deserialize_anchor)
11702 .context("invalid old end")?;
11703 let insert_range = {
11704 match completion.old_insert_start.zip(completion.old_insert_end) {
11705 Some((start, end)) => {
11706 let start = deserialize_anchor(start).context("invalid insert old start")?;
11707 let end = deserialize_anchor(end).context("invalid insert old end")?;
11708 Some(start..end)
11709 }
11710 None => None,
11711 }
11712 };
11713 Ok(CoreCompletion {
11714 replace_range: old_replace_start..old_replace_end,
11715 new_text: completion.new_text,
11716 source: match proto::completion::Source::from_i32(completion.source) {
11717 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11718 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11719 insert_range,
11720 server_id: LanguageServerId::from_proto(completion.server_id),
11721 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11722 lsp_defaults: completion
11723 .lsp_defaults
11724 .as_deref()
11725 .map(serde_json::from_slice)
11726 .transpose()?,
11727 resolved: completion.resolved,
11728 },
11729 Some(proto::completion::Source::BufferWord) => {
11730 let word_range = completion
11731 .buffer_word_start
11732 .and_then(deserialize_anchor)
11733 .context("invalid buffer word start")?
11734 ..completion
11735 .buffer_word_end
11736 .and_then(deserialize_anchor)
11737 .context("invalid buffer word end")?;
11738 CompletionSource::BufferWord {
11739 word_range,
11740 resolved: completion.resolved,
11741 }
11742 }
11743 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11744 sort_text: completion
11745 .sort_text
11746 .context("expected sort text to exist")?,
11747 },
11748 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11749 },
11750 })
11751 }
11752
11753 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11754 let (kind, lsp_action) = match &action.lsp_action {
11755 LspAction::Action(code_action) => (
11756 proto::code_action::Kind::Action as i32,
11757 serde_json::to_vec(code_action).unwrap(),
11758 ),
11759 LspAction::Command(command) => (
11760 proto::code_action::Kind::Command as i32,
11761 serde_json::to_vec(command).unwrap(),
11762 ),
11763 LspAction::CodeLens(code_lens) => (
11764 proto::code_action::Kind::CodeLens as i32,
11765 serde_json::to_vec(code_lens).unwrap(),
11766 ),
11767 };
11768
11769 proto::CodeAction {
11770 server_id: action.server_id.0 as u64,
11771 start: Some(serialize_anchor(&action.range.start)),
11772 end: Some(serialize_anchor(&action.range.end)),
11773 lsp_action,
11774 kind,
11775 resolved: action.resolved,
11776 }
11777 }
11778
11779 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11780 let start = action
11781 .start
11782 .and_then(deserialize_anchor)
11783 .context("invalid start")?;
11784 let end = action
11785 .end
11786 .and_then(deserialize_anchor)
11787 .context("invalid end")?;
11788 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11789 Some(proto::code_action::Kind::Action) => {
11790 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11791 }
11792 Some(proto::code_action::Kind::Command) => {
11793 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11794 }
11795 Some(proto::code_action::Kind::CodeLens) => {
11796 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11797 }
11798 None => anyhow::bail!("Unknown action kind {}", action.kind),
11799 };
11800 Ok(CodeAction {
11801 server_id: LanguageServerId(action.server_id as usize),
11802 range: start..end,
11803 resolved: action.resolved,
11804 lsp_action,
11805 })
11806 }
11807
11808 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11809 match &formatting_result {
11810 Ok(_) => self.last_formatting_failure = None,
11811 Err(error) => {
11812 let error_string = format!("{error:#}");
11813 log::error!("Formatting failed: {error_string}");
11814 self.last_formatting_failure
11815 .replace(error_string.lines().join(" "));
11816 }
11817 }
11818 }
11819
11820 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11821 self.lsp_server_capabilities.remove(&for_server);
11822 for lsp_data in self.lsp_data.values_mut() {
11823 lsp_data.remove_server_data(for_server);
11824 }
11825 if let Some(local) = self.as_local_mut() {
11826 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11827 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11828 buffer_servers.remove(&for_server);
11829 }
11830 }
11831 }
11832
11833 pub fn result_id(
11834 &self,
11835 server_id: LanguageServerId,
11836 buffer_id: BufferId,
11837 cx: &App,
11838 ) -> Option<String> {
11839 let abs_path = self
11840 .buffer_store
11841 .read(cx)
11842 .get(buffer_id)
11843 .and_then(|b| File::from_dyn(b.read(cx).file()))
11844 .map(|f| f.abs_path(cx))?;
11845 self.as_local()?
11846 .buffer_pull_diagnostics_result_ids
11847 .get(&server_id)?
11848 .get(&abs_path)?
11849 .clone()
11850 }
11851
11852 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11853 let Some(local) = self.as_local() else {
11854 return HashMap::default();
11855 };
11856 local
11857 .buffer_pull_diagnostics_result_ids
11858 .get(&server_id)
11859 .into_iter()
11860 .flatten()
11861 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11862 .collect()
11863 }
11864
11865 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11866 if let Some(LanguageServerState::Running {
11867 workspace_diagnostics_refresh_tasks,
11868 ..
11869 }) = self
11870 .as_local_mut()
11871 .and_then(|local| local.language_servers.get_mut(&server_id))
11872 {
11873 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11874 diagnostics.refresh_tx.try_send(()).ok();
11875 }
11876 }
11877 }
11878
11879 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11880 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11881 return;
11882 };
11883 let Some(local) = self.as_local_mut() else {
11884 return;
11885 };
11886
11887 for server_id in buffer.update(cx, |buffer, cx| {
11888 local.language_server_ids_for_buffer(buffer, cx)
11889 }) {
11890 if let Some(LanguageServerState::Running {
11891 workspace_diagnostics_refresh_tasks,
11892 ..
11893 }) = local.language_servers.get_mut(&server_id)
11894 {
11895 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11896 diagnostics.refresh_tx.try_send(()).ok();
11897 }
11898 }
11899 }
11900 }
11901
11902 fn apply_workspace_diagnostic_report(
11903 &mut self,
11904 server_id: LanguageServerId,
11905 report: lsp::WorkspaceDiagnosticReportResult,
11906 cx: &mut Context<Self>,
11907 ) {
11908 let workspace_diagnostics =
11909 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11910 let mut unchanged_buffers = HashSet::default();
11911 let mut changed_buffers = HashSet::default();
11912 let workspace_diagnostics_updates = workspace_diagnostics
11913 .into_iter()
11914 .filter_map(
11915 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11916 LspPullDiagnostics::Response {
11917 server_id,
11918 uri,
11919 diagnostics,
11920 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11921 LspPullDiagnostics::Default => None,
11922 },
11923 )
11924 .fold(
11925 HashMap::default(),
11926 |mut acc, (server_id, uri, diagnostics, version)| {
11927 let (result_id, diagnostics) = match diagnostics {
11928 PulledDiagnostics::Unchanged { result_id } => {
11929 unchanged_buffers.insert(uri.clone());
11930 (Some(result_id), Vec::new())
11931 }
11932 PulledDiagnostics::Changed {
11933 result_id,
11934 diagnostics,
11935 } => {
11936 changed_buffers.insert(uri.clone());
11937 (result_id, diagnostics)
11938 }
11939 };
11940 let disk_based_sources = Cow::Owned(
11941 self.language_server_adapter_for_id(server_id)
11942 .as_ref()
11943 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11944 .unwrap_or(&[])
11945 .to_vec(),
11946 );
11947 acc.entry(server_id)
11948 .or_insert_with(Vec::new)
11949 .push(DocumentDiagnosticsUpdate {
11950 server_id,
11951 diagnostics: lsp::PublishDiagnosticsParams {
11952 uri,
11953 diagnostics,
11954 version,
11955 },
11956 result_id,
11957 disk_based_sources,
11958 });
11959 acc
11960 },
11961 );
11962
11963 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11964 self.merge_lsp_diagnostics(
11965 DiagnosticSourceKind::Pulled,
11966 diagnostic_updates,
11967 |buffer, old_diagnostic, cx| {
11968 File::from_dyn(buffer.file())
11969 .and_then(|file| {
11970 let abs_path = file.as_local()?.abs_path(cx);
11971 lsp::Uri::from_file_path(abs_path).ok()
11972 })
11973 .is_none_or(|buffer_uri| {
11974 unchanged_buffers.contains(&buffer_uri)
11975 || match old_diagnostic.source_kind {
11976 DiagnosticSourceKind::Pulled => {
11977 !changed_buffers.contains(&buffer_uri)
11978 }
11979 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11980 true
11981 }
11982 }
11983 })
11984 },
11985 cx,
11986 )
11987 .log_err();
11988 }
11989 }
11990
11991 fn register_server_capabilities(
11992 &mut self,
11993 server_id: LanguageServerId,
11994 params: lsp::RegistrationParams,
11995 cx: &mut Context<Self>,
11996 ) -> anyhow::Result<()> {
11997 let server = self
11998 .language_server_for_id(server_id)
11999 .with_context(|| format!("no server {server_id} found"))?;
12000 for reg in params.registrations {
12001 match reg.method.as_str() {
12002 "workspace/didChangeWatchedFiles" => {
12003 if let Some(options) = reg.register_options {
12004 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12005 let caps = serde_json::from_value(options)?;
12006 local_lsp_store
12007 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12008 true
12009 } else {
12010 false
12011 };
12012 if notify {
12013 notify_server_capabilities_updated(&server, cx);
12014 }
12015 }
12016 }
12017 "workspace/didChangeConfiguration" => {
12018 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12019 }
12020 "workspace/didChangeWorkspaceFolders" => {
12021 // In this case register options is an empty object, we can ignore it
12022 let caps = lsp::WorkspaceFoldersServerCapabilities {
12023 supported: Some(true),
12024 change_notifications: Some(OneOf::Right(reg.id)),
12025 };
12026 server.update_capabilities(|capabilities| {
12027 capabilities
12028 .workspace
12029 .get_or_insert_default()
12030 .workspace_folders = Some(caps);
12031 });
12032 notify_server_capabilities_updated(&server, cx);
12033 }
12034 "workspace/symbol" => {
12035 let options = parse_register_capabilities(reg)?;
12036 server.update_capabilities(|capabilities| {
12037 capabilities.workspace_symbol_provider = Some(options);
12038 });
12039 notify_server_capabilities_updated(&server, cx);
12040 }
12041 "workspace/fileOperations" => {
12042 if let Some(options) = reg.register_options {
12043 let caps = serde_json::from_value(options)?;
12044 server.update_capabilities(|capabilities| {
12045 capabilities
12046 .workspace
12047 .get_or_insert_default()
12048 .file_operations = Some(caps);
12049 });
12050 notify_server_capabilities_updated(&server, cx);
12051 }
12052 }
12053 "workspace/executeCommand" => {
12054 if let Some(options) = reg.register_options {
12055 let options = serde_json::from_value(options)?;
12056 server.update_capabilities(|capabilities| {
12057 capabilities.execute_command_provider = Some(options);
12058 });
12059 notify_server_capabilities_updated(&server, cx);
12060 }
12061 }
12062 "textDocument/rangeFormatting" => {
12063 let options = parse_register_capabilities(reg)?;
12064 server.update_capabilities(|capabilities| {
12065 capabilities.document_range_formatting_provider = Some(options);
12066 });
12067 notify_server_capabilities_updated(&server, cx);
12068 }
12069 "textDocument/onTypeFormatting" => {
12070 if let Some(options) = reg
12071 .register_options
12072 .map(serde_json::from_value)
12073 .transpose()?
12074 {
12075 server.update_capabilities(|capabilities| {
12076 capabilities.document_on_type_formatting_provider = Some(options);
12077 });
12078 notify_server_capabilities_updated(&server, cx);
12079 }
12080 }
12081 "textDocument/formatting" => {
12082 let options = parse_register_capabilities(reg)?;
12083 server.update_capabilities(|capabilities| {
12084 capabilities.document_formatting_provider = Some(options);
12085 });
12086 notify_server_capabilities_updated(&server, cx);
12087 }
12088 "textDocument/rename" => {
12089 let options = parse_register_capabilities(reg)?;
12090 server.update_capabilities(|capabilities| {
12091 capabilities.rename_provider = Some(options);
12092 });
12093 notify_server_capabilities_updated(&server, cx);
12094 }
12095 "textDocument/inlayHint" => {
12096 let options = parse_register_capabilities(reg)?;
12097 server.update_capabilities(|capabilities| {
12098 capabilities.inlay_hint_provider = Some(options);
12099 });
12100 notify_server_capabilities_updated(&server, cx);
12101 }
12102 "textDocument/documentSymbol" => {
12103 let options = parse_register_capabilities(reg)?;
12104 server.update_capabilities(|capabilities| {
12105 capabilities.document_symbol_provider = Some(options);
12106 });
12107 notify_server_capabilities_updated(&server, cx);
12108 }
12109 "textDocument/codeAction" => {
12110 let options = parse_register_capabilities(reg)?;
12111 let provider = match options {
12112 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12113 OneOf::Right(caps) => caps,
12114 };
12115 server.update_capabilities(|capabilities| {
12116 capabilities.code_action_provider = Some(provider);
12117 });
12118 notify_server_capabilities_updated(&server, cx);
12119 }
12120 "textDocument/definition" => {
12121 let options = parse_register_capabilities(reg)?;
12122 server.update_capabilities(|capabilities| {
12123 capabilities.definition_provider = Some(options);
12124 });
12125 notify_server_capabilities_updated(&server, cx);
12126 }
12127 "textDocument/completion" => {
12128 if let Some(caps) = reg
12129 .register_options
12130 .map(serde_json::from_value::<CompletionOptions>)
12131 .transpose()?
12132 {
12133 server.update_capabilities(|capabilities| {
12134 capabilities.completion_provider = Some(caps.clone());
12135 });
12136
12137 if let Some(local) = self.as_local() {
12138 let mut buffers_with_language_server = Vec::new();
12139 for handle in self.buffer_store.read(cx).buffers() {
12140 let buffer_id = handle.read(cx).remote_id();
12141 if local
12142 .buffers_opened_in_servers
12143 .get(&buffer_id)
12144 .filter(|s| s.contains(&server_id))
12145 .is_some()
12146 {
12147 buffers_with_language_server.push(handle);
12148 }
12149 }
12150 let triggers = caps
12151 .trigger_characters
12152 .unwrap_or_default()
12153 .into_iter()
12154 .collect::<BTreeSet<_>>();
12155 for handle in buffers_with_language_server {
12156 let triggers = triggers.clone();
12157 let _ = handle.update(cx, move |buffer, cx| {
12158 buffer.set_completion_triggers(server_id, triggers, cx);
12159 });
12160 }
12161 }
12162 notify_server_capabilities_updated(&server, cx);
12163 }
12164 }
12165 "textDocument/hover" => {
12166 let options = parse_register_capabilities(reg)?;
12167 let provider = match options {
12168 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12169 OneOf::Right(caps) => caps,
12170 };
12171 server.update_capabilities(|capabilities| {
12172 capabilities.hover_provider = Some(provider);
12173 });
12174 notify_server_capabilities_updated(&server, cx);
12175 }
12176 "textDocument/signatureHelp" => {
12177 if let Some(caps) = reg
12178 .register_options
12179 .map(serde_json::from_value)
12180 .transpose()?
12181 {
12182 server.update_capabilities(|capabilities| {
12183 capabilities.signature_help_provider = Some(caps);
12184 });
12185 notify_server_capabilities_updated(&server, cx);
12186 }
12187 }
12188 "textDocument/didChange" => {
12189 if let Some(sync_kind) = reg
12190 .register_options
12191 .and_then(|opts| opts.get("syncKind").cloned())
12192 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12193 .transpose()?
12194 {
12195 server.update_capabilities(|capabilities| {
12196 let mut sync_options =
12197 Self::take_text_document_sync_options(capabilities);
12198 sync_options.change = Some(sync_kind);
12199 capabilities.text_document_sync =
12200 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12201 });
12202 notify_server_capabilities_updated(&server, cx);
12203 }
12204 }
12205 "textDocument/didSave" => {
12206 if let Some(include_text) = reg
12207 .register_options
12208 .map(|opts| {
12209 let transpose = opts
12210 .get("includeText")
12211 .cloned()
12212 .map(serde_json::from_value::<Option<bool>>)
12213 .transpose();
12214 match transpose {
12215 Ok(value) => Ok(value.flatten()),
12216 Err(e) => Err(e),
12217 }
12218 })
12219 .transpose()?
12220 {
12221 server.update_capabilities(|capabilities| {
12222 let mut sync_options =
12223 Self::take_text_document_sync_options(capabilities);
12224 sync_options.save =
12225 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12226 include_text,
12227 }));
12228 capabilities.text_document_sync =
12229 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12230 });
12231 notify_server_capabilities_updated(&server, cx);
12232 }
12233 }
12234 "textDocument/codeLens" => {
12235 if let Some(caps) = reg
12236 .register_options
12237 .map(serde_json::from_value)
12238 .transpose()?
12239 {
12240 server.update_capabilities(|capabilities| {
12241 capabilities.code_lens_provider = Some(caps);
12242 });
12243 notify_server_capabilities_updated(&server, cx);
12244 }
12245 }
12246 "textDocument/diagnostic" => {
12247 if let Some(caps) = reg
12248 .register_options
12249 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12250 .transpose()?
12251 {
12252 let local = self
12253 .as_local_mut()
12254 .context("Expected LSP Store to be local")?;
12255 let state = local
12256 .language_servers
12257 .get_mut(&server_id)
12258 .context("Could not obtain Language Servers state")?;
12259 local
12260 .language_server_dynamic_registrations
12261 .entry(server_id)
12262 .or_default()
12263 .diagnostics
12264 .insert(Some(reg.id.clone()), caps.clone());
12265
12266 if let LanguageServerState::Running {
12267 workspace_diagnostics_refresh_tasks,
12268 ..
12269 } = state
12270 && let Some(task) = lsp_workspace_diagnostics_refresh(
12271 Some(reg.id.clone()),
12272 caps.clone(),
12273 server.clone(),
12274 cx,
12275 )
12276 {
12277 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12278 }
12279
12280 let mut did_update_caps = false;
12281 server.update_capabilities(|capabilities| {
12282 if capabilities.diagnostic_provider.as_ref().is_none_or(
12283 |current_caps| {
12284 let supports_workspace_diagnostics =
12285 |capabilities: &DiagnosticServerCapabilities| {
12286 match capabilities {
12287 DiagnosticServerCapabilities::Options(
12288 diagnostic_options,
12289 ) => diagnostic_options.workspace_diagnostics,
12290 DiagnosticServerCapabilities::RegistrationOptions(
12291 diagnostic_registration_options,
12292 ) => {
12293 diagnostic_registration_options
12294 .diagnostic_options
12295 .workspace_diagnostics
12296 }
12297 }
12298 };
12299 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12300 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12301 // as it'll think that they're not supported.
12302 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12303 !supports_workspace_diagnostics(current_caps)
12304 & supports_workspace_diagnostics(&caps)
12305 },
12306 ) {
12307 did_update_caps = true;
12308 capabilities.diagnostic_provider = Some(caps);
12309 }
12310 });
12311 if did_update_caps {
12312 notify_server_capabilities_updated(&server, cx);
12313 }
12314 }
12315 }
12316 "textDocument/documentColor" => {
12317 let options = parse_register_capabilities(reg)?;
12318 let provider = match options {
12319 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12320 OneOf::Right(caps) => caps,
12321 };
12322 server.update_capabilities(|capabilities| {
12323 capabilities.color_provider = Some(provider);
12324 });
12325 notify_server_capabilities_updated(&server, cx);
12326 }
12327 _ => log::warn!("unhandled capability registration: {reg:?}"),
12328 }
12329 }
12330
12331 Ok(())
12332 }
12333
12334 fn unregister_server_capabilities(
12335 &mut self,
12336 server_id: LanguageServerId,
12337 params: lsp::UnregistrationParams,
12338 cx: &mut Context<Self>,
12339 ) -> anyhow::Result<()> {
12340 let server = self
12341 .language_server_for_id(server_id)
12342 .with_context(|| format!("no server {server_id} found"))?;
12343 for unreg in params.unregisterations.iter() {
12344 match unreg.method.as_str() {
12345 "workspace/didChangeWatchedFiles" => {
12346 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12347 local_lsp_store
12348 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12349 true
12350 } else {
12351 false
12352 };
12353 if notify {
12354 notify_server_capabilities_updated(&server, cx);
12355 }
12356 }
12357 "workspace/didChangeConfiguration" => {
12358 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12359 }
12360 "workspace/didChangeWorkspaceFolders" => {
12361 server.update_capabilities(|capabilities| {
12362 capabilities
12363 .workspace
12364 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12365 workspace_folders: None,
12366 file_operations: None,
12367 })
12368 .workspace_folders = None;
12369 });
12370 notify_server_capabilities_updated(&server, cx);
12371 }
12372 "workspace/symbol" => {
12373 server.update_capabilities(|capabilities| {
12374 capabilities.workspace_symbol_provider = None
12375 });
12376 notify_server_capabilities_updated(&server, cx);
12377 }
12378 "workspace/fileOperations" => {
12379 server.update_capabilities(|capabilities| {
12380 capabilities
12381 .workspace
12382 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12383 workspace_folders: None,
12384 file_operations: None,
12385 })
12386 .file_operations = None;
12387 });
12388 notify_server_capabilities_updated(&server, cx);
12389 }
12390 "workspace/executeCommand" => {
12391 server.update_capabilities(|capabilities| {
12392 capabilities.execute_command_provider = None;
12393 });
12394 notify_server_capabilities_updated(&server, cx);
12395 }
12396 "textDocument/rangeFormatting" => {
12397 server.update_capabilities(|capabilities| {
12398 capabilities.document_range_formatting_provider = None
12399 });
12400 notify_server_capabilities_updated(&server, cx);
12401 }
12402 "textDocument/onTypeFormatting" => {
12403 server.update_capabilities(|capabilities| {
12404 capabilities.document_on_type_formatting_provider = None;
12405 });
12406 notify_server_capabilities_updated(&server, cx);
12407 }
12408 "textDocument/formatting" => {
12409 server.update_capabilities(|capabilities| {
12410 capabilities.document_formatting_provider = None;
12411 });
12412 notify_server_capabilities_updated(&server, cx);
12413 }
12414 "textDocument/rename" => {
12415 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12416 notify_server_capabilities_updated(&server, cx);
12417 }
12418 "textDocument/codeAction" => {
12419 server.update_capabilities(|capabilities| {
12420 capabilities.code_action_provider = None;
12421 });
12422 notify_server_capabilities_updated(&server, cx);
12423 }
12424 "textDocument/definition" => {
12425 server.update_capabilities(|capabilities| {
12426 capabilities.definition_provider = None;
12427 });
12428 notify_server_capabilities_updated(&server, cx);
12429 }
12430 "textDocument/completion" => {
12431 server.update_capabilities(|capabilities| {
12432 capabilities.completion_provider = None;
12433 });
12434 notify_server_capabilities_updated(&server, cx);
12435 }
12436 "textDocument/hover" => {
12437 server.update_capabilities(|capabilities| {
12438 capabilities.hover_provider = None;
12439 });
12440 notify_server_capabilities_updated(&server, cx);
12441 }
12442 "textDocument/signatureHelp" => {
12443 server.update_capabilities(|capabilities| {
12444 capabilities.signature_help_provider = None;
12445 });
12446 notify_server_capabilities_updated(&server, cx);
12447 }
12448 "textDocument/didChange" => {
12449 server.update_capabilities(|capabilities| {
12450 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12451 sync_options.change = None;
12452 capabilities.text_document_sync =
12453 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12454 });
12455 notify_server_capabilities_updated(&server, cx);
12456 }
12457 "textDocument/didSave" => {
12458 server.update_capabilities(|capabilities| {
12459 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12460 sync_options.save = None;
12461 capabilities.text_document_sync =
12462 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12463 });
12464 notify_server_capabilities_updated(&server, cx);
12465 }
12466 "textDocument/codeLens" => {
12467 server.update_capabilities(|capabilities| {
12468 capabilities.code_lens_provider = None;
12469 });
12470 notify_server_capabilities_updated(&server, cx);
12471 }
12472 "textDocument/diagnostic" => {
12473 let local = self
12474 .as_local_mut()
12475 .context("Expected LSP Store to be local")?;
12476
12477 let state = local
12478 .language_servers
12479 .get_mut(&server_id)
12480 .context("Could not obtain Language Servers state")?;
12481 let options = local
12482 .language_server_dynamic_registrations
12483 .get_mut(&server_id)
12484 .with_context(|| {
12485 format!("Expected dynamic registration to exist for server {server_id}")
12486 })?.diagnostics
12487 .remove(&Some(unreg.id.clone()))
12488 .with_context(|| format!(
12489 "Attempted to unregister non-existent diagnostic registration with ID {}",
12490 unreg.id)
12491 )?;
12492
12493 let mut has_any_diagnostic_providers_still = true;
12494 if let Some(identifier) = diagnostic_identifier(&options)
12495 && let LanguageServerState::Running {
12496 workspace_diagnostics_refresh_tasks,
12497 ..
12498 } = state
12499 {
12500 workspace_diagnostics_refresh_tasks.remove(&identifier);
12501 has_any_diagnostic_providers_still =
12502 !workspace_diagnostics_refresh_tasks.is_empty();
12503 }
12504
12505 if !has_any_diagnostic_providers_still {
12506 server.update_capabilities(|capabilities| {
12507 debug_assert!(capabilities.diagnostic_provider.is_some());
12508 capabilities.diagnostic_provider = None;
12509 });
12510 }
12511
12512 notify_server_capabilities_updated(&server, cx);
12513 }
12514 "textDocument/documentColor" => {
12515 server.update_capabilities(|capabilities| {
12516 capabilities.color_provider = None;
12517 });
12518 notify_server_capabilities_updated(&server, cx);
12519 }
12520 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12521 }
12522 }
12523
12524 Ok(())
12525 }
12526
12527 async fn deduplicate_range_based_lsp_requests<T>(
12528 lsp_store: &Entity<Self>,
12529 server_id: Option<LanguageServerId>,
12530 lsp_request_id: LspRequestId,
12531 proto_request: &T::ProtoRequest,
12532 range: Range<Anchor>,
12533 cx: &mut AsyncApp,
12534 ) -> Result<()>
12535 where
12536 T: LspCommand,
12537 T::ProtoRequest: proto::LspRequestMessage,
12538 {
12539 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12540 let version = deserialize_version(proto_request.buffer_version());
12541 let buffer = lsp_store.update(cx, |this, cx| {
12542 this.buffer_store.read(cx).get_existing(buffer_id)
12543 })??;
12544 buffer
12545 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12546 .await?;
12547 lsp_store.update(cx, |lsp_store, cx| {
12548 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12549 let chunks_queried_for = lsp_data
12550 .inlay_hints
12551 .applicable_chunks(&[range])
12552 .collect::<Vec<_>>();
12553 match chunks_queried_for.as_slice() {
12554 &[chunk] => {
12555 let key = LspKey {
12556 request_type: TypeId::of::<T>(),
12557 server_queried: server_id,
12558 };
12559 let previous_request = lsp_data
12560 .chunk_lsp_requests
12561 .entry(key)
12562 .or_default()
12563 .insert(chunk, lsp_request_id);
12564 if let Some((previous_request, running_requests)) =
12565 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12566 {
12567 running_requests.remove(&previous_request);
12568 }
12569 }
12570 _ambiguous_chunks => {
12571 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12572 // there, a buffer version-based check will be performed and outdated requests discarded.
12573 }
12574 }
12575 anyhow::Ok(())
12576 })??;
12577
12578 Ok(())
12579 }
12580
12581 async fn query_lsp_locally<T>(
12582 lsp_store: Entity<Self>,
12583 for_server_id: Option<LanguageServerId>,
12584 sender_id: proto::PeerId,
12585 lsp_request_id: LspRequestId,
12586 proto_request: T::ProtoRequest,
12587 position: Option<Anchor>,
12588 cx: &mut AsyncApp,
12589 ) -> Result<()>
12590 where
12591 T: LspCommand + Clone,
12592 T::ProtoRequest: proto::LspRequestMessage,
12593 <T::ProtoRequest as proto::RequestMessage>::Response:
12594 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12595 {
12596 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12597 let version = deserialize_version(proto_request.buffer_version());
12598 let buffer = lsp_store.update(cx, |this, cx| {
12599 this.buffer_store.read(cx).get_existing(buffer_id)
12600 })??;
12601 buffer
12602 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12603 .await?;
12604 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12605 let request =
12606 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12607 let key = LspKey {
12608 request_type: TypeId::of::<T>(),
12609 server_queried: for_server_id,
12610 };
12611 lsp_store.update(cx, |lsp_store, cx| {
12612 let request_task = match for_server_id {
12613 Some(server_id) => {
12614 let server_task = lsp_store.request_lsp(
12615 buffer.clone(),
12616 LanguageServerToQuery::Other(server_id),
12617 request.clone(),
12618 cx,
12619 );
12620 cx.background_spawn(async move {
12621 let mut responses = Vec::new();
12622 match server_task.await {
12623 Ok(response) => responses.push((server_id, response)),
12624 // rust-analyzer likes to error with this when its still loading up
12625 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12626 Err(e) => log::error!(
12627 "Error handling response for request {request:?}: {e:#}"
12628 ),
12629 }
12630 responses
12631 })
12632 }
12633 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12634 };
12635 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12636 if T::ProtoRequest::stop_previous_requests() {
12637 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12638 lsp_requests.clear();
12639 }
12640 }
12641 lsp_data.lsp_requests.entry(key).or_default().insert(
12642 lsp_request_id,
12643 cx.spawn(async move |lsp_store, cx| {
12644 let response = request_task.await;
12645 lsp_store
12646 .update(cx, |lsp_store, cx| {
12647 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12648 {
12649 let response = response
12650 .into_iter()
12651 .map(|(server_id, response)| {
12652 (
12653 server_id.to_proto(),
12654 T::response_to_proto(
12655 response,
12656 lsp_store,
12657 sender_id,
12658 &buffer_version,
12659 cx,
12660 )
12661 .into(),
12662 )
12663 })
12664 .collect::<HashMap<_, _>>();
12665 match client.send_lsp_response::<T::ProtoRequest>(
12666 project_id,
12667 lsp_request_id,
12668 response,
12669 ) {
12670 Ok(()) => {}
12671 Err(e) => {
12672 log::error!("Failed to send LSP response: {e:#}",)
12673 }
12674 }
12675 }
12676 })
12677 .ok();
12678 }),
12679 );
12680 })?;
12681 Ok(())
12682 }
12683
12684 fn take_text_document_sync_options(
12685 capabilities: &mut lsp::ServerCapabilities,
12686 ) -> lsp::TextDocumentSyncOptions {
12687 match capabilities.text_document_sync.take() {
12688 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12689 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12690 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12691 sync_options.change = Some(sync_kind);
12692 sync_options
12693 }
12694 None => lsp::TextDocumentSyncOptions::default(),
12695 }
12696 }
12697
12698 #[cfg(any(test, feature = "test-support"))]
12699 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12700 Some(
12701 self.lsp_data
12702 .get_mut(&buffer_id)?
12703 .code_lens
12704 .take()?
12705 .update
12706 .take()?
12707 .1,
12708 )
12709 }
12710
12711 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12712 self.downstream_client.clone()
12713 }
12714
12715 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12716 self.worktree_store.clone()
12717 }
12718
12719 /// Gets what's stored in the LSP data for the given buffer.
12720 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12721 self.lsp_data.get_mut(&buffer_id)
12722 }
12723
12724 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12725 /// new [`BufferLspData`] will be created to replace the previous state.
12726 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12727 let (buffer_id, buffer_version) =
12728 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12729 let lsp_data = self
12730 .lsp_data
12731 .entry(buffer_id)
12732 .or_insert_with(|| BufferLspData::new(buffer, cx));
12733 if buffer_version.changed_since(&lsp_data.buffer_version) {
12734 *lsp_data = BufferLspData::new(buffer, cx);
12735 }
12736 lsp_data
12737 }
12738}
12739
12740// Registration with registerOptions as null, should fallback to true.
12741// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12742fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12743 reg: lsp::Registration,
12744) -> Result<OneOf<bool, T>> {
12745 Ok(match reg.register_options {
12746 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12747 None => OneOf::Left(true),
12748 })
12749}
12750
12751fn subscribe_to_binary_statuses(
12752 languages: &Arc<LanguageRegistry>,
12753 cx: &mut Context<'_, LspStore>,
12754) -> Task<()> {
12755 let mut server_statuses = languages.language_server_binary_statuses();
12756 cx.spawn(async move |lsp_store, cx| {
12757 while let Some((server_name, binary_status)) = server_statuses.next().await {
12758 if lsp_store
12759 .update(cx, |_, cx| {
12760 let mut message = None;
12761 let binary_status = match binary_status {
12762 BinaryStatus::None => proto::ServerBinaryStatus::None,
12763 BinaryStatus::CheckingForUpdate => {
12764 proto::ServerBinaryStatus::CheckingForUpdate
12765 }
12766 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12767 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12768 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12769 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12770 BinaryStatus::Failed { error } => {
12771 message = Some(error);
12772 proto::ServerBinaryStatus::Failed
12773 }
12774 };
12775 cx.emit(LspStoreEvent::LanguageServerUpdate {
12776 // Binary updates are about the binary that might not have any language server id at that point.
12777 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12778 language_server_id: LanguageServerId(0),
12779 name: Some(server_name),
12780 message: proto::update_language_server::Variant::StatusUpdate(
12781 proto::StatusUpdate {
12782 message,
12783 status: Some(proto::status_update::Status::Binary(
12784 binary_status as i32,
12785 )),
12786 },
12787 ),
12788 });
12789 })
12790 .is_err()
12791 {
12792 break;
12793 }
12794 }
12795 })
12796}
12797
12798fn lsp_workspace_diagnostics_refresh(
12799 registration_id: Option<String>,
12800 options: DiagnosticServerCapabilities,
12801 server: Arc<LanguageServer>,
12802 cx: &mut Context<'_, LspStore>,
12803) -> Option<WorkspaceRefreshTask> {
12804 let identifier = diagnostic_identifier(&options)?;
12805
12806 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12807 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12808 refresh_tx.try_send(()).ok();
12809
12810 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12811 let mut attempts = 0;
12812 let max_attempts = 50;
12813 let mut requests = 0;
12814
12815 loop {
12816 let Some(()) = refresh_rx.recv().await else {
12817 return;
12818 };
12819
12820 'request: loop {
12821 requests += 1;
12822 if attempts > max_attempts {
12823 log::error!(
12824 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12825 );
12826 return;
12827 }
12828 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12829 cx.background_executor()
12830 .timer(Duration::from_millis(backoff_millis))
12831 .await;
12832 attempts += 1;
12833
12834 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12835 lsp_store
12836 .all_result_ids(server.server_id())
12837 .into_iter()
12838 .filter_map(|(abs_path, result_id)| {
12839 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12840 Some(lsp::PreviousResultId {
12841 uri,
12842 value: result_id,
12843 })
12844 })
12845 .collect()
12846 }) else {
12847 return;
12848 };
12849
12850 let token = if let Some(identifier) = ®istration_id {
12851 format!(
12852 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12853 server.server_id(),
12854 )
12855 } else {
12856 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12857 };
12858
12859 progress_rx.try_recv().ok();
12860 let timer =
12861 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12862 let progress = pin!(progress_rx.recv().fuse());
12863 let response_result = server
12864 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12865 lsp::WorkspaceDiagnosticParams {
12866 previous_result_ids,
12867 identifier: identifier.clone(),
12868 work_done_progress_params: Default::default(),
12869 partial_result_params: lsp::PartialResultParams {
12870 partial_result_token: Some(lsp::ProgressToken::String(token)),
12871 },
12872 },
12873 select(timer, progress).then(|either| match either {
12874 Either::Left((message, ..)) => ready(message).left_future(),
12875 Either::Right(..) => pending::<String>().right_future(),
12876 }),
12877 )
12878 .await;
12879
12880 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12881 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12882 match response_result {
12883 ConnectionResult::Timeout => {
12884 log::error!("Timeout during workspace diagnostics pull");
12885 continue 'request;
12886 }
12887 ConnectionResult::ConnectionReset => {
12888 log::error!("Server closed a workspace diagnostics pull request");
12889 continue 'request;
12890 }
12891 ConnectionResult::Result(Err(e)) => {
12892 log::error!("Error during workspace diagnostics pull: {e:#}");
12893 break 'request;
12894 }
12895 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12896 attempts = 0;
12897 if lsp_store
12898 .update(cx, |lsp_store, cx| {
12899 lsp_store.apply_workspace_diagnostic_report(
12900 server.server_id(),
12901 pulled_diagnostics,
12902 cx,
12903 )
12904 })
12905 .is_err()
12906 {
12907 return;
12908 }
12909 break 'request;
12910 }
12911 }
12912 }
12913 }
12914 });
12915
12916 Some(WorkspaceRefreshTask {
12917 refresh_tx,
12918 progress_tx,
12919 task: workspace_query_language_server,
12920 })
12921}
12922
12923fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12924 match &options {
12925 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12926 if !diagnostic_options.workspace_diagnostics {
12927 return None;
12928 }
12929 Some(diagnostic_options.identifier.clone())
12930 }
12931 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12932 let diagnostic_options = ®istration_options.diagnostic_options;
12933 if !diagnostic_options.workspace_diagnostics {
12934 return None;
12935 }
12936 Some(diagnostic_options.identifier.clone())
12937 }
12938 }
12939}
12940
12941fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12942 let CompletionSource::BufferWord {
12943 word_range,
12944 resolved,
12945 } = &mut completion.source
12946 else {
12947 return;
12948 };
12949 if *resolved {
12950 return;
12951 }
12952
12953 if completion.new_text
12954 != snapshot
12955 .text_for_range(word_range.clone())
12956 .collect::<String>()
12957 {
12958 return;
12959 }
12960
12961 let mut offset = 0;
12962 for chunk in snapshot.chunks(word_range.clone(), true) {
12963 let end_offset = offset + chunk.text.len();
12964 if let Some(highlight_id) = chunk.syntax_highlight_id {
12965 completion
12966 .label
12967 .runs
12968 .push((offset..end_offset, highlight_id));
12969 }
12970 offset = end_offset;
12971 }
12972 *resolved = true;
12973}
12974
12975impl EventEmitter<LspStoreEvent> for LspStore {}
12976
12977fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12978 hover
12979 .contents
12980 .retain(|hover_block| !hover_block.text.trim().is_empty());
12981 if hover.contents.is_empty() {
12982 None
12983 } else {
12984 Some(hover)
12985 }
12986}
12987
12988async fn populate_labels_for_completions(
12989 new_completions: Vec<CoreCompletion>,
12990 language: Option<Arc<Language>>,
12991 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12992) -> Vec<Completion> {
12993 let lsp_completions = new_completions
12994 .iter()
12995 .filter_map(|new_completion| {
12996 new_completion
12997 .source
12998 .lsp_completion(true)
12999 .map(|lsp_completion| lsp_completion.into_owned())
13000 })
13001 .collect::<Vec<_>>();
13002
13003 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13004 lsp_adapter
13005 .labels_for_completions(&lsp_completions, language)
13006 .await
13007 .log_err()
13008 .unwrap_or_default()
13009 } else {
13010 Vec::new()
13011 }
13012 .into_iter()
13013 .fuse();
13014
13015 let mut completions = Vec::new();
13016 for completion in new_completions {
13017 match completion.source.lsp_completion(true) {
13018 Some(lsp_completion) => {
13019 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13020
13021 let mut label = labels.next().flatten().unwrap_or_else(|| {
13022 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13023 });
13024 ensure_uniform_list_compatible_label(&mut label);
13025 completions.push(Completion {
13026 label,
13027 documentation,
13028 replace_range: completion.replace_range,
13029 new_text: completion.new_text,
13030 insert_text_mode: lsp_completion.insert_text_mode,
13031 source: completion.source,
13032 icon_path: None,
13033 confirm: None,
13034 match_start: None,
13035 snippet_deduplication_key: None,
13036 });
13037 }
13038 None => {
13039 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13040 ensure_uniform_list_compatible_label(&mut label);
13041 completions.push(Completion {
13042 label,
13043 documentation: None,
13044 replace_range: completion.replace_range,
13045 new_text: completion.new_text,
13046 source: completion.source,
13047 insert_text_mode: None,
13048 icon_path: None,
13049 confirm: None,
13050 match_start: None,
13051 snippet_deduplication_key: None,
13052 });
13053 }
13054 }
13055 }
13056 completions
13057}
13058
13059#[derive(Debug)]
13060pub enum LanguageServerToQuery {
13061 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13062 FirstCapable,
13063 /// Query a specific language server.
13064 Other(LanguageServerId),
13065}
13066
13067#[derive(Default)]
13068struct RenamePathsWatchedForServer {
13069 did_rename: Vec<RenameActionPredicate>,
13070 will_rename: Vec<RenameActionPredicate>,
13071}
13072
13073impl RenamePathsWatchedForServer {
13074 fn with_did_rename_patterns(
13075 mut self,
13076 did_rename: Option<&FileOperationRegistrationOptions>,
13077 ) -> Self {
13078 if let Some(did_rename) = did_rename {
13079 self.did_rename = did_rename
13080 .filters
13081 .iter()
13082 .filter_map(|filter| filter.try_into().log_err())
13083 .collect();
13084 }
13085 self
13086 }
13087 fn with_will_rename_patterns(
13088 mut self,
13089 will_rename: Option<&FileOperationRegistrationOptions>,
13090 ) -> Self {
13091 if let Some(will_rename) = will_rename {
13092 self.will_rename = will_rename
13093 .filters
13094 .iter()
13095 .filter_map(|filter| filter.try_into().log_err())
13096 .collect();
13097 }
13098 self
13099 }
13100
13101 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13102 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13103 }
13104 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13105 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13106 }
13107}
13108
13109impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13110 type Error = globset::Error;
13111 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13112 Ok(Self {
13113 kind: ops.pattern.matches.clone(),
13114 glob: GlobBuilder::new(&ops.pattern.glob)
13115 .case_insensitive(
13116 ops.pattern
13117 .options
13118 .as_ref()
13119 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13120 )
13121 .build()?
13122 .compile_matcher(),
13123 })
13124 }
13125}
13126struct RenameActionPredicate {
13127 glob: GlobMatcher,
13128 kind: Option<FileOperationPatternKind>,
13129}
13130
13131impl RenameActionPredicate {
13132 // Returns true if language server should be notified
13133 fn eval(&self, path: &str, is_dir: bool) -> bool {
13134 self.kind.as_ref().is_none_or(|kind| {
13135 let expected_kind = if is_dir {
13136 FileOperationPatternKind::Folder
13137 } else {
13138 FileOperationPatternKind::File
13139 };
13140 kind == &expected_kind
13141 }) && self.glob.is_match(path)
13142 }
13143}
13144
13145#[derive(Default)]
13146struct LanguageServerWatchedPaths {
13147 worktree_paths: HashMap<WorktreeId, GlobSet>,
13148 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13149}
13150
13151#[derive(Default)]
13152struct LanguageServerWatchedPathsBuilder {
13153 worktree_paths: HashMap<WorktreeId, GlobSet>,
13154 abs_paths: HashMap<Arc<Path>, GlobSet>,
13155}
13156
13157impl LanguageServerWatchedPathsBuilder {
13158 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13159 self.worktree_paths.insert(worktree_id, glob_set);
13160 }
13161 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13162 self.abs_paths.insert(path, glob_set);
13163 }
13164 fn build(
13165 self,
13166 fs: Arc<dyn Fs>,
13167 language_server_id: LanguageServerId,
13168 cx: &mut Context<LspStore>,
13169 ) -> LanguageServerWatchedPaths {
13170 let lsp_store = cx.weak_entity();
13171
13172 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13173 let abs_paths = self
13174 .abs_paths
13175 .into_iter()
13176 .map(|(abs_path, globset)| {
13177 let task = cx.spawn({
13178 let abs_path = abs_path.clone();
13179 let fs = fs.clone();
13180
13181 let lsp_store = lsp_store.clone();
13182 async move |_, cx| {
13183 maybe!(async move {
13184 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13185 while let Some(update) = push_updates.0.next().await {
13186 let action = lsp_store
13187 .update(cx, |this, _| {
13188 let Some(local) = this.as_local() else {
13189 return ControlFlow::Break(());
13190 };
13191 let Some(watcher) = local
13192 .language_server_watched_paths
13193 .get(&language_server_id)
13194 else {
13195 return ControlFlow::Break(());
13196 };
13197 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13198 "Watched abs path is not registered with a watcher",
13199 );
13200 let matching_entries = update
13201 .into_iter()
13202 .filter(|event| globs.is_match(&event.path))
13203 .collect::<Vec<_>>();
13204 this.lsp_notify_abs_paths_changed(
13205 language_server_id,
13206 matching_entries,
13207 );
13208 ControlFlow::Continue(())
13209 })
13210 .ok()?;
13211
13212 if action.is_break() {
13213 break;
13214 }
13215 }
13216 Some(())
13217 })
13218 .await;
13219 }
13220 });
13221 (abs_path, (globset, task))
13222 })
13223 .collect();
13224 LanguageServerWatchedPaths {
13225 worktree_paths: self.worktree_paths,
13226 abs_paths,
13227 }
13228 }
13229}
13230
13231struct LspBufferSnapshot {
13232 version: i32,
13233 snapshot: TextBufferSnapshot,
13234}
13235
13236/// A prompt requested by LSP server.
13237#[derive(Clone, Debug)]
13238pub struct LanguageServerPromptRequest {
13239 pub level: PromptLevel,
13240 pub message: String,
13241 pub actions: Vec<MessageActionItem>,
13242 pub lsp_name: String,
13243 pub(crate) response_channel: Sender<MessageActionItem>,
13244}
13245
13246impl LanguageServerPromptRequest {
13247 pub async fn respond(self, index: usize) -> Option<()> {
13248 if let Some(response) = self.actions.into_iter().nth(index) {
13249 self.response_channel.send(response).await.ok()
13250 } else {
13251 None
13252 }
13253 }
13254}
13255impl PartialEq for LanguageServerPromptRequest {
13256 fn eq(&self, other: &Self) -> bool {
13257 self.message == other.message && self.actions == other.actions
13258 }
13259}
13260
13261#[derive(Clone, Debug, PartialEq)]
13262pub enum LanguageServerLogType {
13263 Log(MessageType),
13264 Trace { verbose_info: Option<String> },
13265 Rpc { received: bool },
13266}
13267
13268impl LanguageServerLogType {
13269 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13270 match self {
13271 Self::Log(log_type) => {
13272 use proto::log_message::LogLevel;
13273 let level = match *log_type {
13274 MessageType::ERROR => LogLevel::Error,
13275 MessageType::WARNING => LogLevel::Warning,
13276 MessageType::INFO => LogLevel::Info,
13277 MessageType::LOG => LogLevel::Log,
13278 other => {
13279 log::warn!("Unknown lsp log message type: {other:?}");
13280 LogLevel::Log
13281 }
13282 };
13283 proto::language_server_log::LogType::Log(proto::LogMessage {
13284 level: level as i32,
13285 })
13286 }
13287 Self::Trace { verbose_info } => {
13288 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13289 verbose_info: verbose_info.to_owned(),
13290 })
13291 }
13292 Self::Rpc { received } => {
13293 let kind = if *received {
13294 proto::rpc_message::Kind::Received
13295 } else {
13296 proto::rpc_message::Kind::Sent
13297 };
13298 let kind = kind as i32;
13299 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13300 }
13301 }
13302 }
13303
13304 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13305 use proto::log_message::LogLevel;
13306 use proto::rpc_message;
13307 match log_type {
13308 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13309 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13310 LogLevel::Error => MessageType::ERROR,
13311 LogLevel::Warning => MessageType::WARNING,
13312 LogLevel::Info => MessageType::INFO,
13313 LogLevel::Log => MessageType::LOG,
13314 },
13315 ),
13316 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13317 verbose_info: trace_message.verbose_info,
13318 },
13319 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13320 received: match rpc_message::Kind::from_i32(message.kind)
13321 .unwrap_or(rpc_message::Kind::Received)
13322 {
13323 rpc_message::Kind::Received => true,
13324 rpc_message::Kind::Sent => false,
13325 },
13326 },
13327 }
13328 }
13329}
13330
13331pub struct WorkspaceRefreshTask {
13332 refresh_tx: mpsc::Sender<()>,
13333 progress_tx: mpsc::Sender<()>,
13334 #[allow(dead_code)]
13335 task: Task<()>,
13336}
13337
13338pub enum LanguageServerState {
13339 Starting {
13340 startup: Task<Option<Arc<LanguageServer>>>,
13341 /// List of language servers that will be added to the workspace once it's initialization completes.
13342 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13343 },
13344
13345 Running {
13346 adapter: Arc<CachedLspAdapter>,
13347 server: Arc<LanguageServer>,
13348 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13349 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13350 },
13351}
13352
13353impl LanguageServerState {
13354 fn add_workspace_folder(&self, uri: Uri) {
13355 match self {
13356 LanguageServerState::Starting {
13357 pending_workspace_folders,
13358 ..
13359 } => {
13360 pending_workspace_folders.lock().insert(uri);
13361 }
13362 LanguageServerState::Running { server, .. } => {
13363 server.add_workspace_folder(uri);
13364 }
13365 }
13366 }
13367 fn _remove_workspace_folder(&self, uri: Uri) {
13368 match self {
13369 LanguageServerState::Starting {
13370 pending_workspace_folders,
13371 ..
13372 } => {
13373 pending_workspace_folders.lock().remove(&uri);
13374 }
13375 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13376 }
13377 }
13378}
13379
13380impl std::fmt::Debug for LanguageServerState {
13381 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13382 match self {
13383 LanguageServerState::Starting { .. } => {
13384 f.debug_struct("LanguageServerState::Starting").finish()
13385 }
13386 LanguageServerState::Running { .. } => {
13387 f.debug_struct("LanguageServerState::Running").finish()
13388 }
13389 }
13390 }
13391}
13392
13393#[derive(Clone, Debug, Serialize)]
13394pub struct LanguageServerProgress {
13395 pub is_disk_based_diagnostics_progress: bool,
13396 pub is_cancellable: bool,
13397 pub title: Option<String>,
13398 pub message: Option<String>,
13399 pub percentage: Option<usize>,
13400 #[serde(skip_serializing)]
13401 pub last_update_at: Instant,
13402}
13403
13404#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13405pub struct DiagnosticSummary {
13406 pub error_count: usize,
13407 pub warning_count: usize,
13408}
13409
13410impl DiagnosticSummary {
13411 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13412 let mut this = Self {
13413 error_count: 0,
13414 warning_count: 0,
13415 };
13416
13417 for entry in diagnostics {
13418 if entry.diagnostic.is_primary {
13419 match entry.diagnostic.severity {
13420 DiagnosticSeverity::ERROR => this.error_count += 1,
13421 DiagnosticSeverity::WARNING => this.warning_count += 1,
13422 _ => {}
13423 }
13424 }
13425 }
13426
13427 this
13428 }
13429
13430 pub fn is_empty(&self) -> bool {
13431 self.error_count == 0 && self.warning_count == 0
13432 }
13433
13434 pub fn to_proto(
13435 self,
13436 language_server_id: LanguageServerId,
13437 path: &RelPath,
13438 ) -> proto::DiagnosticSummary {
13439 proto::DiagnosticSummary {
13440 path: path.to_proto(),
13441 language_server_id: language_server_id.0 as u64,
13442 error_count: self.error_count as u32,
13443 warning_count: self.warning_count as u32,
13444 }
13445 }
13446}
13447
13448#[derive(Clone, Debug)]
13449pub enum CompletionDocumentation {
13450 /// There is no documentation for this completion.
13451 Undocumented,
13452 /// A single line of documentation.
13453 SingleLine(SharedString),
13454 /// Multiple lines of plain text documentation.
13455 MultiLinePlainText(SharedString),
13456 /// Markdown documentation.
13457 MultiLineMarkdown(SharedString),
13458 /// Both single line and multiple lines of plain text documentation.
13459 SingleLineAndMultiLinePlainText {
13460 single_line: SharedString,
13461 plain_text: Option<SharedString>,
13462 },
13463}
13464
13465impl CompletionDocumentation {
13466 #[cfg(any(test, feature = "test-support"))]
13467 pub fn text(&self) -> SharedString {
13468 match self {
13469 CompletionDocumentation::Undocumented => "".into(),
13470 CompletionDocumentation::SingleLine(s) => s.clone(),
13471 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13472 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13473 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13474 single_line.clone()
13475 }
13476 }
13477 }
13478}
13479
13480impl From<lsp::Documentation> for CompletionDocumentation {
13481 fn from(docs: lsp::Documentation) -> Self {
13482 match docs {
13483 lsp::Documentation::String(text) => {
13484 if text.lines().count() <= 1 {
13485 CompletionDocumentation::SingleLine(text.into())
13486 } else {
13487 CompletionDocumentation::MultiLinePlainText(text.into())
13488 }
13489 }
13490
13491 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13492 lsp::MarkupKind::PlainText => {
13493 if value.lines().count() <= 1 {
13494 CompletionDocumentation::SingleLine(value.into())
13495 } else {
13496 CompletionDocumentation::MultiLinePlainText(value.into())
13497 }
13498 }
13499
13500 lsp::MarkupKind::Markdown => {
13501 CompletionDocumentation::MultiLineMarkdown(value.into())
13502 }
13503 },
13504 }
13505 }
13506}
13507
13508pub enum ResolvedHint {
13509 Resolved(InlayHint),
13510 Resolving(Shared<Task<()>>),
13511}
13512
13513fn glob_literal_prefix(glob: &Path) -> PathBuf {
13514 glob.components()
13515 .take_while(|component| match component {
13516 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13517 _ => true,
13518 })
13519 .collect()
13520}
13521
13522pub struct SshLspAdapter {
13523 name: LanguageServerName,
13524 binary: LanguageServerBinary,
13525 initialization_options: Option<String>,
13526 code_action_kinds: Option<Vec<CodeActionKind>>,
13527}
13528
13529impl SshLspAdapter {
13530 pub fn new(
13531 name: LanguageServerName,
13532 binary: LanguageServerBinary,
13533 initialization_options: Option<String>,
13534 code_action_kinds: Option<String>,
13535 ) -> Self {
13536 Self {
13537 name,
13538 binary,
13539 initialization_options,
13540 code_action_kinds: code_action_kinds
13541 .as_ref()
13542 .and_then(|c| serde_json::from_str(c).ok()),
13543 }
13544 }
13545}
13546
13547impl LspInstaller for SshLspAdapter {
13548 type BinaryVersion = ();
13549 async fn check_if_user_installed(
13550 &self,
13551 _: &dyn LspAdapterDelegate,
13552 _: Option<Toolchain>,
13553 _: &AsyncApp,
13554 ) -> Option<LanguageServerBinary> {
13555 Some(self.binary.clone())
13556 }
13557
13558 async fn cached_server_binary(
13559 &self,
13560 _: PathBuf,
13561 _: &dyn LspAdapterDelegate,
13562 ) -> Option<LanguageServerBinary> {
13563 None
13564 }
13565
13566 async fn fetch_latest_server_version(
13567 &self,
13568 _: &dyn LspAdapterDelegate,
13569 _: bool,
13570 _: &mut AsyncApp,
13571 ) -> Result<()> {
13572 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13573 }
13574
13575 async fn fetch_server_binary(
13576 &self,
13577 _: (),
13578 _: PathBuf,
13579 _: &dyn LspAdapterDelegate,
13580 ) -> Result<LanguageServerBinary> {
13581 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13582 }
13583}
13584
13585#[async_trait(?Send)]
13586impl LspAdapter for SshLspAdapter {
13587 fn name(&self) -> LanguageServerName {
13588 self.name.clone()
13589 }
13590
13591 async fn initialization_options(
13592 self: Arc<Self>,
13593 _: &Arc<dyn LspAdapterDelegate>,
13594 ) -> Result<Option<serde_json::Value>> {
13595 let Some(options) = &self.initialization_options else {
13596 return Ok(None);
13597 };
13598 let result = serde_json::from_str(options)?;
13599 Ok(result)
13600 }
13601
13602 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13603 self.code_action_kinds.clone()
13604 }
13605}
13606
13607pub fn language_server_settings<'a>(
13608 delegate: &'a dyn LspAdapterDelegate,
13609 language: &LanguageServerName,
13610 cx: &'a App,
13611) -> Option<&'a LspSettings> {
13612 language_server_settings_for(
13613 SettingsLocation {
13614 worktree_id: delegate.worktree_id(),
13615 path: RelPath::empty(),
13616 },
13617 language,
13618 cx,
13619 )
13620}
13621
13622pub(crate) fn language_server_settings_for<'a>(
13623 location: SettingsLocation<'a>,
13624 language: &LanguageServerName,
13625 cx: &'a App,
13626) -> Option<&'a LspSettings> {
13627 ProjectSettings::get(Some(location), cx).lsp.get(language)
13628}
13629
13630pub struct LocalLspAdapterDelegate {
13631 lsp_store: WeakEntity<LspStore>,
13632 worktree: worktree::Snapshot,
13633 fs: Arc<dyn Fs>,
13634 http_client: Arc<dyn HttpClient>,
13635 language_registry: Arc<LanguageRegistry>,
13636 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13637}
13638
13639impl LocalLspAdapterDelegate {
13640 pub fn new(
13641 language_registry: Arc<LanguageRegistry>,
13642 environment: &Entity<ProjectEnvironment>,
13643 lsp_store: WeakEntity<LspStore>,
13644 worktree: &Entity<Worktree>,
13645 http_client: Arc<dyn HttpClient>,
13646 fs: Arc<dyn Fs>,
13647 cx: &mut App,
13648 ) -> Arc<Self> {
13649 let load_shell_env_task =
13650 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13651
13652 Arc::new(Self {
13653 lsp_store,
13654 worktree: worktree.read(cx).snapshot(),
13655 fs,
13656 http_client,
13657 language_registry,
13658 load_shell_env_task,
13659 })
13660 }
13661
13662 fn from_local_lsp(
13663 local: &LocalLspStore,
13664 worktree: &Entity<Worktree>,
13665 cx: &mut App,
13666 ) -> Arc<Self> {
13667 Self::new(
13668 local.languages.clone(),
13669 &local.environment,
13670 local.weak.clone(),
13671 worktree,
13672 local.http_client.clone(),
13673 local.fs.clone(),
13674 cx,
13675 )
13676 }
13677}
13678
13679#[async_trait]
13680impl LspAdapterDelegate for LocalLspAdapterDelegate {
13681 fn show_notification(&self, message: &str, cx: &mut App) {
13682 self.lsp_store
13683 .update(cx, |_, cx| {
13684 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13685 })
13686 .ok();
13687 }
13688
13689 fn http_client(&self) -> Arc<dyn HttpClient> {
13690 self.http_client.clone()
13691 }
13692
13693 fn worktree_id(&self) -> WorktreeId {
13694 self.worktree.id()
13695 }
13696
13697 fn worktree_root_path(&self) -> &Path {
13698 self.worktree.abs_path().as_ref()
13699 }
13700
13701 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13702 self.worktree.resolve_executable_path(path)
13703 }
13704
13705 async fn shell_env(&self) -> HashMap<String, String> {
13706 let task = self.load_shell_env_task.clone();
13707 task.await.unwrap_or_default()
13708 }
13709
13710 async fn npm_package_installed_version(
13711 &self,
13712 package_name: &str,
13713 ) -> Result<Option<(PathBuf, String)>> {
13714 let local_package_directory = self.worktree_root_path();
13715 let node_modules_directory = local_package_directory.join("node_modules");
13716
13717 if let Some(version) =
13718 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13719 {
13720 return Ok(Some((node_modules_directory, version)));
13721 }
13722 let Some(npm) = self.which("npm".as_ref()).await else {
13723 log::warn!(
13724 "Failed to find npm executable for {:?}",
13725 local_package_directory
13726 );
13727 return Ok(None);
13728 };
13729
13730 let env = self.shell_env().await;
13731 let output = util::command::new_smol_command(&npm)
13732 .args(["root", "-g"])
13733 .envs(env)
13734 .current_dir(local_package_directory)
13735 .output()
13736 .await?;
13737 let global_node_modules =
13738 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13739
13740 if let Some(version) =
13741 read_package_installed_version(global_node_modules.clone(), package_name).await?
13742 {
13743 return Ok(Some((global_node_modules, version)));
13744 }
13745 return Ok(None);
13746 }
13747
13748 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13749 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13750 if self.fs.is_file(&worktree_abs_path).await {
13751 worktree_abs_path.pop();
13752 }
13753
13754 let env = self.shell_env().await;
13755
13756 let shell_path = env.get("PATH").cloned();
13757
13758 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13759 }
13760
13761 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13762 let mut working_dir = self.worktree_root_path().to_path_buf();
13763 if self.fs.is_file(&working_dir).await {
13764 working_dir.pop();
13765 }
13766 let output = util::command::new_smol_command(&command.path)
13767 .args(command.arguments)
13768 .envs(command.env.clone().unwrap_or_default())
13769 .current_dir(working_dir)
13770 .output()
13771 .await?;
13772
13773 anyhow::ensure!(
13774 output.status.success(),
13775 "{}, stdout: {:?}, stderr: {:?}",
13776 output.status,
13777 String::from_utf8_lossy(&output.stdout),
13778 String::from_utf8_lossy(&output.stderr)
13779 );
13780 Ok(())
13781 }
13782
13783 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13784 self.language_registry
13785 .update_lsp_binary_status(server_name, status);
13786 }
13787
13788 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13789 self.language_registry
13790 .all_lsp_adapters()
13791 .into_iter()
13792 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13793 .collect()
13794 }
13795
13796 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13797 let dir = self.language_registry.language_server_download_dir(name)?;
13798
13799 if !dir.exists() {
13800 smol::fs::create_dir_all(&dir)
13801 .await
13802 .context("failed to create container directory")
13803 .log_err()?;
13804 }
13805
13806 Some(dir)
13807 }
13808
13809 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13810 let entry = self
13811 .worktree
13812 .entry_for_path(path)
13813 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13814 let abs_path = self.worktree.absolutize(&entry.path);
13815 self.fs.load(&abs_path).await
13816 }
13817}
13818
13819async fn populate_labels_for_symbols(
13820 symbols: Vec<CoreSymbol>,
13821 language_registry: &Arc<LanguageRegistry>,
13822 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13823 output: &mut Vec<Symbol>,
13824) {
13825 #[allow(clippy::mutable_key_type)]
13826 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13827
13828 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13829 for symbol in symbols {
13830 let Some(file_name) = symbol.path.file_name() else {
13831 continue;
13832 };
13833 let language = language_registry
13834 .load_language_for_file_path(Path::new(file_name))
13835 .await
13836 .ok()
13837 .or_else(|| {
13838 unknown_paths.insert(file_name.into());
13839 None
13840 });
13841 symbols_by_language
13842 .entry(language)
13843 .or_default()
13844 .push(symbol);
13845 }
13846
13847 for unknown_path in unknown_paths {
13848 log::info!("no language found for symbol in file {unknown_path:?}");
13849 }
13850
13851 let mut label_params = Vec::new();
13852 for (language, mut symbols) in symbols_by_language {
13853 label_params.clear();
13854 label_params.extend(
13855 symbols
13856 .iter_mut()
13857 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13858 );
13859
13860 let mut labels = Vec::new();
13861 if let Some(language) = language {
13862 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13863 language_registry
13864 .lsp_adapters(&language.name())
13865 .first()
13866 .cloned()
13867 });
13868 if let Some(lsp_adapter) = lsp_adapter {
13869 labels = lsp_adapter
13870 .labels_for_symbols(&label_params, &language)
13871 .await
13872 .log_err()
13873 .unwrap_or_default();
13874 }
13875 }
13876
13877 for ((symbol, (name, _)), label) in symbols
13878 .into_iter()
13879 .zip(label_params.drain(..))
13880 .zip(labels.into_iter().chain(iter::repeat(None)))
13881 {
13882 output.push(Symbol {
13883 language_server_name: symbol.language_server_name,
13884 source_worktree_id: symbol.source_worktree_id,
13885 source_language_server_id: symbol.source_language_server_id,
13886 path: symbol.path,
13887 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13888 name,
13889 kind: symbol.kind,
13890 range: symbol.range,
13891 });
13892 }
13893 }
13894}
13895
13896fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13897 match server.capabilities().text_document_sync.as_ref()? {
13898 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13899 // Server wants didSave but didn't specify includeText.
13900 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13901 // Server doesn't want didSave at all.
13902 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13903 // Server provided SaveOptions.
13904 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13905 Some(save_options.include_text.unwrap_or(false))
13906 }
13907 },
13908 // We do not have any save info. Kind affects didChange only.
13909 lsp::TextDocumentSyncCapability::Kind(_) => None,
13910 }
13911}
13912
13913/// Completion items are displayed in a `UniformList`.
13914/// Usually, those items are single-line strings, but in LSP responses,
13915/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13916/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13917/// 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,
13918/// breaking the completions menu presentation.
13919///
13920/// 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.
13921fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13922 let mut new_text = String::with_capacity(label.text.len());
13923 let mut offset_map = vec![0; label.text.len() + 1];
13924 let mut last_char_was_space = false;
13925 let mut new_idx = 0;
13926 let chars = label.text.char_indices().fuse();
13927 let mut newlines_removed = false;
13928
13929 for (idx, c) in chars {
13930 offset_map[idx] = new_idx;
13931
13932 match c {
13933 '\n' if last_char_was_space => {
13934 newlines_removed = true;
13935 }
13936 '\t' | ' ' if last_char_was_space => {}
13937 '\n' if !last_char_was_space => {
13938 new_text.push(' ');
13939 new_idx += 1;
13940 last_char_was_space = true;
13941 newlines_removed = true;
13942 }
13943 ' ' | '\t' => {
13944 new_text.push(' ');
13945 new_idx += 1;
13946 last_char_was_space = true;
13947 }
13948 _ => {
13949 new_text.push(c);
13950 new_idx += c.len_utf8();
13951 last_char_was_space = false;
13952 }
13953 }
13954 }
13955 offset_map[label.text.len()] = new_idx;
13956
13957 // Only modify the label if newlines were removed.
13958 if !newlines_removed {
13959 return;
13960 }
13961
13962 let last_index = new_idx;
13963 let mut run_ranges_errors = Vec::new();
13964 label.runs.retain_mut(|(range, _)| {
13965 match offset_map.get(range.start) {
13966 Some(&start) => range.start = start,
13967 None => {
13968 run_ranges_errors.push(range.clone());
13969 return false;
13970 }
13971 }
13972
13973 match offset_map.get(range.end) {
13974 Some(&end) => range.end = end,
13975 None => {
13976 run_ranges_errors.push(range.clone());
13977 range.end = last_index;
13978 }
13979 }
13980 true
13981 });
13982 if !run_ranges_errors.is_empty() {
13983 log::error!(
13984 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13985 label.text
13986 );
13987 }
13988
13989 let mut wrong_filter_range = None;
13990 if label.filter_range == (0..label.text.len()) {
13991 label.filter_range = 0..new_text.len();
13992 } else {
13993 let mut original_filter_range = Some(label.filter_range.clone());
13994 match offset_map.get(label.filter_range.start) {
13995 Some(&start) => label.filter_range.start = start,
13996 None => {
13997 wrong_filter_range = original_filter_range.take();
13998 label.filter_range.start = last_index;
13999 }
14000 }
14001
14002 match offset_map.get(label.filter_range.end) {
14003 Some(&end) => label.filter_range.end = end,
14004 None => {
14005 wrong_filter_range = original_filter_range.take();
14006 label.filter_range.end = last_index;
14007 }
14008 }
14009 }
14010 if let Some(wrong_filter_range) = wrong_filter_range {
14011 log::error!(
14012 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14013 label.text
14014 );
14015 }
14016
14017 label.text = new_text;
14018}
14019
14020#[cfg(test)]
14021mod tests {
14022 use language::HighlightId;
14023
14024 use super::*;
14025
14026 #[test]
14027 fn test_glob_literal_prefix() {
14028 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14029 assert_eq!(
14030 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14031 Path::new("node_modules")
14032 );
14033 assert_eq!(
14034 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14035 Path::new("foo")
14036 );
14037 assert_eq!(
14038 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14039 Path::new("foo/bar/baz.js")
14040 );
14041
14042 #[cfg(target_os = "windows")]
14043 {
14044 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14045 assert_eq!(
14046 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14047 Path::new("node_modules")
14048 );
14049 assert_eq!(
14050 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14051 Path::new("foo")
14052 );
14053 assert_eq!(
14054 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14055 Path::new("foo/bar/baz.js")
14056 );
14057 }
14058 }
14059
14060 #[test]
14061 fn test_multi_len_chars_normalization() {
14062 let mut label = CodeLabel::new(
14063 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14064 0..6,
14065 vec![(0..6, HighlightId(1))],
14066 );
14067 ensure_uniform_list_compatible_label(&mut label);
14068 assert_eq!(
14069 label,
14070 CodeLabel::new(
14071 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14072 0..6,
14073 vec![(0..6, HighlightId(1))],
14074 )
14075 );
14076 }
14077}