1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 worktree_store::{WorktreeStore, WorktreeStoreEvent},
42 yarn::YarnPathStore,
43};
44use anyhow::{Context as _, Result, anyhow};
45use async_trait::async_trait;
46use client::{TypedEnvelope, proto};
47use clock::Global;
48use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
49use futures::{
50 AsyncWriteExt, Future, FutureExt, StreamExt,
51 future::{Either, Shared, join_all, pending, select},
52 select, select_biased,
53 stream::FuturesUnordered,
54};
55use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
56use gpui::{
57 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
58 WeakEntity,
59};
60use http_client::HttpClient;
61use itertools::Itertools as _;
62use language::{
63 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
64 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
65 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
66 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
67 Transaction, Unclipped,
68 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
69 point_to_lsp,
70 proto::{
71 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
72 serialize_lsp_edit, serialize_version,
73 },
74 range_from_lsp, range_to_lsp,
75 row_chunk::RowChunk,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
79 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
80 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
81 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
82 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
83 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
84 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
85 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use serde_json::Value;
97use settings::{Settings, SettingsLocation, SettingsStore};
98use sha2::{Digest, Sha256};
99use smol::channel::Sender;
100use snippet::Snippet;
101use std::{
102 any::TypeId,
103 borrow::Cow,
104 cell::RefCell,
105 cmp::{Ordering, Reverse},
106 convert::TryInto,
107 ffi::OsStr,
108 future::ready,
109 iter, mem,
110 ops::{ControlFlow, Range},
111 path::{self, Path, PathBuf},
112 pin::pin,
113 rc::Rc,
114 sync::{
115 Arc,
116 atomic::{self, AtomicUsize},
117 },
118 time::{Duration, Instant},
119};
120use sum_tree::Dimensions;
121use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
122
123use util::{
124 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
125 paths::{PathStyle, SanitizedPath},
126 post_inc,
127 rel_path::RelPath,
128};
129
130pub use fs::*;
131pub use language::Location;
132pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
133#[cfg(any(test, feature = "test-support"))]
134pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
135pub use worktree::{
136 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
137 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
138};
139
140const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
141pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
142const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
143const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
144
145#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
146pub enum ProgressToken {
147 Number(i32),
148 String(SharedString),
149}
150
151impl std::fmt::Display for ProgressToken {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 Self::Number(number) => write!(f, "{number}"),
155 Self::String(string) => write!(f, "{string}"),
156 }
157 }
158}
159
160impl ProgressToken {
161 fn from_lsp(value: lsp::NumberOrString) -> Self {
162 match value {
163 lsp::NumberOrString::Number(number) => Self::Number(number),
164 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
165 }
166 }
167
168 fn to_lsp(&self) -> lsp::NumberOrString {
169 match self {
170 Self::Number(number) => lsp::NumberOrString::Number(*number),
171 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
172 }
173 }
174
175 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
176 Some(match value.value? {
177 proto::progress_token::Value::Number(number) => Self::Number(number),
178 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
179 })
180 }
181
182 fn to_proto(&self) -> proto::ProgressToken {
183 proto::ProgressToken {
184 value: Some(match self {
185 Self::Number(number) => proto::progress_token::Value::Number(*number),
186 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
187 }),
188 }
189 }
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum FormatTrigger {
194 Save,
195 Manual,
196}
197
198pub enum LspFormatTarget {
199 Buffers,
200 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
201}
202
203pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
204
205impl FormatTrigger {
206 fn from_proto(value: i32) -> FormatTrigger {
207 match value {
208 0 => FormatTrigger::Save,
209 1 => FormatTrigger::Manual,
210 _ => FormatTrigger::Save,
211 }
212 }
213}
214
215#[derive(Clone)]
216struct UnifiedLanguageServer {
217 id: LanguageServerId,
218 project_roots: HashSet<Arc<RelPath>>,
219}
220
221#[derive(Clone, Hash, PartialEq, Eq)]
222struct LanguageServerSeed {
223 worktree_id: WorktreeId,
224 name: LanguageServerName,
225 toolchain: Option<Toolchain>,
226 settings: Arc<LspSettings>,
227}
228
229#[derive(Debug)]
230pub struct DocumentDiagnosticsUpdate<'a, D> {
231 pub diagnostics: D,
232 pub result_id: Option<String>,
233 pub server_id: LanguageServerId,
234 pub disk_based_sources: Cow<'a, [String]>,
235}
236
237pub struct DocumentDiagnostics {
238 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
239 document_abs_path: PathBuf,
240 version: Option<i32>,
241}
242
243#[derive(Default, Debug)]
244struct DynamicRegistrations {
245 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
246 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
247}
248
249pub struct LocalLspStore {
250 weak: WeakEntity<LspStore>,
251 worktree_store: Entity<WorktreeStore>,
252 toolchain_store: Entity<LocalToolchainStore>,
253 http_client: Arc<dyn HttpClient>,
254 environment: Entity<ProjectEnvironment>,
255 fs: Arc<dyn Fs>,
256 languages: Arc<LanguageRegistry>,
257 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
258 yarn: Entity<YarnPathStore>,
259 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
260 buffers_being_formatted: HashSet<BufferId>,
261 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
262 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
263 watched_manifest_filenames: HashSet<ManifestName>,
264 language_server_paths_watched_for_rename:
265 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
266 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
267 supplementary_language_servers:
268 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
269 prettier_store: Entity<PrettierStore>,
270 next_diagnostic_group_id: usize,
271 diagnostics: HashMap<
272 WorktreeId,
273 HashMap<
274 Arc<RelPath>,
275 Vec<(
276 LanguageServerId,
277 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
278 )>,
279 >,
280 >,
281 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
282 _subscription: gpui::Subscription,
283 lsp_tree: LanguageServerTree,
284 registered_buffers: HashMap<BufferId, usize>,
285 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
286 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
287}
288
289impl LocalLspStore {
290 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
291 pub fn running_language_server_for_id(
292 &self,
293 id: LanguageServerId,
294 ) -> Option<&Arc<LanguageServer>> {
295 let language_server_state = self.language_servers.get(&id)?;
296
297 match language_server_state {
298 LanguageServerState::Running { server, .. } => Some(server),
299 LanguageServerState::Starting { .. } => None,
300 }
301 }
302
303 fn get_or_insert_language_server(
304 &mut self,
305 worktree_handle: &Entity<Worktree>,
306 delegate: Arc<LocalLspAdapterDelegate>,
307 disposition: &Arc<LaunchDisposition>,
308 language_name: &LanguageName,
309 cx: &mut App,
310 ) -> LanguageServerId {
311 let key = LanguageServerSeed {
312 worktree_id: worktree_handle.read(cx).id(),
313 name: disposition.server_name.clone(),
314 settings: disposition.settings.clone(),
315 toolchain: disposition.toolchain.clone(),
316 };
317 if let Some(state) = self.language_server_ids.get_mut(&key) {
318 state.project_roots.insert(disposition.path.path.clone());
319 state.id
320 } else {
321 let adapter = self
322 .languages
323 .lsp_adapters(language_name)
324 .into_iter()
325 .find(|adapter| adapter.name() == disposition.server_name)
326 .expect("To find LSP adapter");
327 let new_language_server_id = self.start_language_server(
328 worktree_handle,
329 delegate,
330 adapter,
331 disposition.settings.clone(),
332 key.clone(),
333 cx,
334 );
335 if let Some(state) = self.language_server_ids.get_mut(&key) {
336 state.project_roots.insert(disposition.path.path.clone());
337 } else {
338 debug_assert!(
339 false,
340 "Expected `start_language_server` to ensure that `key` exists in a map"
341 );
342 }
343 new_language_server_id
344 }
345 }
346
347 fn start_language_server(
348 &mut self,
349 worktree_handle: &Entity<Worktree>,
350 delegate: Arc<LocalLspAdapterDelegate>,
351 adapter: Arc<CachedLspAdapter>,
352 settings: Arc<LspSettings>,
353 key: LanguageServerSeed,
354 cx: &mut App,
355 ) -> LanguageServerId {
356 let worktree = worktree_handle.read(cx);
357
358 let root_path = worktree.abs_path();
359 let toolchain = key.toolchain.clone();
360 let override_options = settings.initialization_options.clone();
361
362 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
363
364 let server_id = self.languages.next_language_server_id();
365 log::trace!(
366 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
367 adapter.name.0
368 );
369
370 let binary = self.get_language_server_binary(
371 adapter.clone(),
372 settings,
373 toolchain.clone(),
374 delegate.clone(),
375 true,
376 cx,
377 );
378 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
379
380 let pending_server = cx.spawn({
381 let adapter = adapter.clone();
382 let server_name = adapter.name.clone();
383 let stderr_capture = stderr_capture.clone();
384 #[cfg(any(test, feature = "test-support"))]
385 let lsp_store = self.weak.clone();
386 let pending_workspace_folders = pending_workspace_folders.clone();
387 async move |cx| {
388 let binary = binary.await?;
389 #[cfg(any(test, feature = "test-support"))]
390 if let Some(server) = lsp_store
391 .update(&mut cx.clone(), |this, cx| {
392 this.languages.create_fake_language_server(
393 server_id,
394 &server_name,
395 binary.clone(),
396 &mut cx.to_async(),
397 )
398 })
399 .ok()
400 .flatten()
401 {
402 return Ok(server);
403 }
404
405 let code_action_kinds = adapter.code_action_kinds();
406 lsp::LanguageServer::new(
407 stderr_capture,
408 server_id,
409 server_name,
410 binary,
411 &root_path,
412 code_action_kinds,
413 Some(pending_workspace_folders),
414 cx,
415 )
416 }
417 });
418
419 let startup = {
420 let server_name = adapter.name.0.clone();
421 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
422 let key = key.clone();
423 let adapter = adapter.clone();
424 let lsp_store = self.weak.clone();
425 let pending_workspace_folders = pending_workspace_folders.clone();
426
427 let pull_diagnostics = ProjectSettings::get_global(cx)
428 .diagnostics
429 .lsp_pull_diagnostics
430 .enabled;
431 cx.spawn(async move |cx| {
432 let result = async {
433 let language_server = pending_server.await?;
434
435 let workspace_config = Self::workspace_configuration_for_adapter(
436 adapter.adapter.clone(),
437 &delegate,
438 toolchain,
439 cx,
440 )
441 .await?;
442
443 let mut initialization_options = Self::initialization_options_for_adapter(
444 adapter.adapter.clone(),
445 &delegate,
446 )
447 .await?;
448
449 match (&mut initialization_options, override_options) {
450 (Some(initialization_options), Some(override_options)) => {
451 merge_json_value_into(override_options, initialization_options);
452 }
453 (None, override_options) => initialization_options = override_options,
454 _ => {}
455 }
456
457 let initialization_params = cx.update(|cx| {
458 let mut params =
459 language_server.default_initialize_params(pull_diagnostics, cx);
460 params.initialization_options = initialization_options;
461 adapter.adapter.prepare_initialize_params(params, cx)
462 })??;
463
464 Self::setup_lsp_messages(
465 lsp_store.clone(),
466 &language_server,
467 delegate.clone(),
468 adapter.clone(),
469 );
470
471 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
472 settings: workspace_config,
473 };
474 let language_server = cx
475 .update(|cx| {
476 language_server.initialize(
477 initialization_params,
478 Arc::new(did_change_configuration_params.clone()),
479 cx,
480 )
481 })?
482 .await
483 .inspect_err(|_| {
484 if let Some(lsp_store) = lsp_store.upgrade() {
485 lsp_store
486 .update(cx, |lsp_store, cx| {
487 lsp_store.cleanup_lsp_data(server_id);
488 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
489 })
490 .ok();
491 }
492 })?;
493
494 language_server.notify::<lsp::notification::DidChangeConfiguration>(
495 did_change_configuration_params,
496 )?;
497
498 anyhow::Ok(language_server)
499 }
500 .await;
501
502 match result {
503 Ok(server) => {
504 lsp_store
505 .update(cx, |lsp_store, cx| {
506 lsp_store.insert_newly_running_language_server(
507 adapter,
508 server.clone(),
509 server_id,
510 key,
511 pending_workspace_folders,
512 cx,
513 );
514 })
515 .ok();
516 stderr_capture.lock().take();
517 Some(server)
518 }
519
520 Err(err) => {
521 let log = stderr_capture.lock().take().unwrap_or_default();
522 delegate.update_status(
523 adapter.name(),
524 BinaryStatus::Failed {
525 error: if log.is_empty() {
526 format!("{err:#}")
527 } else {
528 format!("{err:#}\n-- stderr --\n{log}")
529 },
530 },
531 );
532 log::error!("Failed to start language server {server_name:?}: {err:?}");
533 if !log.is_empty() {
534 log::error!("server stderr: {log}");
535 }
536 None
537 }
538 }
539 })
540 };
541 let state = LanguageServerState::Starting {
542 startup,
543 pending_workspace_folders,
544 };
545
546 self.languages
547 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
548
549 self.language_servers.insert(server_id, state);
550 self.language_server_ids
551 .entry(key)
552 .or_insert(UnifiedLanguageServer {
553 id: server_id,
554 project_roots: Default::default(),
555 });
556 server_id
557 }
558
559 fn get_language_server_binary(
560 &self,
561 adapter: Arc<CachedLspAdapter>,
562 settings: Arc<LspSettings>,
563 toolchain: Option<Toolchain>,
564 delegate: Arc<dyn LspAdapterDelegate>,
565 allow_binary_download: bool,
566 cx: &mut App,
567 ) -> Task<Result<LanguageServerBinary>> {
568 if let Some(settings) = &settings.binary
569 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
570 {
571 let settings = settings.clone();
572
573 return cx.background_spawn(async move {
574 let mut env = delegate.shell_env().await;
575 env.extend(settings.env.unwrap_or_default());
576
577 Ok(LanguageServerBinary {
578 path: delegate.resolve_executable_path(path),
579 env: Some(env),
580 arguments: settings
581 .arguments
582 .unwrap_or_default()
583 .iter()
584 .map(Into::into)
585 .collect(),
586 })
587 });
588 }
589 let lsp_binary_options = LanguageServerBinaryOptions {
590 allow_path_lookup: !settings
591 .binary
592 .as_ref()
593 .and_then(|b| b.ignore_system_version)
594 .unwrap_or_default(),
595 allow_binary_download,
596 pre_release: settings
597 .fetch
598 .as_ref()
599 .and_then(|f| f.pre_release)
600 .unwrap_or(false),
601 };
602
603 cx.spawn(async move |cx| {
604 let (existing_binary, maybe_download_binary) = adapter
605 .clone()
606 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
607 .await
608 .await;
609
610 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
611
612 let mut binary = match (existing_binary, maybe_download_binary) {
613 (binary, None) => binary?,
614 (Err(_), Some(downloader)) => downloader.await?,
615 (Ok(existing_binary), Some(downloader)) => {
616 let mut download_timeout = cx
617 .background_executor()
618 .timer(SERVER_DOWNLOAD_TIMEOUT)
619 .fuse();
620 let mut downloader = downloader.fuse();
621 futures::select! {
622 _ = download_timeout => {
623 // Return existing binary and kick the existing work to the background.
624 cx.spawn(async move |_| downloader.await).detach();
625 Ok(existing_binary)
626 },
627 downloaded_or_existing_binary = downloader => {
628 // If download fails, this results in the existing binary.
629 downloaded_or_existing_binary
630 }
631 }?
632 }
633 };
634 let mut shell_env = delegate.shell_env().await;
635
636 shell_env.extend(binary.env.unwrap_or_default());
637
638 if let Some(settings) = settings.binary.as_ref() {
639 if let Some(arguments) = &settings.arguments {
640 binary.arguments = arguments.iter().map(Into::into).collect();
641 }
642 if let Some(env) = &settings.env {
643 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
644 }
645 }
646
647 binary.env = Some(shell_env);
648 Ok(binary)
649 })
650 }
651
652 fn setup_lsp_messages(
653 lsp_store: WeakEntity<LspStore>,
654 language_server: &LanguageServer,
655 delegate: Arc<dyn LspAdapterDelegate>,
656 adapter: Arc<CachedLspAdapter>,
657 ) {
658 let name = language_server.name();
659 let server_id = language_server.server_id();
660 language_server
661 .on_notification::<lsp::notification::PublishDiagnostics, _>({
662 let adapter = adapter.clone();
663 let this = lsp_store.clone();
664 move |mut params, cx| {
665 let adapter = adapter.clone();
666 if let Some(this) = this.upgrade() {
667 this.update(cx, |this, cx| {
668 {
669 let buffer = params
670 .uri
671 .to_file_path()
672 .map(|file_path| this.get_buffer(&file_path, cx))
673 .ok()
674 .flatten();
675 adapter.process_diagnostics(&mut params, server_id, buffer);
676 }
677
678 this.merge_lsp_diagnostics(
679 DiagnosticSourceKind::Pushed,
680 vec![DocumentDiagnosticsUpdate {
681 server_id,
682 diagnostics: params,
683 result_id: None,
684 disk_based_sources: Cow::Borrowed(
685 &adapter.disk_based_diagnostic_sources,
686 ),
687 }],
688 |_, diagnostic, cx| match diagnostic.source_kind {
689 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
690 adapter.retain_old_diagnostic(diagnostic, cx)
691 }
692 DiagnosticSourceKind::Pulled => true,
693 },
694 cx,
695 )
696 .log_err();
697 })
698 .ok();
699 }
700 }
701 })
702 .detach();
703 language_server
704 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
705 let adapter = adapter.adapter.clone();
706 let delegate = delegate.clone();
707 let this = lsp_store.clone();
708 move |params, cx| {
709 let adapter = adapter.clone();
710 let delegate = delegate.clone();
711 let this = this.clone();
712 let mut cx = cx.clone();
713 async move {
714 let toolchain_for_id = this
715 .update(&mut cx, |this, _| {
716 this.as_local()?.language_server_ids.iter().find_map(
717 |(seed, value)| {
718 (value.id == server_id).then(|| seed.toolchain.clone())
719 },
720 )
721 })?
722 .context("Expected the LSP store to be in a local mode")?;
723 let workspace_config = Self::workspace_configuration_for_adapter(
724 adapter.clone(),
725 &delegate,
726 toolchain_for_id,
727 &mut cx,
728 )
729 .await?;
730
731 Ok(params
732 .items
733 .into_iter()
734 .map(|item| {
735 if let Some(section) = &item.section {
736 workspace_config
737 .get(section)
738 .cloned()
739 .unwrap_or(serde_json::Value::Null)
740 } else {
741 workspace_config.clone()
742 }
743 })
744 .collect())
745 }
746 }
747 })
748 .detach();
749
750 language_server
751 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
752 let this = lsp_store.clone();
753 move |_, cx| {
754 let this = this.clone();
755 let cx = cx.clone();
756 async move {
757 let Some(server) =
758 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
759 else {
760 return Ok(None);
761 };
762 let root = server.workspace_folders();
763 Ok(Some(
764 root.into_iter()
765 .map(|uri| WorkspaceFolder {
766 uri,
767 name: Default::default(),
768 })
769 .collect(),
770 ))
771 }
772 }
773 })
774 .detach();
775 // Even though we don't have handling for these requests, respond to them to
776 // avoid stalling any language server like `gopls` which waits for a response
777 // to these requests when initializing.
778 language_server
779 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
780 let this = lsp_store.clone();
781 move |params, cx| {
782 let this = this.clone();
783 let mut cx = cx.clone();
784 async move {
785 this.update(&mut cx, |this, _| {
786 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
787 {
788 status
789 .progress_tokens
790 .insert(ProgressToken::from_lsp(params.token));
791 }
792 })?;
793
794 Ok(())
795 }
796 }
797 })
798 .detach();
799
800 language_server
801 .on_request::<lsp::request::RegisterCapability, _, _>({
802 let lsp_store = lsp_store.clone();
803 move |params, cx| {
804 let lsp_store = lsp_store.clone();
805 let mut cx = cx.clone();
806 async move {
807 lsp_store
808 .update(&mut cx, |lsp_store, cx| {
809 if lsp_store.as_local().is_some() {
810 match lsp_store
811 .register_server_capabilities(server_id, params, cx)
812 {
813 Ok(()) => {}
814 Err(e) => {
815 log::error!(
816 "Failed to register server capabilities: {e:#}"
817 );
818 }
819 };
820 }
821 })
822 .ok();
823 Ok(())
824 }
825 }
826 })
827 .detach();
828
829 language_server
830 .on_request::<lsp::request::UnregisterCapability, _, _>({
831 let lsp_store = lsp_store.clone();
832 move |params, cx| {
833 let lsp_store = lsp_store.clone();
834 let mut cx = cx.clone();
835 async move {
836 lsp_store
837 .update(&mut cx, |lsp_store, cx| {
838 if lsp_store.as_local().is_some() {
839 match lsp_store
840 .unregister_server_capabilities(server_id, params, cx)
841 {
842 Ok(()) => {}
843 Err(e) => {
844 log::error!(
845 "Failed to unregister server capabilities: {e:#}"
846 );
847 }
848 }
849 }
850 })
851 .ok();
852 Ok(())
853 }
854 }
855 })
856 .detach();
857
858 language_server
859 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
860 let this = lsp_store.clone();
861 move |params, cx| {
862 let mut cx = cx.clone();
863 let this = this.clone();
864 async move {
865 LocalLspStore::on_lsp_workspace_edit(
866 this.clone(),
867 params,
868 server_id,
869 &mut cx,
870 )
871 .await
872 }
873 }
874 })
875 .detach();
876
877 language_server
878 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
879 let lsp_store = lsp_store.clone();
880 let request_id = Arc::new(AtomicUsize::new(0));
881 move |(), cx| {
882 let lsp_store = lsp_store.clone();
883 let request_id = request_id.clone();
884 let mut cx = cx.clone();
885 async move {
886 lsp_store
887 .update(&mut cx, |lsp_store, cx| {
888 let request_id =
889 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
890 cx.emit(LspStoreEvent::RefreshInlayHints {
891 server_id,
892 request_id,
893 });
894 lsp_store
895 .downstream_client
896 .as_ref()
897 .map(|(client, project_id)| {
898 client.send(proto::RefreshInlayHints {
899 project_id: *project_id,
900 server_id: server_id.to_proto(),
901 request_id: request_id.map(|id| id as u64),
902 })
903 })
904 })?
905 .transpose()?;
906 Ok(())
907 }
908 }
909 })
910 .detach();
911
912 language_server
913 .on_request::<lsp::request::CodeLensRefresh, _, _>({
914 let this = lsp_store.clone();
915 move |(), cx| {
916 let this = this.clone();
917 let mut cx = cx.clone();
918 async move {
919 this.update(&mut cx, |this, cx| {
920 cx.emit(LspStoreEvent::RefreshCodeLens);
921 this.downstream_client.as_ref().map(|(client, project_id)| {
922 client.send(proto::RefreshCodeLens {
923 project_id: *project_id,
924 })
925 })
926 })?
927 .transpose()?;
928 Ok(())
929 }
930 }
931 })
932 .detach();
933
934 language_server
935 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
936 let this = lsp_store.clone();
937 move |(), cx| {
938 let this = this.clone();
939 let mut cx = cx.clone();
940 async move {
941 this.update(&mut cx, |lsp_store, _| {
942 lsp_store.pull_workspace_diagnostics(server_id);
943 lsp_store
944 .downstream_client
945 .as_ref()
946 .map(|(client, project_id)| {
947 client.send(proto::PullWorkspaceDiagnostics {
948 project_id: *project_id,
949 server_id: server_id.to_proto(),
950 })
951 })
952 })?
953 .transpose()?;
954 Ok(())
955 }
956 }
957 })
958 .detach();
959
960 language_server
961 .on_request::<lsp::request::ShowMessageRequest, _, _>({
962 let this = lsp_store.clone();
963 let name = name.to_string();
964 move |params, cx| {
965 let this = this.clone();
966 let name = name.to_string();
967 let mut cx = cx.clone();
968 async move {
969 let actions = params.actions.unwrap_or_default();
970 let (tx, rx) = smol::channel::bounded(1);
971 let request = LanguageServerPromptRequest {
972 level: match params.typ {
973 lsp::MessageType::ERROR => PromptLevel::Critical,
974 lsp::MessageType::WARNING => PromptLevel::Warning,
975 _ => PromptLevel::Info,
976 },
977 message: params.message,
978 actions,
979 response_channel: tx,
980 lsp_name: name.clone(),
981 };
982
983 let did_update = this
984 .update(&mut cx, |_, cx| {
985 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
986 })
987 .is_ok();
988 if did_update {
989 let response = rx.recv().await.ok();
990 Ok(response)
991 } else {
992 Ok(None)
993 }
994 }
995 }
996 })
997 .detach();
998 language_server
999 .on_notification::<lsp::notification::ShowMessage, _>({
1000 let this = lsp_store.clone();
1001 let name = name.to_string();
1002 move |params, cx| {
1003 let this = this.clone();
1004 let name = name.to_string();
1005 let mut cx = cx.clone();
1006
1007 let (tx, _) = smol::channel::bounded(1);
1008 let request = LanguageServerPromptRequest {
1009 level: match params.typ {
1010 lsp::MessageType::ERROR => PromptLevel::Critical,
1011 lsp::MessageType::WARNING => PromptLevel::Warning,
1012 _ => PromptLevel::Info,
1013 },
1014 message: params.message,
1015 actions: vec![],
1016 response_channel: tx,
1017 lsp_name: name,
1018 };
1019
1020 let _ = this.update(&mut cx, |_, cx| {
1021 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1022 });
1023 }
1024 })
1025 .detach();
1026
1027 let disk_based_diagnostics_progress_token =
1028 adapter.disk_based_diagnostics_progress_token.clone();
1029
1030 language_server
1031 .on_notification::<lsp::notification::Progress, _>({
1032 let this = lsp_store.clone();
1033 move |params, cx| {
1034 if let Some(this) = this.upgrade() {
1035 this.update(cx, |this, cx| {
1036 this.on_lsp_progress(
1037 params,
1038 server_id,
1039 disk_based_diagnostics_progress_token.clone(),
1040 cx,
1041 );
1042 })
1043 .ok();
1044 }
1045 }
1046 })
1047 .detach();
1048
1049 language_server
1050 .on_notification::<lsp::notification::LogMessage, _>({
1051 let this = lsp_store.clone();
1052 move |params, cx| {
1053 if let Some(this) = this.upgrade() {
1054 this.update(cx, |_, cx| {
1055 cx.emit(LspStoreEvent::LanguageServerLog(
1056 server_id,
1057 LanguageServerLogType::Log(params.typ),
1058 params.message,
1059 ));
1060 })
1061 .ok();
1062 }
1063 }
1064 })
1065 .detach();
1066
1067 language_server
1068 .on_notification::<lsp::notification::LogTrace, _>({
1069 let this = lsp_store.clone();
1070 move |params, cx| {
1071 let mut cx = cx.clone();
1072 if let Some(this) = this.upgrade() {
1073 this.update(&mut cx, |_, cx| {
1074 cx.emit(LspStoreEvent::LanguageServerLog(
1075 server_id,
1076 LanguageServerLogType::Trace {
1077 verbose_info: params.verbose,
1078 },
1079 params.message,
1080 ));
1081 })
1082 .ok();
1083 }
1084 }
1085 })
1086 .detach();
1087
1088 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1089 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1090 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1091 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1092 }
1093
1094 fn shutdown_language_servers_on_quit(
1095 &mut self,
1096 _: &mut Context<LspStore>,
1097 ) -> impl Future<Output = ()> + use<> {
1098 let shutdown_futures = self
1099 .language_servers
1100 .drain()
1101 .map(|(_, server_state)| Self::shutdown_server(server_state))
1102 .collect::<Vec<_>>();
1103
1104 async move {
1105 join_all(shutdown_futures).await;
1106 }
1107 }
1108
1109 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1110 match server_state {
1111 LanguageServerState::Running { server, .. } => {
1112 if let Some(shutdown) = server.shutdown() {
1113 shutdown.await;
1114 }
1115 }
1116 LanguageServerState::Starting { startup, .. } => {
1117 if let Some(server) = startup.await
1118 && let Some(shutdown) = server.shutdown()
1119 {
1120 shutdown.await;
1121 }
1122 }
1123 }
1124 Ok(())
1125 }
1126
1127 fn language_servers_for_worktree(
1128 &self,
1129 worktree_id: WorktreeId,
1130 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1131 self.language_server_ids
1132 .iter()
1133 .filter_map(move |(seed, state)| {
1134 if seed.worktree_id != worktree_id {
1135 return None;
1136 }
1137
1138 if let Some(LanguageServerState::Running { server, .. }) =
1139 self.language_servers.get(&state.id)
1140 {
1141 Some(server)
1142 } else {
1143 None
1144 }
1145 })
1146 }
1147
1148 fn language_server_ids_for_project_path(
1149 &self,
1150 project_path: ProjectPath,
1151 language: &Language,
1152 cx: &mut App,
1153 ) -> Vec<LanguageServerId> {
1154 let Some(worktree) = self
1155 .worktree_store
1156 .read(cx)
1157 .worktree_for_id(project_path.worktree_id, cx)
1158 else {
1159 return Vec::new();
1160 };
1161 let delegate: Arc<dyn ManifestDelegate> =
1162 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1163
1164 self.lsp_tree
1165 .get(
1166 project_path,
1167 language.name(),
1168 language.manifest(),
1169 &delegate,
1170 cx,
1171 )
1172 .collect::<Vec<_>>()
1173 }
1174
1175 fn language_server_ids_for_buffer(
1176 &self,
1177 buffer: &Buffer,
1178 cx: &mut App,
1179 ) -> Vec<LanguageServerId> {
1180 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1181 let worktree_id = file.worktree_id(cx);
1182
1183 let path: Arc<RelPath> = file
1184 .path()
1185 .parent()
1186 .map(Arc::from)
1187 .unwrap_or_else(|| file.path().clone());
1188 let worktree_path = ProjectPath { worktree_id, path };
1189 self.language_server_ids_for_project_path(worktree_path, language, cx)
1190 } else {
1191 Vec::new()
1192 }
1193 }
1194
1195 fn language_servers_for_buffer<'a>(
1196 &'a self,
1197 buffer: &'a Buffer,
1198 cx: &'a mut App,
1199 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1200 self.language_server_ids_for_buffer(buffer, cx)
1201 .into_iter()
1202 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1203 LanguageServerState::Running {
1204 adapter, server, ..
1205 } => Some((adapter, server)),
1206 _ => None,
1207 })
1208 }
1209
1210 async fn execute_code_action_kind_locally(
1211 lsp_store: WeakEntity<LspStore>,
1212 mut buffers: Vec<Entity<Buffer>>,
1213 kind: CodeActionKind,
1214 push_to_history: bool,
1215 cx: &mut AsyncApp,
1216 ) -> anyhow::Result<ProjectTransaction> {
1217 // Do not allow multiple concurrent code actions requests for the
1218 // same buffer.
1219 lsp_store.update(cx, |this, cx| {
1220 let this = this.as_local_mut().unwrap();
1221 buffers.retain(|buffer| {
1222 this.buffers_being_formatted
1223 .insert(buffer.read(cx).remote_id())
1224 });
1225 })?;
1226 let _cleanup = defer({
1227 let this = lsp_store.clone();
1228 let mut cx = cx.clone();
1229 let buffers = &buffers;
1230 move || {
1231 this.update(&mut cx, |this, cx| {
1232 let this = this.as_local_mut().unwrap();
1233 for buffer in buffers {
1234 this.buffers_being_formatted
1235 .remove(&buffer.read(cx).remote_id());
1236 }
1237 })
1238 .ok();
1239 }
1240 });
1241 let mut project_transaction = ProjectTransaction::default();
1242
1243 for buffer in &buffers {
1244 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1245 buffer.update(cx, |buffer, cx| {
1246 lsp_store
1247 .as_local()
1248 .unwrap()
1249 .language_servers_for_buffer(buffer, cx)
1250 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1251 .collect::<Vec<_>>()
1252 })
1253 })?;
1254 for (_, language_server) in adapters_and_servers.iter() {
1255 let actions = Self::get_server_code_actions_from_action_kinds(
1256 &lsp_store,
1257 language_server.server_id(),
1258 vec![kind.clone()],
1259 buffer,
1260 cx,
1261 )
1262 .await?;
1263 Self::execute_code_actions_on_server(
1264 &lsp_store,
1265 language_server,
1266 actions,
1267 push_to_history,
1268 &mut project_transaction,
1269 cx,
1270 )
1271 .await?;
1272 }
1273 }
1274 Ok(project_transaction)
1275 }
1276
1277 async fn format_locally(
1278 lsp_store: WeakEntity<LspStore>,
1279 mut buffers: Vec<FormattableBuffer>,
1280 push_to_history: bool,
1281 trigger: FormatTrigger,
1282 logger: zlog::Logger,
1283 cx: &mut AsyncApp,
1284 ) -> anyhow::Result<ProjectTransaction> {
1285 // Do not allow multiple concurrent formatting requests for the
1286 // same buffer.
1287 lsp_store.update(cx, |this, cx| {
1288 let this = this.as_local_mut().unwrap();
1289 buffers.retain(|buffer| {
1290 this.buffers_being_formatted
1291 .insert(buffer.handle.read(cx).remote_id())
1292 });
1293 })?;
1294
1295 let _cleanup = defer({
1296 let this = lsp_store.clone();
1297 let mut cx = cx.clone();
1298 let buffers = &buffers;
1299 move || {
1300 this.update(&mut cx, |this, cx| {
1301 let this = this.as_local_mut().unwrap();
1302 for buffer in buffers {
1303 this.buffers_being_formatted
1304 .remove(&buffer.handle.read(cx).remote_id());
1305 }
1306 })
1307 .ok();
1308 }
1309 });
1310
1311 let mut project_transaction = ProjectTransaction::default();
1312
1313 for buffer in &buffers {
1314 zlog::debug!(
1315 logger =>
1316 "formatting buffer '{:?}'",
1317 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1318 );
1319 // Create an empty transaction to hold all of the formatting edits.
1320 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1321 // ensure no transactions created while formatting are
1322 // grouped with the previous transaction in the history
1323 // based on the transaction group interval
1324 buffer.finalize_last_transaction();
1325 buffer
1326 .start_transaction()
1327 .context("transaction already open")?;
1328 buffer.end_transaction(cx);
1329 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1330 buffer.finalize_last_transaction();
1331 anyhow::Ok(transaction_id)
1332 })??;
1333
1334 let result = Self::format_buffer_locally(
1335 lsp_store.clone(),
1336 buffer,
1337 formatting_transaction_id,
1338 trigger,
1339 logger,
1340 cx,
1341 )
1342 .await;
1343
1344 buffer.handle.update(cx, |buffer, cx| {
1345 let Some(formatting_transaction) =
1346 buffer.get_transaction(formatting_transaction_id).cloned()
1347 else {
1348 zlog::warn!(logger => "no formatting transaction");
1349 return;
1350 };
1351 if formatting_transaction.edit_ids.is_empty() {
1352 zlog::debug!(logger => "no changes made while formatting");
1353 buffer.forget_transaction(formatting_transaction_id);
1354 return;
1355 }
1356 if !push_to_history {
1357 zlog::trace!(logger => "forgetting format transaction");
1358 buffer.forget_transaction(formatting_transaction.id);
1359 }
1360 project_transaction
1361 .0
1362 .insert(cx.entity(), formatting_transaction);
1363 })?;
1364
1365 result?;
1366 }
1367
1368 Ok(project_transaction)
1369 }
1370
1371 async fn format_buffer_locally(
1372 lsp_store: WeakEntity<LspStore>,
1373 buffer: &FormattableBuffer,
1374 formatting_transaction_id: clock::Lamport,
1375 trigger: FormatTrigger,
1376 logger: zlog::Logger,
1377 cx: &mut AsyncApp,
1378 ) -> Result<()> {
1379 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1380 buffer.handle.update(cx, |buffer, cx| {
1381 let adapters_and_servers = lsp_store
1382 .as_local()
1383 .unwrap()
1384 .language_servers_for_buffer(buffer, cx)
1385 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1386 .collect::<Vec<_>>();
1387 let settings =
1388 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1389 .into_owned();
1390 (adapters_and_servers, settings)
1391 })
1392 })?;
1393
1394 /// Apply edits to the buffer that will become part of the formatting transaction.
1395 /// Fails if the buffer has been edited since the start of that transaction.
1396 fn extend_formatting_transaction(
1397 buffer: &FormattableBuffer,
1398 formatting_transaction_id: text::TransactionId,
1399 cx: &mut AsyncApp,
1400 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1401 ) -> anyhow::Result<()> {
1402 buffer.handle.update(cx, |buffer, cx| {
1403 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1404 if last_transaction_id != Some(formatting_transaction_id) {
1405 anyhow::bail!("Buffer edited while formatting. Aborting")
1406 }
1407 buffer.start_transaction();
1408 operation(buffer, cx);
1409 if let Some(transaction_id) = buffer.end_transaction(cx) {
1410 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1411 }
1412 Ok(())
1413 })?
1414 }
1415
1416 // handle whitespace formatting
1417 if settings.remove_trailing_whitespace_on_save {
1418 zlog::trace!(logger => "removing trailing whitespace");
1419 let diff = buffer
1420 .handle
1421 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1422 .await;
1423 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1424 buffer.apply_diff(diff, cx);
1425 })?;
1426 }
1427
1428 if settings.ensure_final_newline_on_save {
1429 zlog::trace!(logger => "ensuring final newline");
1430 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1431 buffer.ensure_final_newline(cx);
1432 })?;
1433 }
1434
1435 // Formatter for `code_actions_on_format` that runs before
1436 // the rest of the formatters
1437 let mut code_actions_on_format_formatters = None;
1438 let should_run_code_actions_on_format = !matches!(
1439 (trigger, &settings.format_on_save),
1440 (FormatTrigger::Save, &FormatOnSave::Off)
1441 );
1442 if should_run_code_actions_on_format {
1443 let have_code_actions_to_run_on_format = settings
1444 .code_actions_on_format
1445 .values()
1446 .any(|enabled| *enabled);
1447 if have_code_actions_to_run_on_format {
1448 zlog::trace!(logger => "going to run code actions on format");
1449 code_actions_on_format_formatters = Some(
1450 settings
1451 .code_actions_on_format
1452 .iter()
1453 .filter_map(|(action, enabled)| enabled.then_some(action))
1454 .cloned()
1455 .map(Formatter::CodeAction)
1456 .collect::<Vec<_>>(),
1457 );
1458 }
1459 }
1460
1461 let formatters = match (trigger, &settings.format_on_save) {
1462 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1463 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1464 settings.formatter.as_ref()
1465 }
1466 };
1467
1468 let formatters = code_actions_on_format_formatters
1469 .iter()
1470 .flatten()
1471 .chain(formatters);
1472
1473 for formatter in formatters {
1474 let formatter = if formatter == &Formatter::Auto {
1475 if settings.prettier.allowed {
1476 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1477 &Formatter::Prettier
1478 } else {
1479 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1480 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1481 }
1482 } else {
1483 formatter
1484 };
1485 match formatter {
1486 Formatter::Auto => unreachable!("Auto resolved above"),
1487 Formatter::Prettier => {
1488 let logger = zlog::scoped!(logger => "prettier");
1489 zlog::trace!(logger => "formatting");
1490 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1491
1492 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1493 lsp_store.prettier_store().unwrap().downgrade()
1494 })?;
1495 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1496 .await
1497 .transpose()?;
1498 let Some(diff) = diff else {
1499 zlog::trace!(logger => "No changes");
1500 continue;
1501 };
1502
1503 extend_formatting_transaction(
1504 buffer,
1505 formatting_transaction_id,
1506 cx,
1507 |buffer, cx| {
1508 buffer.apply_diff(diff, cx);
1509 },
1510 )?;
1511 }
1512 Formatter::External { command, arguments } => {
1513 let logger = zlog::scoped!(logger => "command");
1514 zlog::trace!(logger => "formatting");
1515 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1516
1517 let diff = Self::format_via_external_command(
1518 buffer,
1519 command.as_ref(),
1520 arguments.as_deref(),
1521 cx,
1522 )
1523 .await
1524 .with_context(|| {
1525 format!("Failed to format buffer via external command: {}", command)
1526 })?;
1527 let Some(diff) = diff else {
1528 zlog::trace!(logger => "No changes");
1529 continue;
1530 };
1531
1532 extend_formatting_transaction(
1533 buffer,
1534 formatting_transaction_id,
1535 cx,
1536 |buffer, cx| {
1537 buffer.apply_diff(diff, cx);
1538 },
1539 )?;
1540 }
1541 Formatter::LanguageServer(specifier) => {
1542 let logger = zlog::scoped!(logger => "language-server");
1543 zlog::trace!(logger => "formatting");
1544 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1545
1546 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1547 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1548 continue;
1549 };
1550
1551 let language_server = match specifier {
1552 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1553 adapters_and_servers.iter().find_map(|(adapter, server)| {
1554 if adapter.name.0.as_ref() == name {
1555 Some(server.clone())
1556 } else {
1557 None
1558 }
1559 })
1560 }
1561 settings::LanguageServerFormatterSpecifier::Current => {
1562 adapters_and_servers.first().map(|e| e.1.clone())
1563 }
1564 };
1565
1566 let Some(language_server) = language_server else {
1567 log::debug!(
1568 "No language server found to format buffer '{:?}'. Skipping",
1569 buffer_path_abs.as_path().to_string_lossy()
1570 );
1571 continue;
1572 };
1573
1574 zlog::trace!(
1575 logger =>
1576 "Formatting buffer '{:?}' using language server '{:?}'",
1577 buffer_path_abs.as_path().to_string_lossy(),
1578 language_server.name()
1579 );
1580
1581 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1582 zlog::trace!(logger => "formatting ranges");
1583 Self::format_ranges_via_lsp(
1584 &lsp_store,
1585 &buffer.handle,
1586 ranges,
1587 buffer_path_abs,
1588 &language_server,
1589 &settings,
1590 cx,
1591 )
1592 .await
1593 .context("Failed to format ranges via language server")?
1594 } else {
1595 zlog::trace!(logger => "formatting full");
1596 Self::format_via_lsp(
1597 &lsp_store,
1598 &buffer.handle,
1599 buffer_path_abs,
1600 &language_server,
1601 &settings,
1602 cx,
1603 )
1604 .await
1605 .context("failed to format via language server")?
1606 };
1607
1608 if edits.is_empty() {
1609 zlog::trace!(logger => "No changes");
1610 continue;
1611 }
1612 extend_formatting_transaction(
1613 buffer,
1614 formatting_transaction_id,
1615 cx,
1616 |buffer, cx| {
1617 buffer.edit(edits, None, cx);
1618 },
1619 )?;
1620 }
1621 Formatter::CodeAction(code_action_name) => {
1622 let logger = zlog::scoped!(logger => "code-actions");
1623 zlog::trace!(logger => "formatting");
1624 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1625
1626 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1627 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1628 continue;
1629 };
1630
1631 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1632 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1633
1634 let mut actions_and_servers = Vec::new();
1635
1636 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1637 let actions_result = Self::get_server_code_actions_from_action_kinds(
1638 &lsp_store,
1639 language_server.server_id(),
1640 vec![code_action_kind.clone()],
1641 &buffer.handle,
1642 cx,
1643 )
1644 .await
1645 .with_context(|| {
1646 format!(
1647 "Failed to resolve code action {:?} with language server {}",
1648 code_action_kind,
1649 language_server.name()
1650 )
1651 });
1652 let Ok(actions) = actions_result else {
1653 // note: it may be better to set result to the error and break formatters here
1654 // but for now we try to execute the actions that we can resolve and skip the rest
1655 zlog::error!(
1656 logger =>
1657 "Failed to resolve code action {:?} with language server {}",
1658 code_action_kind,
1659 language_server.name()
1660 );
1661 continue;
1662 };
1663 for action in actions {
1664 actions_and_servers.push((action, index));
1665 }
1666 }
1667
1668 if actions_and_servers.is_empty() {
1669 zlog::warn!(logger => "No code actions were resolved, continuing");
1670 continue;
1671 }
1672
1673 'actions: for (mut action, server_index) in actions_and_servers {
1674 let server = &adapters_and_servers[server_index].1;
1675
1676 let describe_code_action = |action: &CodeAction| {
1677 format!(
1678 "code action '{}' with title \"{}\" on server {}",
1679 action
1680 .lsp_action
1681 .action_kind()
1682 .unwrap_or("unknown".into())
1683 .as_str(),
1684 action.lsp_action.title(),
1685 server.name(),
1686 )
1687 };
1688
1689 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1690
1691 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1692 zlog::error!(
1693 logger =>
1694 "Failed to resolve {}. Error: {}",
1695 describe_code_action(&action),
1696 err
1697 );
1698 continue;
1699 }
1700
1701 if let Some(edit) = action.lsp_action.edit().cloned() {
1702 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1703 // but filters out and logs warnings for code actions that require unreasonably
1704 // difficult handling on our part, such as:
1705 // - applying edits that call commands
1706 // which can result in arbitrary workspace edits being sent from the server that
1707 // have no way of being tied back to the command that initiated them (i.e. we
1708 // can't know which edits are part of the format request, or if the server is done sending
1709 // actions in response to the command)
1710 // - actions that create/delete/modify/rename files other than the one we are formatting
1711 // as we then would need to handle such changes correctly in the local history as well
1712 // as the remote history through the ProjectTransaction
1713 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1714 // Supporting these actions is not impossible, but not supported as of yet.
1715 if edit.changes.is_none() && edit.document_changes.is_none() {
1716 zlog::trace!(
1717 logger =>
1718 "No changes for code action. Skipping {}",
1719 describe_code_action(&action),
1720 );
1721 continue;
1722 }
1723
1724 let mut operations = Vec::new();
1725 if let Some(document_changes) = edit.document_changes {
1726 match document_changes {
1727 lsp::DocumentChanges::Edits(edits) => operations.extend(
1728 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1729 ),
1730 lsp::DocumentChanges::Operations(ops) => operations = ops,
1731 }
1732 } else if let Some(changes) = edit.changes {
1733 operations.extend(changes.into_iter().map(|(uri, edits)| {
1734 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1735 text_document:
1736 lsp::OptionalVersionedTextDocumentIdentifier {
1737 uri,
1738 version: None,
1739 },
1740 edits: edits.into_iter().map(Edit::Plain).collect(),
1741 })
1742 }));
1743 }
1744
1745 let mut edits = Vec::with_capacity(operations.len());
1746
1747 if operations.is_empty() {
1748 zlog::trace!(
1749 logger =>
1750 "No changes for code action. Skipping {}",
1751 describe_code_action(&action),
1752 );
1753 continue;
1754 }
1755 for operation in operations {
1756 let op = match operation {
1757 lsp::DocumentChangeOperation::Edit(op) => op,
1758 lsp::DocumentChangeOperation::Op(_) => {
1759 zlog::warn!(
1760 logger =>
1761 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1762 describe_code_action(&action),
1763 );
1764 continue 'actions;
1765 }
1766 };
1767 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1768 zlog::warn!(
1769 logger =>
1770 "Failed to convert URI '{:?}' to file path. Skipping {}",
1771 &op.text_document.uri,
1772 describe_code_action(&action),
1773 );
1774 continue 'actions;
1775 };
1776 if &file_path != buffer_path_abs {
1777 zlog::warn!(
1778 logger =>
1779 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1780 file_path,
1781 buffer_path_abs,
1782 describe_code_action(&action),
1783 );
1784 continue 'actions;
1785 }
1786
1787 let mut lsp_edits = Vec::new();
1788 for edit in op.edits {
1789 match edit {
1790 Edit::Plain(edit) => {
1791 if !lsp_edits.contains(&edit) {
1792 lsp_edits.push(edit);
1793 }
1794 }
1795 Edit::Annotated(edit) => {
1796 if !lsp_edits.contains(&edit.text_edit) {
1797 lsp_edits.push(edit.text_edit);
1798 }
1799 }
1800 Edit::Snippet(_) => {
1801 zlog::warn!(
1802 logger =>
1803 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1804 describe_code_action(&action),
1805 );
1806 continue 'actions;
1807 }
1808 }
1809 }
1810 let edits_result = lsp_store
1811 .update(cx, |lsp_store, cx| {
1812 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1813 &buffer.handle,
1814 lsp_edits,
1815 server.server_id(),
1816 op.text_document.version,
1817 cx,
1818 )
1819 })?
1820 .await;
1821 let Ok(resolved_edits) = edits_result else {
1822 zlog::warn!(
1823 logger =>
1824 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1825 buffer_path_abs.as_path(),
1826 describe_code_action(&action),
1827 );
1828 continue 'actions;
1829 };
1830 edits.extend(resolved_edits);
1831 }
1832
1833 if edits.is_empty() {
1834 zlog::warn!(logger => "No edits resolved from LSP");
1835 continue;
1836 }
1837
1838 extend_formatting_transaction(
1839 buffer,
1840 formatting_transaction_id,
1841 cx,
1842 |buffer, cx| {
1843 zlog::info!(
1844 "Applying edits {edits:?}. Content: {:?}",
1845 buffer.text()
1846 );
1847 buffer.edit(edits, None, cx);
1848 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1849 },
1850 )?;
1851 }
1852
1853 if let Some(command) = action.lsp_action.command() {
1854 zlog::warn!(
1855 logger =>
1856 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1857 &command.command,
1858 );
1859
1860 // bail early if command is invalid
1861 let server_capabilities = server.capabilities();
1862 let available_commands = server_capabilities
1863 .execute_command_provider
1864 .as_ref()
1865 .map(|options| options.commands.as_slice())
1866 .unwrap_or_default();
1867 if !available_commands.contains(&command.command) {
1868 zlog::warn!(
1869 logger =>
1870 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1871 command.command,
1872 server.name(),
1873 );
1874 continue;
1875 }
1876
1877 // noop so we just ensure buffer hasn't been edited since resolving code actions
1878 extend_formatting_transaction(
1879 buffer,
1880 formatting_transaction_id,
1881 cx,
1882 |_, _| {},
1883 )?;
1884 zlog::info!(logger => "Executing command {}", &command.command);
1885
1886 lsp_store.update(cx, |this, _| {
1887 this.as_local_mut()
1888 .unwrap()
1889 .last_workspace_edits_by_language_server
1890 .remove(&server.server_id());
1891 })?;
1892
1893 let execute_command_result = server
1894 .request::<lsp::request::ExecuteCommand>(
1895 lsp::ExecuteCommandParams {
1896 command: command.command.clone(),
1897 arguments: command.arguments.clone().unwrap_or_default(),
1898 ..Default::default()
1899 },
1900 )
1901 .await
1902 .into_response();
1903
1904 if execute_command_result.is_err() {
1905 zlog::error!(
1906 logger =>
1907 "Failed to execute command '{}' as part of {}",
1908 &command.command,
1909 describe_code_action(&action),
1910 );
1911 continue 'actions;
1912 }
1913
1914 let mut project_transaction_command =
1915 lsp_store.update(cx, |this, _| {
1916 this.as_local_mut()
1917 .unwrap()
1918 .last_workspace_edits_by_language_server
1919 .remove(&server.server_id())
1920 .unwrap_or_default()
1921 })?;
1922
1923 if let Some(transaction) =
1924 project_transaction_command.0.remove(&buffer.handle)
1925 {
1926 zlog::trace!(
1927 logger =>
1928 "Successfully captured {} edits that resulted from command {}",
1929 transaction.edit_ids.len(),
1930 &command.command,
1931 );
1932 let transaction_id_project_transaction = transaction.id;
1933 buffer.handle.update(cx, |buffer, _| {
1934 // it may have been removed from history if push_to_history was
1935 // false in deserialize_workspace_edit. If so push it so we
1936 // can merge it with the format transaction
1937 // and pop the combined transaction off the history stack
1938 // later if push_to_history is false
1939 if buffer.get_transaction(transaction.id).is_none() {
1940 buffer.push_transaction(transaction, Instant::now());
1941 }
1942 buffer.merge_transactions(
1943 transaction_id_project_transaction,
1944 formatting_transaction_id,
1945 );
1946 })?;
1947 }
1948
1949 if !project_transaction_command.0.is_empty() {
1950 let mut extra_buffers = String::new();
1951 for buffer in project_transaction_command.0.keys() {
1952 buffer
1953 .read_with(cx, |b, cx| {
1954 if let Some(path) = b.project_path(cx) {
1955 if !extra_buffers.is_empty() {
1956 extra_buffers.push_str(", ");
1957 }
1958 extra_buffers.push_str(path.path.as_unix_str());
1959 }
1960 })
1961 .ok();
1962 }
1963 zlog::warn!(
1964 logger =>
1965 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1966 &command.command,
1967 extra_buffers,
1968 );
1969 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1970 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1971 // add it so it's included, and merge it into the format transaction when its created later
1972 }
1973 }
1974 }
1975 }
1976 }
1977 }
1978
1979 Ok(())
1980 }
1981
1982 pub async fn format_ranges_via_lsp(
1983 this: &WeakEntity<LspStore>,
1984 buffer_handle: &Entity<Buffer>,
1985 ranges: &[Range<Anchor>],
1986 abs_path: &Path,
1987 language_server: &Arc<LanguageServer>,
1988 settings: &LanguageSettings,
1989 cx: &mut AsyncApp,
1990 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1991 let capabilities = &language_server.capabilities();
1992 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1993 if range_formatting_provider == Some(&OneOf::Left(false)) {
1994 anyhow::bail!(
1995 "{} language server does not support range formatting",
1996 language_server.name()
1997 );
1998 }
1999
2000 let uri = file_path_to_lsp_url(abs_path)?;
2001 let text_document = lsp::TextDocumentIdentifier::new(uri);
2002
2003 let lsp_edits = {
2004 let mut lsp_ranges = Vec::new();
2005 this.update(cx, |_this, cx| {
2006 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2007 // not have been sent to the language server. This seems like a fairly systemic
2008 // issue, though, the resolution probably is not specific to formatting.
2009 //
2010 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2011 // LSP.
2012 let snapshot = buffer_handle.read(cx).snapshot();
2013 for range in ranges {
2014 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2015 }
2016 anyhow::Ok(())
2017 })??;
2018
2019 let mut edits = None;
2020 for range in lsp_ranges {
2021 if let Some(mut edit) = language_server
2022 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2023 text_document: text_document.clone(),
2024 range,
2025 options: lsp_command::lsp_formatting_options(settings),
2026 work_done_progress_params: Default::default(),
2027 })
2028 .await
2029 .into_response()?
2030 {
2031 edits.get_or_insert_with(Vec::new).append(&mut edit);
2032 }
2033 }
2034 edits
2035 };
2036
2037 if let Some(lsp_edits) = lsp_edits {
2038 this.update(cx, |this, cx| {
2039 this.as_local_mut().unwrap().edits_from_lsp(
2040 buffer_handle,
2041 lsp_edits,
2042 language_server.server_id(),
2043 None,
2044 cx,
2045 )
2046 })?
2047 .await
2048 } else {
2049 Ok(Vec::with_capacity(0))
2050 }
2051 }
2052
2053 async fn format_via_lsp(
2054 this: &WeakEntity<LspStore>,
2055 buffer: &Entity<Buffer>,
2056 abs_path: &Path,
2057 language_server: &Arc<LanguageServer>,
2058 settings: &LanguageSettings,
2059 cx: &mut AsyncApp,
2060 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2061 let logger = zlog::scoped!("lsp_format");
2062 zlog::debug!(logger => "Formatting via LSP");
2063
2064 let uri = file_path_to_lsp_url(abs_path)?;
2065 let text_document = lsp::TextDocumentIdentifier::new(uri);
2066 let capabilities = &language_server.capabilities();
2067
2068 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2069 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2070
2071 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2072 let _timer = zlog::time!(logger => "format-full");
2073 language_server
2074 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2075 text_document,
2076 options: lsp_command::lsp_formatting_options(settings),
2077 work_done_progress_params: Default::default(),
2078 })
2079 .await
2080 .into_response()?
2081 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2082 let _timer = zlog::time!(logger => "format-range");
2083 let buffer_start = lsp::Position::new(0, 0);
2084 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2085 language_server
2086 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2087 text_document: text_document.clone(),
2088 range: lsp::Range::new(buffer_start, buffer_end),
2089 options: lsp_command::lsp_formatting_options(settings),
2090 work_done_progress_params: Default::default(),
2091 })
2092 .await
2093 .into_response()?
2094 } else {
2095 None
2096 };
2097
2098 if let Some(lsp_edits) = lsp_edits {
2099 this.update(cx, |this, cx| {
2100 this.as_local_mut().unwrap().edits_from_lsp(
2101 buffer,
2102 lsp_edits,
2103 language_server.server_id(),
2104 None,
2105 cx,
2106 )
2107 })?
2108 .await
2109 } else {
2110 Ok(Vec::with_capacity(0))
2111 }
2112 }
2113
2114 async fn format_via_external_command(
2115 buffer: &FormattableBuffer,
2116 command: &str,
2117 arguments: Option<&[String]>,
2118 cx: &mut AsyncApp,
2119 ) -> Result<Option<Diff>> {
2120 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2121 let file = File::from_dyn(buffer.file())?;
2122 let worktree = file.worktree.read(cx);
2123 let mut worktree_path = worktree.abs_path().to_path_buf();
2124 if worktree.root_entry()?.is_file() {
2125 worktree_path.pop();
2126 }
2127 Some(worktree_path)
2128 })?;
2129
2130 let mut child = util::command::new_smol_command(command);
2131
2132 if let Some(buffer_env) = buffer.env.as_ref() {
2133 child.envs(buffer_env);
2134 }
2135
2136 if let Some(working_dir_path) = working_dir_path {
2137 child.current_dir(working_dir_path);
2138 }
2139
2140 if let Some(arguments) = arguments {
2141 child.args(arguments.iter().map(|arg| {
2142 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2143 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2144 } else {
2145 arg.replace("{buffer_path}", "Untitled")
2146 }
2147 }));
2148 }
2149
2150 let mut child = child
2151 .stdin(smol::process::Stdio::piped())
2152 .stdout(smol::process::Stdio::piped())
2153 .stderr(smol::process::Stdio::piped())
2154 .spawn()?;
2155
2156 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2157 let text = buffer
2158 .handle
2159 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2160 for chunk in text.chunks() {
2161 stdin.write_all(chunk.as_bytes()).await?;
2162 }
2163 stdin.flush().await?;
2164
2165 let output = child.output().await?;
2166 anyhow::ensure!(
2167 output.status.success(),
2168 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2169 output.status.code(),
2170 String::from_utf8_lossy(&output.stdout),
2171 String::from_utf8_lossy(&output.stderr),
2172 );
2173
2174 let stdout = String::from_utf8(output.stdout)?;
2175 Ok(Some(
2176 buffer
2177 .handle
2178 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2179 .await,
2180 ))
2181 }
2182
2183 async fn try_resolve_code_action(
2184 lang_server: &LanguageServer,
2185 action: &mut CodeAction,
2186 ) -> anyhow::Result<()> {
2187 match &mut action.lsp_action {
2188 LspAction::Action(lsp_action) => {
2189 if !action.resolved
2190 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2191 && lsp_action.data.is_some()
2192 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2193 {
2194 *lsp_action = Box::new(
2195 lang_server
2196 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2197 .await
2198 .into_response()?,
2199 );
2200 }
2201 }
2202 LspAction::CodeLens(lens) => {
2203 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2204 *lens = lang_server
2205 .request::<lsp::request::CodeLensResolve>(lens.clone())
2206 .await
2207 .into_response()?;
2208 }
2209 }
2210 LspAction::Command(_) => {}
2211 }
2212
2213 action.resolved = true;
2214 anyhow::Ok(())
2215 }
2216
2217 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2218 let buffer = buffer_handle.read(cx);
2219
2220 let file = buffer.file().cloned();
2221
2222 let Some(file) = File::from_dyn(file.as_ref()) else {
2223 return;
2224 };
2225 if !file.is_local() {
2226 return;
2227 }
2228 let path = ProjectPath::from_file(file, cx);
2229 let worktree_id = file.worktree_id(cx);
2230 let language = buffer.language().cloned();
2231
2232 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2233 for (server_id, diagnostics) in
2234 diagnostics.get(file.path()).cloned().unwrap_or_default()
2235 {
2236 self.update_buffer_diagnostics(
2237 buffer_handle,
2238 server_id,
2239 None,
2240 None,
2241 diagnostics,
2242 Vec::new(),
2243 cx,
2244 )
2245 .log_err();
2246 }
2247 }
2248 let Some(language) = language else {
2249 return;
2250 };
2251 let Some(snapshot) = self
2252 .worktree_store
2253 .read(cx)
2254 .worktree_for_id(worktree_id, cx)
2255 .map(|worktree| worktree.read(cx).snapshot())
2256 else {
2257 return;
2258 };
2259 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2260
2261 for server_id in
2262 self.lsp_tree
2263 .get(path, language.name(), language.manifest(), &delegate, cx)
2264 {
2265 let server = self
2266 .language_servers
2267 .get(&server_id)
2268 .and_then(|server_state| {
2269 if let LanguageServerState::Running { server, .. } = server_state {
2270 Some(server.clone())
2271 } else {
2272 None
2273 }
2274 });
2275 let server = match server {
2276 Some(server) => server,
2277 None => continue,
2278 };
2279
2280 buffer_handle.update(cx, |buffer, cx| {
2281 buffer.set_completion_triggers(
2282 server.server_id(),
2283 server
2284 .capabilities()
2285 .completion_provider
2286 .as_ref()
2287 .and_then(|provider| {
2288 provider
2289 .trigger_characters
2290 .as_ref()
2291 .map(|characters| characters.iter().cloned().collect())
2292 })
2293 .unwrap_or_default(),
2294 cx,
2295 );
2296 });
2297 }
2298 }
2299
2300 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2301 buffer.update(cx, |buffer, cx| {
2302 let Some(language) = buffer.language() else {
2303 return;
2304 };
2305 let path = ProjectPath {
2306 worktree_id: old_file.worktree_id(cx),
2307 path: old_file.path.clone(),
2308 };
2309 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2310 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2311 buffer.set_completion_triggers(server_id, Default::default(), cx);
2312 }
2313 });
2314 }
2315
2316 fn update_buffer_diagnostics(
2317 &mut self,
2318 buffer: &Entity<Buffer>,
2319 server_id: LanguageServerId,
2320 result_id: Option<String>,
2321 version: Option<i32>,
2322 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2323 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2324 cx: &mut Context<LspStore>,
2325 ) -> Result<()> {
2326 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2327 Ordering::Equal
2328 .then_with(|| b.is_primary.cmp(&a.is_primary))
2329 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2330 .then_with(|| a.severity.cmp(&b.severity))
2331 .then_with(|| a.message.cmp(&b.message))
2332 }
2333
2334 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2335 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2336 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2337
2338 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2339 Ordering::Equal
2340 .then_with(|| a.range.start.cmp(&b.range.start))
2341 .then_with(|| b.range.end.cmp(&a.range.end))
2342 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2343 });
2344
2345 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2346
2347 let edits_since_save = std::cell::LazyCell::new(|| {
2348 let saved_version = buffer.read(cx).saved_version();
2349 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2350 });
2351
2352 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2353
2354 for (new_diagnostic, entry) in diagnostics {
2355 let start;
2356 let end;
2357 if new_diagnostic && entry.diagnostic.is_disk_based {
2358 // Some diagnostics are based on files on disk instead of buffers'
2359 // current contents. Adjust these diagnostics' ranges to reflect
2360 // any unsaved edits.
2361 // Do not alter the reused ones though, as their coordinates were stored as anchors
2362 // and were properly adjusted on reuse.
2363 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2364 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2365 } else {
2366 start = entry.range.start;
2367 end = entry.range.end;
2368 }
2369
2370 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2371 ..snapshot.clip_point_utf16(end, Bias::Right);
2372
2373 // Expand empty ranges by one codepoint
2374 if range.start == range.end {
2375 // This will be go to the next boundary when being clipped
2376 range.end.column += 1;
2377 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2378 if range.start == range.end && range.end.column > 0 {
2379 range.start.column -= 1;
2380 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2381 }
2382 }
2383
2384 sanitized_diagnostics.push(DiagnosticEntry {
2385 range,
2386 diagnostic: entry.diagnostic,
2387 });
2388 }
2389 drop(edits_since_save);
2390
2391 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2392 buffer.update(cx, |buffer, cx| {
2393 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2394 self.buffer_pull_diagnostics_result_ids
2395 .entry(server_id)
2396 .or_default()
2397 .insert(abs_path, result_id);
2398 }
2399
2400 buffer.update_diagnostics(server_id, set, cx)
2401 });
2402
2403 Ok(())
2404 }
2405
2406 fn register_language_server_for_invisible_worktree(
2407 &mut self,
2408 worktree: &Entity<Worktree>,
2409 language_server_id: LanguageServerId,
2410 cx: &mut App,
2411 ) {
2412 let worktree = worktree.read(cx);
2413 let worktree_id = worktree.id();
2414 debug_assert!(!worktree.is_visible());
2415 let Some(mut origin_seed) = self
2416 .language_server_ids
2417 .iter()
2418 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2419 else {
2420 return;
2421 };
2422 origin_seed.worktree_id = worktree_id;
2423 self.language_server_ids
2424 .entry(origin_seed)
2425 .or_insert_with(|| UnifiedLanguageServer {
2426 id: language_server_id,
2427 project_roots: Default::default(),
2428 });
2429 }
2430
2431 fn register_buffer_with_language_servers(
2432 &mut self,
2433 buffer_handle: &Entity<Buffer>,
2434 only_register_servers: HashSet<LanguageServerSelector>,
2435 cx: &mut Context<LspStore>,
2436 ) {
2437 let buffer = buffer_handle.read(cx);
2438 let buffer_id = buffer.remote_id();
2439
2440 let Some(file) = File::from_dyn(buffer.file()) else {
2441 return;
2442 };
2443 if !file.is_local() {
2444 return;
2445 }
2446
2447 let abs_path = file.abs_path(cx);
2448 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2449 return;
2450 };
2451 let initial_snapshot = buffer.text_snapshot();
2452 let worktree_id = file.worktree_id(cx);
2453
2454 let Some(language) = buffer.language().cloned() else {
2455 return;
2456 };
2457 let path: Arc<RelPath> = file
2458 .path()
2459 .parent()
2460 .map(Arc::from)
2461 .unwrap_or_else(|| file.path().clone());
2462 let Some(worktree) = self
2463 .worktree_store
2464 .read(cx)
2465 .worktree_for_id(worktree_id, cx)
2466 else {
2467 return;
2468 };
2469 let language_name = language.name();
2470 let (reused, delegate, servers) = self
2471 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2472 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2473 .unwrap_or_else(|| {
2474 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2475 let delegate: Arc<dyn ManifestDelegate> =
2476 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2477
2478 let servers = self
2479 .lsp_tree
2480 .walk(
2481 ProjectPath { worktree_id, path },
2482 language.name(),
2483 language.manifest(),
2484 &delegate,
2485 cx,
2486 )
2487 .collect::<Vec<_>>();
2488 (false, lsp_delegate, servers)
2489 });
2490 let servers_and_adapters = servers
2491 .into_iter()
2492 .filter_map(|server_node| {
2493 if reused && server_node.server_id().is_none() {
2494 return None;
2495 }
2496 if !only_register_servers.is_empty() {
2497 if let Some(server_id) = server_node.server_id()
2498 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2499 {
2500 return None;
2501 }
2502 if let Some(name) = server_node.name()
2503 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2504 {
2505 return None;
2506 }
2507 }
2508
2509 let server_id = server_node.server_id_or_init(|disposition| {
2510 let path = &disposition.path;
2511
2512 {
2513 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2514
2515 let server_id = self.get_or_insert_language_server(
2516 &worktree,
2517 delegate.clone(),
2518 disposition,
2519 &language_name,
2520 cx,
2521 );
2522
2523 if let Some(state) = self.language_servers.get(&server_id)
2524 && let Ok(uri) = uri
2525 {
2526 state.add_workspace_folder(uri);
2527 };
2528 server_id
2529 }
2530 })?;
2531 let server_state = self.language_servers.get(&server_id)?;
2532 if let LanguageServerState::Running {
2533 server, adapter, ..
2534 } = server_state
2535 {
2536 Some((server.clone(), adapter.clone()))
2537 } else {
2538 None
2539 }
2540 })
2541 .collect::<Vec<_>>();
2542 for (server, adapter) in servers_and_adapters {
2543 buffer_handle.update(cx, |buffer, cx| {
2544 buffer.set_completion_triggers(
2545 server.server_id(),
2546 server
2547 .capabilities()
2548 .completion_provider
2549 .as_ref()
2550 .and_then(|provider| {
2551 provider
2552 .trigger_characters
2553 .as_ref()
2554 .map(|characters| characters.iter().cloned().collect())
2555 })
2556 .unwrap_or_default(),
2557 cx,
2558 );
2559 });
2560
2561 let snapshot = LspBufferSnapshot {
2562 version: 0,
2563 snapshot: initial_snapshot.clone(),
2564 };
2565
2566 let mut registered = false;
2567 self.buffer_snapshots
2568 .entry(buffer_id)
2569 .or_default()
2570 .entry(server.server_id())
2571 .or_insert_with(|| {
2572 registered = true;
2573 server.register_buffer(
2574 uri.clone(),
2575 adapter.language_id(&language.name()),
2576 0,
2577 initial_snapshot.text(),
2578 );
2579
2580 vec![snapshot]
2581 });
2582
2583 self.buffers_opened_in_servers
2584 .entry(buffer_id)
2585 .or_default()
2586 .insert(server.server_id());
2587 if registered {
2588 cx.emit(LspStoreEvent::LanguageServerUpdate {
2589 language_server_id: server.server_id(),
2590 name: None,
2591 message: proto::update_language_server::Variant::RegisteredForBuffer(
2592 proto::RegisteredForBuffer {
2593 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2594 buffer_id: buffer_id.to_proto(),
2595 },
2596 ),
2597 });
2598 }
2599 }
2600 }
2601
2602 fn reuse_existing_language_server<'lang_name>(
2603 &self,
2604 server_tree: &LanguageServerTree,
2605 worktree: &Entity<Worktree>,
2606 language_name: &'lang_name LanguageName,
2607 cx: &mut App,
2608 ) -> Option<(
2609 Arc<LocalLspAdapterDelegate>,
2610 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2611 )> {
2612 if worktree.read(cx).is_visible() {
2613 return None;
2614 }
2615
2616 let worktree_store = self.worktree_store.read(cx);
2617 let servers = server_tree
2618 .instances
2619 .iter()
2620 .filter(|(worktree_id, _)| {
2621 worktree_store
2622 .worktree_for_id(**worktree_id, cx)
2623 .is_some_and(|worktree| worktree.read(cx).is_visible())
2624 })
2625 .flat_map(|(worktree_id, servers)| {
2626 servers
2627 .roots
2628 .iter()
2629 .flat_map(|(_, language_servers)| language_servers)
2630 .map(move |(_, (server_node, server_languages))| {
2631 (worktree_id, server_node, server_languages)
2632 })
2633 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2634 .map(|(worktree_id, server_node, _)| {
2635 (
2636 *worktree_id,
2637 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2638 )
2639 })
2640 })
2641 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2642 acc.entry(worktree_id)
2643 .or_insert_with(Vec::new)
2644 .push(server_node);
2645 acc
2646 })
2647 .into_values()
2648 .max_by_key(|servers| servers.len())?;
2649
2650 let worktree_id = worktree.read(cx).id();
2651 let apply = move |tree: &mut LanguageServerTree| {
2652 for server_node in &servers {
2653 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2654 }
2655 servers
2656 };
2657
2658 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2659 Some((delegate, apply))
2660 }
2661
2662 pub(crate) fn unregister_old_buffer_from_language_servers(
2663 &mut self,
2664 buffer: &Entity<Buffer>,
2665 old_file: &File,
2666 cx: &mut App,
2667 ) {
2668 let old_path = match old_file.as_local() {
2669 Some(local) => local.abs_path(cx),
2670 None => return,
2671 };
2672
2673 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2674 debug_panic!("{old_path:?} is not parseable as an URI");
2675 return;
2676 };
2677 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2678 }
2679
2680 pub(crate) fn unregister_buffer_from_language_servers(
2681 &mut self,
2682 buffer: &Entity<Buffer>,
2683 file_url: &lsp::Uri,
2684 cx: &mut App,
2685 ) {
2686 buffer.update(cx, |buffer, cx| {
2687 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2688
2689 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2690 language_server.unregister_buffer(file_url.clone());
2691 }
2692 });
2693 }
2694
2695 fn buffer_snapshot_for_lsp_version(
2696 &mut self,
2697 buffer: &Entity<Buffer>,
2698 server_id: LanguageServerId,
2699 version: Option<i32>,
2700 cx: &App,
2701 ) -> Result<TextBufferSnapshot> {
2702 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2703
2704 if let Some(version) = version {
2705 let buffer_id = buffer.read(cx).remote_id();
2706 let snapshots = if let Some(snapshots) = self
2707 .buffer_snapshots
2708 .get_mut(&buffer_id)
2709 .and_then(|m| m.get_mut(&server_id))
2710 {
2711 snapshots
2712 } else if version == 0 {
2713 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2714 // We detect this case and treat it as if the version was `None`.
2715 return Ok(buffer.read(cx).text_snapshot());
2716 } else {
2717 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2718 };
2719
2720 let found_snapshot = snapshots
2721 .binary_search_by_key(&version, |e| e.version)
2722 .map(|ix| snapshots[ix].snapshot.clone())
2723 .map_err(|_| {
2724 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2725 })?;
2726
2727 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2728 Ok(found_snapshot)
2729 } else {
2730 Ok((buffer.read(cx)).text_snapshot())
2731 }
2732 }
2733
2734 async fn get_server_code_actions_from_action_kinds(
2735 lsp_store: &WeakEntity<LspStore>,
2736 language_server_id: LanguageServerId,
2737 code_action_kinds: Vec<lsp::CodeActionKind>,
2738 buffer: &Entity<Buffer>,
2739 cx: &mut AsyncApp,
2740 ) -> Result<Vec<CodeAction>> {
2741 let actions = lsp_store
2742 .update(cx, move |this, cx| {
2743 let request = GetCodeActions {
2744 range: text::Anchor::MIN..text::Anchor::MAX,
2745 kinds: Some(code_action_kinds),
2746 };
2747 let server = LanguageServerToQuery::Other(language_server_id);
2748 this.request_lsp(buffer.clone(), server, request, cx)
2749 })?
2750 .await?;
2751 Ok(actions)
2752 }
2753
2754 pub async fn execute_code_actions_on_server(
2755 lsp_store: &WeakEntity<LspStore>,
2756 language_server: &Arc<LanguageServer>,
2757
2758 actions: Vec<CodeAction>,
2759 push_to_history: bool,
2760 project_transaction: &mut ProjectTransaction,
2761 cx: &mut AsyncApp,
2762 ) -> anyhow::Result<()> {
2763 for mut action in actions {
2764 Self::try_resolve_code_action(language_server, &mut action)
2765 .await
2766 .context("resolving a formatting code action")?;
2767
2768 if let Some(edit) = action.lsp_action.edit() {
2769 if edit.changes.is_none() && edit.document_changes.is_none() {
2770 continue;
2771 }
2772
2773 let new = Self::deserialize_workspace_edit(
2774 lsp_store.upgrade().context("project dropped")?,
2775 edit.clone(),
2776 push_to_history,
2777 language_server.clone(),
2778 cx,
2779 )
2780 .await?;
2781 project_transaction.0.extend(new.0);
2782 }
2783
2784 if let Some(command) = action.lsp_action.command() {
2785 let server_capabilities = language_server.capabilities();
2786 let available_commands = server_capabilities
2787 .execute_command_provider
2788 .as_ref()
2789 .map(|options| options.commands.as_slice())
2790 .unwrap_or_default();
2791 if available_commands.contains(&command.command) {
2792 lsp_store.update(cx, |lsp_store, _| {
2793 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2794 mode.last_workspace_edits_by_language_server
2795 .remove(&language_server.server_id());
2796 }
2797 })?;
2798
2799 language_server
2800 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2801 command: command.command.clone(),
2802 arguments: command.arguments.clone().unwrap_or_default(),
2803 ..Default::default()
2804 })
2805 .await
2806 .into_response()
2807 .context("execute command")?;
2808
2809 lsp_store.update(cx, |this, _| {
2810 if let LspStoreMode::Local(mode) = &mut this.mode {
2811 project_transaction.0.extend(
2812 mode.last_workspace_edits_by_language_server
2813 .remove(&language_server.server_id())
2814 .unwrap_or_default()
2815 .0,
2816 )
2817 }
2818 })?;
2819 } else {
2820 log::warn!(
2821 "Cannot execute a command {} not listed in the language server capabilities",
2822 command.command
2823 )
2824 }
2825 }
2826 }
2827 Ok(())
2828 }
2829
2830 pub async fn deserialize_text_edits(
2831 this: Entity<LspStore>,
2832 buffer_to_edit: Entity<Buffer>,
2833 edits: Vec<lsp::TextEdit>,
2834 push_to_history: bool,
2835 _: Arc<CachedLspAdapter>,
2836 language_server: Arc<LanguageServer>,
2837 cx: &mut AsyncApp,
2838 ) -> Result<Option<Transaction>> {
2839 let edits = this
2840 .update(cx, |this, cx| {
2841 this.as_local_mut().unwrap().edits_from_lsp(
2842 &buffer_to_edit,
2843 edits,
2844 language_server.server_id(),
2845 None,
2846 cx,
2847 )
2848 })?
2849 .await?;
2850
2851 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2852 buffer.finalize_last_transaction();
2853 buffer.start_transaction();
2854 for (range, text) in edits {
2855 buffer.edit([(range, text)], None, cx);
2856 }
2857
2858 if buffer.end_transaction(cx).is_some() {
2859 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2860 if !push_to_history {
2861 buffer.forget_transaction(transaction.id);
2862 }
2863 Some(transaction)
2864 } else {
2865 None
2866 }
2867 })?;
2868
2869 Ok(transaction)
2870 }
2871
2872 #[allow(clippy::type_complexity)]
2873 pub(crate) fn edits_from_lsp(
2874 &mut self,
2875 buffer: &Entity<Buffer>,
2876 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2877 server_id: LanguageServerId,
2878 version: Option<i32>,
2879 cx: &mut Context<LspStore>,
2880 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2881 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2882 cx.background_spawn(async move {
2883 let snapshot = snapshot?;
2884 let mut lsp_edits = lsp_edits
2885 .into_iter()
2886 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2887 .collect::<Vec<_>>();
2888
2889 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2890
2891 let mut lsp_edits = lsp_edits.into_iter().peekable();
2892 let mut edits = Vec::new();
2893 while let Some((range, mut new_text)) = lsp_edits.next() {
2894 // Clip invalid ranges provided by the language server.
2895 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2896 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2897
2898 // Combine any LSP edits that are adjacent.
2899 //
2900 // Also, combine LSP edits that are separated from each other by only
2901 // a newline. This is important because for some code actions,
2902 // Rust-analyzer rewrites the entire buffer via a series of edits that
2903 // are separated by unchanged newline characters.
2904 //
2905 // In order for the diffing logic below to work properly, any edits that
2906 // cancel each other out must be combined into one.
2907 while let Some((next_range, next_text)) = lsp_edits.peek() {
2908 if next_range.start.0 > range.end {
2909 if next_range.start.0.row > range.end.row + 1
2910 || next_range.start.0.column > 0
2911 || snapshot.clip_point_utf16(
2912 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2913 Bias::Left,
2914 ) > range.end
2915 {
2916 break;
2917 }
2918 new_text.push('\n');
2919 }
2920 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2921 new_text.push_str(next_text);
2922 lsp_edits.next();
2923 }
2924
2925 // For multiline edits, perform a diff of the old and new text so that
2926 // we can identify the changes more precisely, preserving the locations
2927 // of any anchors positioned in the unchanged regions.
2928 if range.end.row > range.start.row {
2929 let offset = range.start.to_offset(&snapshot);
2930 let old_text = snapshot.text_for_range(range).collect::<String>();
2931 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2932 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2933 (
2934 snapshot.anchor_after(offset + range.start)
2935 ..snapshot.anchor_before(offset + range.end),
2936 replacement,
2937 )
2938 }));
2939 } else if range.end == range.start {
2940 let anchor = snapshot.anchor_after(range.start);
2941 edits.push((anchor..anchor, new_text.into()));
2942 } else {
2943 let edit_start = snapshot.anchor_after(range.start);
2944 let edit_end = snapshot.anchor_before(range.end);
2945 edits.push((edit_start..edit_end, new_text.into()));
2946 }
2947 }
2948
2949 Ok(edits)
2950 })
2951 }
2952
2953 pub(crate) async fn deserialize_workspace_edit(
2954 this: Entity<LspStore>,
2955 edit: lsp::WorkspaceEdit,
2956 push_to_history: bool,
2957 language_server: Arc<LanguageServer>,
2958 cx: &mut AsyncApp,
2959 ) -> Result<ProjectTransaction> {
2960 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2961
2962 let mut operations = Vec::new();
2963 if let Some(document_changes) = edit.document_changes {
2964 match document_changes {
2965 lsp::DocumentChanges::Edits(edits) => {
2966 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2967 }
2968 lsp::DocumentChanges::Operations(ops) => operations = ops,
2969 }
2970 } else if let Some(changes) = edit.changes {
2971 operations.extend(changes.into_iter().map(|(uri, edits)| {
2972 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2973 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2974 uri,
2975 version: None,
2976 },
2977 edits: edits.into_iter().map(Edit::Plain).collect(),
2978 })
2979 }));
2980 }
2981
2982 let mut project_transaction = ProjectTransaction::default();
2983 for operation in operations {
2984 match operation {
2985 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2986 let abs_path = op
2987 .uri
2988 .to_file_path()
2989 .map_err(|()| anyhow!("can't convert URI to path"))?;
2990
2991 if let Some(parent_path) = abs_path.parent() {
2992 fs.create_dir(parent_path).await?;
2993 }
2994 if abs_path.ends_with("/") {
2995 fs.create_dir(&abs_path).await?;
2996 } else {
2997 fs.create_file(
2998 &abs_path,
2999 op.options
3000 .map(|options| fs::CreateOptions {
3001 overwrite: options.overwrite.unwrap_or(false),
3002 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3003 })
3004 .unwrap_or_default(),
3005 )
3006 .await?;
3007 }
3008 }
3009
3010 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3011 let source_abs_path = op
3012 .old_uri
3013 .to_file_path()
3014 .map_err(|()| anyhow!("can't convert URI to path"))?;
3015 let target_abs_path = op
3016 .new_uri
3017 .to_file_path()
3018 .map_err(|()| anyhow!("can't convert URI to path"))?;
3019 fs.rename(
3020 &source_abs_path,
3021 &target_abs_path,
3022 op.options
3023 .map(|options| fs::RenameOptions {
3024 overwrite: options.overwrite.unwrap_or(false),
3025 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3026 })
3027 .unwrap_or_default(),
3028 )
3029 .await?;
3030 }
3031
3032 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3033 let abs_path = op
3034 .uri
3035 .to_file_path()
3036 .map_err(|()| anyhow!("can't convert URI to path"))?;
3037 let options = op
3038 .options
3039 .map(|options| fs::RemoveOptions {
3040 recursive: options.recursive.unwrap_or(false),
3041 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3042 })
3043 .unwrap_or_default();
3044 if abs_path.ends_with("/") {
3045 fs.remove_dir(&abs_path, options).await?;
3046 } else {
3047 fs.remove_file(&abs_path, options).await?;
3048 }
3049 }
3050
3051 lsp::DocumentChangeOperation::Edit(op) => {
3052 let buffer_to_edit = this
3053 .update(cx, |this, cx| {
3054 this.open_local_buffer_via_lsp(
3055 op.text_document.uri.clone(),
3056 language_server.server_id(),
3057 cx,
3058 )
3059 })?
3060 .await?;
3061
3062 let edits = this
3063 .update(cx, |this, cx| {
3064 let path = buffer_to_edit.read(cx).project_path(cx);
3065 let active_entry = this.active_entry;
3066 let is_active_entry = path.is_some_and(|project_path| {
3067 this.worktree_store
3068 .read(cx)
3069 .entry_for_path(&project_path, cx)
3070 .is_some_and(|entry| Some(entry.id) == active_entry)
3071 });
3072 let local = this.as_local_mut().unwrap();
3073
3074 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3075 for edit in op.edits {
3076 match edit {
3077 Edit::Plain(edit) => {
3078 if !edits.contains(&edit) {
3079 edits.push(edit)
3080 }
3081 }
3082 Edit::Annotated(edit) => {
3083 if !edits.contains(&edit.text_edit) {
3084 edits.push(edit.text_edit)
3085 }
3086 }
3087 Edit::Snippet(edit) => {
3088 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3089 else {
3090 continue;
3091 };
3092
3093 if is_active_entry {
3094 snippet_edits.push((edit.range, snippet));
3095 } else {
3096 // Since this buffer is not focused, apply a normal edit.
3097 let new_edit = TextEdit {
3098 range: edit.range,
3099 new_text: snippet.text,
3100 };
3101 if !edits.contains(&new_edit) {
3102 edits.push(new_edit);
3103 }
3104 }
3105 }
3106 }
3107 }
3108 if !snippet_edits.is_empty() {
3109 let buffer_id = buffer_to_edit.read(cx).remote_id();
3110 let version = if let Some(buffer_version) = op.text_document.version
3111 {
3112 local
3113 .buffer_snapshot_for_lsp_version(
3114 &buffer_to_edit,
3115 language_server.server_id(),
3116 Some(buffer_version),
3117 cx,
3118 )
3119 .ok()
3120 .map(|snapshot| snapshot.version)
3121 } else {
3122 Some(buffer_to_edit.read(cx).saved_version().clone())
3123 };
3124
3125 let most_recent_edit =
3126 version.and_then(|version| version.most_recent());
3127 // Check if the edit that triggered that edit has been made by this participant.
3128
3129 if let Some(most_recent_edit) = most_recent_edit {
3130 cx.emit(LspStoreEvent::SnippetEdit {
3131 buffer_id,
3132 edits: snippet_edits,
3133 most_recent_edit,
3134 });
3135 }
3136 }
3137
3138 local.edits_from_lsp(
3139 &buffer_to_edit,
3140 edits,
3141 language_server.server_id(),
3142 op.text_document.version,
3143 cx,
3144 )
3145 })?
3146 .await?;
3147
3148 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3149 buffer.finalize_last_transaction();
3150 buffer.start_transaction();
3151 for (range, text) in edits {
3152 buffer.edit([(range, text)], None, cx);
3153 }
3154
3155 buffer.end_transaction(cx).and_then(|transaction_id| {
3156 if push_to_history {
3157 buffer.finalize_last_transaction();
3158 buffer.get_transaction(transaction_id).cloned()
3159 } else {
3160 buffer.forget_transaction(transaction_id)
3161 }
3162 })
3163 })?;
3164 if let Some(transaction) = transaction {
3165 project_transaction.0.insert(buffer_to_edit, transaction);
3166 }
3167 }
3168 }
3169 }
3170
3171 Ok(project_transaction)
3172 }
3173
3174 async fn on_lsp_workspace_edit(
3175 this: WeakEntity<LspStore>,
3176 params: lsp::ApplyWorkspaceEditParams,
3177 server_id: LanguageServerId,
3178 cx: &mut AsyncApp,
3179 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3180 let this = this.upgrade().context("project project closed")?;
3181 let language_server = this
3182 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3183 .context("language server not found")?;
3184 let transaction = Self::deserialize_workspace_edit(
3185 this.clone(),
3186 params.edit,
3187 true,
3188 language_server.clone(),
3189 cx,
3190 )
3191 .await
3192 .log_err();
3193 this.update(cx, |this, _| {
3194 if let Some(transaction) = transaction {
3195 this.as_local_mut()
3196 .unwrap()
3197 .last_workspace_edits_by_language_server
3198 .insert(server_id, transaction);
3199 }
3200 })?;
3201 Ok(lsp::ApplyWorkspaceEditResponse {
3202 applied: true,
3203 failed_change: None,
3204 failure_reason: None,
3205 })
3206 }
3207
3208 fn remove_worktree(
3209 &mut self,
3210 id_to_remove: WorktreeId,
3211 cx: &mut Context<LspStore>,
3212 ) -> Vec<LanguageServerId> {
3213 self.diagnostics.remove(&id_to_remove);
3214 self.prettier_store.update(cx, |prettier_store, cx| {
3215 prettier_store.remove_worktree(id_to_remove, cx);
3216 });
3217
3218 let mut servers_to_remove = BTreeSet::default();
3219 let mut servers_to_preserve = HashSet::default();
3220 for (seed, state) in &self.language_server_ids {
3221 if seed.worktree_id == id_to_remove {
3222 servers_to_remove.insert(state.id);
3223 } else {
3224 servers_to_preserve.insert(state.id);
3225 }
3226 }
3227 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3228 self.language_server_ids
3229 .retain(|_, state| !servers_to_remove.contains(&state.id));
3230 for server_id_to_remove in &servers_to_remove {
3231 self.language_server_watched_paths
3232 .remove(server_id_to_remove);
3233 self.language_server_paths_watched_for_rename
3234 .remove(server_id_to_remove);
3235 self.last_workspace_edits_by_language_server
3236 .remove(server_id_to_remove);
3237 self.language_servers.remove(server_id_to_remove);
3238 self.buffer_pull_diagnostics_result_ids
3239 .remove(server_id_to_remove);
3240 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3241 buffer_servers.remove(server_id_to_remove);
3242 }
3243 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3244 }
3245 servers_to_remove.into_iter().collect()
3246 }
3247
3248 fn rebuild_watched_paths_inner<'a>(
3249 &'a self,
3250 language_server_id: LanguageServerId,
3251 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3252 cx: &mut Context<LspStore>,
3253 ) -> LanguageServerWatchedPathsBuilder {
3254 let worktrees = self
3255 .worktree_store
3256 .read(cx)
3257 .worktrees()
3258 .filter_map(|worktree| {
3259 self.language_servers_for_worktree(worktree.read(cx).id())
3260 .find(|server| server.server_id() == language_server_id)
3261 .map(|_| worktree)
3262 })
3263 .collect::<Vec<_>>();
3264
3265 let mut worktree_globs = HashMap::default();
3266 let mut abs_globs = HashMap::default();
3267 log::trace!(
3268 "Processing new watcher paths for language server with id {}",
3269 language_server_id
3270 );
3271
3272 for watcher in watchers {
3273 if let Some((worktree, literal_prefix, pattern)) =
3274 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3275 {
3276 worktree.update(cx, |worktree, _| {
3277 if let Some((tree, glob)) =
3278 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3279 {
3280 tree.add_path_prefix_to_scan(literal_prefix);
3281 worktree_globs
3282 .entry(tree.id())
3283 .or_insert_with(GlobSetBuilder::new)
3284 .add(glob);
3285 }
3286 });
3287 } else {
3288 let (path, pattern) = match &watcher.glob_pattern {
3289 lsp::GlobPattern::String(s) => {
3290 let watcher_path = SanitizedPath::new(s);
3291 let path = glob_literal_prefix(watcher_path.as_path());
3292 let pattern = watcher_path
3293 .as_path()
3294 .strip_prefix(&path)
3295 .map(|p| p.to_string_lossy().into_owned())
3296 .unwrap_or_else(|e| {
3297 debug_panic!(
3298 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3299 s,
3300 path.display(),
3301 e
3302 );
3303 watcher_path.as_path().to_string_lossy().into_owned()
3304 });
3305 (path, pattern)
3306 }
3307 lsp::GlobPattern::Relative(rp) => {
3308 let Ok(mut base_uri) = match &rp.base_uri {
3309 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3310 lsp::OneOf::Right(base_uri) => base_uri,
3311 }
3312 .to_file_path() else {
3313 continue;
3314 };
3315
3316 let path = glob_literal_prefix(Path::new(&rp.pattern));
3317 let pattern = Path::new(&rp.pattern)
3318 .strip_prefix(&path)
3319 .map(|p| p.to_string_lossy().into_owned())
3320 .unwrap_or_else(|e| {
3321 debug_panic!(
3322 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3323 rp.pattern,
3324 path.display(),
3325 e
3326 );
3327 rp.pattern.clone()
3328 });
3329 base_uri.push(path);
3330 (base_uri, pattern)
3331 }
3332 };
3333
3334 if let Some(glob) = Glob::new(&pattern).log_err() {
3335 if !path
3336 .components()
3337 .any(|c| matches!(c, path::Component::Normal(_)))
3338 {
3339 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3340 // rather than adding a new watcher for `/`.
3341 for worktree in &worktrees {
3342 worktree_globs
3343 .entry(worktree.read(cx).id())
3344 .or_insert_with(GlobSetBuilder::new)
3345 .add(glob.clone());
3346 }
3347 } else {
3348 abs_globs
3349 .entry(path.into())
3350 .or_insert_with(GlobSetBuilder::new)
3351 .add(glob);
3352 }
3353 }
3354 }
3355 }
3356
3357 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3358 for (worktree_id, builder) in worktree_globs {
3359 if let Ok(globset) = builder.build() {
3360 watch_builder.watch_worktree(worktree_id, globset);
3361 }
3362 }
3363 for (abs_path, builder) in abs_globs {
3364 if let Ok(globset) = builder.build() {
3365 watch_builder.watch_abs_path(abs_path, globset);
3366 }
3367 }
3368 watch_builder
3369 }
3370
3371 fn worktree_and_path_for_file_watcher(
3372 worktrees: &[Entity<Worktree>],
3373 watcher: &FileSystemWatcher,
3374 cx: &App,
3375 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3376 worktrees.iter().find_map(|worktree| {
3377 let tree = worktree.read(cx);
3378 let worktree_root_path = tree.abs_path();
3379 let path_style = tree.path_style();
3380 match &watcher.glob_pattern {
3381 lsp::GlobPattern::String(s) => {
3382 let watcher_path = SanitizedPath::new(s);
3383 let relative = watcher_path
3384 .as_path()
3385 .strip_prefix(&worktree_root_path)
3386 .ok()?;
3387 let literal_prefix = glob_literal_prefix(relative);
3388 Some((
3389 worktree.clone(),
3390 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3391 relative.to_string_lossy().into_owned(),
3392 ))
3393 }
3394 lsp::GlobPattern::Relative(rp) => {
3395 let base_uri = match &rp.base_uri {
3396 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3397 lsp::OneOf::Right(base_uri) => base_uri,
3398 }
3399 .to_file_path()
3400 .ok()?;
3401 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3402 let mut literal_prefix = relative.to_owned();
3403 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3404 Some((
3405 worktree.clone(),
3406 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3407 rp.pattern.clone(),
3408 ))
3409 }
3410 }
3411 })
3412 }
3413
3414 fn rebuild_watched_paths(
3415 &mut self,
3416 language_server_id: LanguageServerId,
3417 cx: &mut Context<LspStore>,
3418 ) {
3419 let Some(registrations) = self
3420 .language_server_dynamic_registrations
3421 .get(&language_server_id)
3422 else {
3423 return;
3424 };
3425
3426 let watch_builder = self.rebuild_watched_paths_inner(
3427 language_server_id,
3428 registrations.did_change_watched_files.values().flatten(),
3429 cx,
3430 );
3431 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3432 self.language_server_watched_paths
3433 .insert(language_server_id, watcher);
3434
3435 cx.notify();
3436 }
3437
3438 fn on_lsp_did_change_watched_files(
3439 &mut self,
3440 language_server_id: LanguageServerId,
3441 registration_id: &str,
3442 params: DidChangeWatchedFilesRegistrationOptions,
3443 cx: &mut Context<LspStore>,
3444 ) {
3445 let registrations = self
3446 .language_server_dynamic_registrations
3447 .entry(language_server_id)
3448 .or_default();
3449
3450 registrations
3451 .did_change_watched_files
3452 .insert(registration_id.to_string(), params.watchers);
3453
3454 self.rebuild_watched_paths(language_server_id, cx);
3455 }
3456
3457 fn on_lsp_unregister_did_change_watched_files(
3458 &mut self,
3459 language_server_id: LanguageServerId,
3460 registration_id: &str,
3461 cx: &mut Context<LspStore>,
3462 ) {
3463 let registrations = self
3464 .language_server_dynamic_registrations
3465 .entry(language_server_id)
3466 .or_default();
3467
3468 if registrations
3469 .did_change_watched_files
3470 .remove(registration_id)
3471 .is_some()
3472 {
3473 log::info!(
3474 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3475 language_server_id,
3476 registration_id
3477 );
3478 } else {
3479 log::warn!(
3480 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3481 language_server_id,
3482 registration_id
3483 );
3484 }
3485
3486 self.rebuild_watched_paths(language_server_id, cx);
3487 }
3488
3489 async fn initialization_options_for_adapter(
3490 adapter: Arc<dyn LspAdapter>,
3491 delegate: &Arc<dyn LspAdapterDelegate>,
3492 ) -> Result<Option<serde_json::Value>> {
3493 let Some(mut initialization_config) =
3494 adapter.clone().initialization_options(delegate).await?
3495 else {
3496 return Ok(None);
3497 };
3498
3499 for other_adapter in delegate.registered_lsp_adapters() {
3500 if other_adapter.name() == adapter.name() {
3501 continue;
3502 }
3503 if let Ok(Some(target_config)) = other_adapter
3504 .clone()
3505 .additional_initialization_options(adapter.name(), delegate)
3506 .await
3507 {
3508 merge_json_value_into(target_config.clone(), &mut initialization_config);
3509 }
3510 }
3511
3512 Ok(Some(initialization_config))
3513 }
3514
3515 async fn workspace_configuration_for_adapter(
3516 adapter: Arc<dyn LspAdapter>,
3517 delegate: &Arc<dyn LspAdapterDelegate>,
3518 toolchain: Option<Toolchain>,
3519 cx: &mut AsyncApp,
3520 ) -> Result<serde_json::Value> {
3521 let mut workspace_config = adapter
3522 .clone()
3523 .workspace_configuration(delegate, toolchain, cx)
3524 .await?;
3525
3526 for other_adapter in delegate.registered_lsp_adapters() {
3527 if other_adapter.name() == adapter.name() {
3528 continue;
3529 }
3530 if let Ok(Some(target_config)) = other_adapter
3531 .clone()
3532 .additional_workspace_configuration(adapter.name(), delegate, cx)
3533 .await
3534 {
3535 merge_json_value_into(target_config.clone(), &mut workspace_config);
3536 }
3537 }
3538
3539 Ok(workspace_config)
3540 }
3541
3542 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3543 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3544 Some(server.clone())
3545 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3546 Some(Arc::clone(server))
3547 } else {
3548 None
3549 }
3550 }
3551}
3552
3553fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3554 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3555 cx.emit(LspStoreEvent::LanguageServerUpdate {
3556 language_server_id: server.server_id(),
3557 name: Some(server.name()),
3558 message: proto::update_language_server::Variant::MetadataUpdated(
3559 proto::ServerMetadataUpdated {
3560 capabilities: Some(capabilities),
3561 binary: Some(proto::LanguageServerBinaryInfo {
3562 path: server.binary().path.to_string_lossy().into_owned(),
3563 arguments: server
3564 .binary()
3565 .arguments
3566 .iter()
3567 .map(|arg| arg.to_string_lossy().into_owned())
3568 .collect(),
3569 }),
3570 configuration: serde_json::to_string(server.configuration()).ok(),
3571 workspace_folders: server
3572 .workspace_folders()
3573 .iter()
3574 .map(|uri| uri.to_string())
3575 .collect(),
3576 },
3577 ),
3578 });
3579 }
3580}
3581
3582#[derive(Debug)]
3583pub struct FormattableBuffer {
3584 handle: Entity<Buffer>,
3585 abs_path: Option<PathBuf>,
3586 env: Option<HashMap<String, String>>,
3587 ranges: Option<Vec<Range<Anchor>>>,
3588}
3589
3590pub struct RemoteLspStore {
3591 upstream_client: Option<AnyProtoClient>,
3592 upstream_project_id: u64,
3593}
3594
3595pub(crate) enum LspStoreMode {
3596 Local(LocalLspStore), // ssh host and collab host
3597 Remote(RemoteLspStore), // collab guest
3598}
3599
3600impl LspStoreMode {
3601 fn is_local(&self) -> bool {
3602 matches!(self, LspStoreMode::Local(_))
3603 }
3604}
3605
3606pub struct LspStore {
3607 mode: LspStoreMode,
3608 last_formatting_failure: Option<String>,
3609 downstream_client: Option<(AnyProtoClient, u64)>,
3610 nonce: u128,
3611 buffer_store: Entity<BufferStore>,
3612 worktree_store: Entity<WorktreeStore>,
3613 pub languages: Arc<LanguageRegistry>,
3614 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3615 active_entry: Option<ProjectEntryId>,
3616 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3617 _maintain_buffer_languages: Task<()>,
3618 diagnostic_summaries:
3619 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3620 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3621 lsp_data: HashMap<BufferId, BufferLspData>,
3622 next_hint_id: Arc<AtomicUsize>,
3623}
3624
3625#[derive(Debug)]
3626pub struct BufferLspData {
3627 buffer_version: Global,
3628 document_colors: Option<DocumentColorData>,
3629 code_lens: Option<CodeLensData>,
3630 inlay_hints: BufferInlayHints,
3631 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3632 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3633}
3634
3635#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3636struct LspKey {
3637 request_type: TypeId,
3638 server_queried: Option<LanguageServerId>,
3639}
3640
3641impl BufferLspData {
3642 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3643 Self {
3644 buffer_version: buffer.read(cx).version(),
3645 document_colors: None,
3646 code_lens: None,
3647 inlay_hints: BufferInlayHints::new(buffer, cx),
3648 lsp_requests: HashMap::default(),
3649 chunk_lsp_requests: HashMap::default(),
3650 }
3651 }
3652
3653 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3654 if let Some(document_colors) = &mut self.document_colors {
3655 document_colors.colors.remove(&for_server);
3656 document_colors.cache_version += 1;
3657 }
3658
3659 if let Some(code_lens) = &mut self.code_lens {
3660 code_lens.lens.remove(&for_server);
3661 }
3662
3663 self.inlay_hints.remove_server_data(for_server);
3664 }
3665
3666 #[cfg(any(test, feature = "test-support"))]
3667 pub fn inlay_hints(&self) -> &BufferInlayHints {
3668 &self.inlay_hints
3669 }
3670}
3671
3672#[derive(Debug, Default, Clone)]
3673pub struct DocumentColors {
3674 pub colors: HashSet<DocumentColor>,
3675 pub cache_version: Option<usize>,
3676}
3677
3678type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3679type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3680
3681#[derive(Debug, Default)]
3682struct DocumentColorData {
3683 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3684 cache_version: usize,
3685 colors_update: Option<(Global, DocumentColorTask)>,
3686}
3687
3688#[derive(Debug, Default)]
3689struct CodeLensData {
3690 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3691 update: Option<(Global, CodeLensTask)>,
3692}
3693
3694#[derive(Debug)]
3695pub enum LspStoreEvent {
3696 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3697 LanguageServerRemoved(LanguageServerId),
3698 LanguageServerUpdate {
3699 language_server_id: LanguageServerId,
3700 name: Option<LanguageServerName>,
3701 message: proto::update_language_server::Variant,
3702 },
3703 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3704 LanguageServerPrompt(LanguageServerPromptRequest),
3705 LanguageDetected {
3706 buffer: Entity<Buffer>,
3707 new_language: Option<Arc<Language>>,
3708 },
3709 Notification(String),
3710 RefreshInlayHints {
3711 server_id: LanguageServerId,
3712 request_id: Option<usize>,
3713 },
3714 RefreshCodeLens,
3715 DiagnosticsUpdated {
3716 server_id: LanguageServerId,
3717 paths: Vec<ProjectPath>,
3718 },
3719 DiskBasedDiagnosticsStarted {
3720 language_server_id: LanguageServerId,
3721 },
3722 DiskBasedDiagnosticsFinished {
3723 language_server_id: LanguageServerId,
3724 },
3725 SnippetEdit {
3726 buffer_id: BufferId,
3727 edits: Vec<(lsp::Range, Snippet)>,
3728 most_recent_edit: clock::Lamport,
3729 },
3730}
3731
3732#[derive(Clone, Debug, Serialize)]
3733pub struct LanguageServerBinaryInfo {
3734 pub path: String,
3735 pub arguments: Vec<String>,
3736 pub env: Option<HashMap<String, String>>,
3737}
3738
3739#[derive(Clone, Debug, Serialize)]
3740pub struct LanguageServerStatus {
3741 pub name: LanguageServerName,
3742 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3743 pub has_pending_diagnostic_updates: bool,
3744 pub progress_tokens: HashSet<ProgressToken>,
3745 pub worktree: Option<WorktreeId>,
3746 pub binary: Option<LanguageServerBinaryInfo>,
3747 pub configuration: Option<Value>,
3748 pub workspace_folders: BTreeSet<Uri>,
3749}
3750
3751#[derive(Clone, Debug)]
3752struct CoreSymbol {
3753 pub language_server_name: LanguageServerName,
3754 pub source_worktree_id: WorktreeId,
3755 pub source_language_server_id: LanguageServerId,
3756 pub path: SymbolLocation,
3757 pub name: String,
3758 pub kind: lsp::SymbolKind,
3759 pub range: Range<Unclipped<PointUtf16>>,
3760}
3761
3762#[derive(Clone, Debug, PartialEq, Eq)]
3763pub enum SymbolLocation {
3764 InProject(ProjectPath),
3765 OutsideProject {
3766 abs_path: Arc<Path>,
3767 signature: [u8; 32],
3768 },
3769}
3770
3771impl SymbolLocation {
3772 fn file_name(&self) -> Option<&str> {
3773 match self {
3774 Self::InProject(path) => path.path.file_name(),
3775 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3776 }
3777 }
3778}
3779
3780impl LspStore {
3781 pub fn init(client: &AnyProtoClient) {
3782 client.add_entity_request_handler(Self::handle_lsp_query);
3783 client.add_entity_message_handler(Self::handle_lsp_query_response);
3784 client.add_entity_request_handler(Self::handle_restart_language_servers);
3785 client.add_entity_request_handler(Self::handle_stop_language_servers);
3786 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3787 client.add_entity_message_handler(Self::handle_start_language_server);
3788 client.add_entity_message_handler(Self::handle_update_language_server);
3789 client.add_entity_message_handler(Self::handle_language_server_log);
3790 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3791 client.add_entity_request_handler(Self::handle_format_buffers);
3792 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3793 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3794 client.add_entity_request_handler(Self::handle_apply_code_action);
3795 client.add_entity_request_handler(Self::handle_get_project_symbols);
3796 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3797 client.add_entity_request_handler(Self::handle_get_color_presentation);
3798 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3799 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3800 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3801 client.add_entity_request_handler(Self::handle_on_type_formatting);
3802 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3803 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3804 client.add_entity_request_handler(Self::handle_rename_project_entry);
3805 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3806 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3807 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3808 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3809 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3810 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3811 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3812
3813 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3814 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3815 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3816 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3817 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3818 client.add_entity_request_handler(
3819 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3820 );
3821 client.add_entity_request_handler(
3822 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3823 );
3824 client.add_entity_request_handler(
3825 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3826 );
3827 }
3828
3829 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3830 match &self.mode {
3831 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3832 _ => None,
3833 }
3834 }
3835
3836 pub fn as_local(&self) -> Option<&LocalLspStore> {
3837 match &self.mode {
3838 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3839 _ => None,
3840 }
3841 }
3842
3843 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3844 match &mut self.mode {
3845 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3846 _ => None,
3847 }
3848 }
3849
3850 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3851 match &self.mode {
3852 LspStoreMode::Remote(RemoteLspStore {
3853 upstream_client: Some(upstream_client),
3854 upstream_project_id,
3855 ..
3856 }) => Some((upstream_client.clone(), *upstream_project_id)),
3857
3858 LspStoreMode::Remote(RemoteLspStore {
3859 upstream_client: None,
3860 ..
3861 }) => None,
3862 LspStoreMode::Local(_) => None,
3863 }
3864 }
3865
3866 pub fn new_local(
3867 buffer_store: Entity<BufferStore>,
3868 worktree_store: Entity<WorktreeStore>,
3869 prettier_store: Entity<PrettierStore>,
3870 toolchain_store: Entity<LocalToolchainStore>,
3871 environment: Entity<ProjectEnvironment>,
3872 manifest_tree: Entity<ManifestTree>,
3873 languages: Arc<LanguageRegistry>,
3874 http_client: Arc<dyn HttpClient>,
3875 fs: Arc<dyn Fs>,
3876 cx: &mut Context<Self>,
3877 ) -> Self {
3878 let yarn = YarnPathStore::new(fs.clone(), cx);
3879 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3880 .detach();
3881 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3882 .detach();
3883 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3884 .detach();
3885 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3886 .detach();
3887 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3888 .detach();
3889 subscribe_to_binary_statuses(&languages, cx).detach();
3890
3891 let _maintain_workspace_config = {
3892 let (sender, receiver) = watch::channel();
3893 (Self::maintain_workspace_config(receiver, cx), sender)
3894 };
3895
3896 Self {
3897 mode: LspStoreMode::Local(LocalLspStore {
3898 weak: cx.weak_entity(),
3899 worktree_store: worktree_store.clone(),
3900
3901 supplementary_language_servers: Default::default(),
3902 languages: languages.clone(),
3903 language_server_ids: Default::default(),
3904 language_servers: Default::default(),
3905 last_workspace_edits_by_language_server: Default::default(),
3906 language_server_watched_paths: Default::default(),
3907 language_server_paths_watched_for_rename: Default::default(),
3908 language_server_dynamic_registrations: Default::default(),
3909 buffers_being_formatted: Default::default(),
3910 buffer_snapshots: Default::default(),
3911 prettier_store,
3912 environment,
3913 http_client,
3914 fs,
3915 yarn,
3916 next_diagnostic_group_id: Default::default(),
3917 diagnostics: Default::default(),
3918 _subscription: cx.on_app_quit(|this, cx| {
3919 this.as_local_mut()
3920 .unwrap()
3921 .shutdown_language_servers_on_quit(cx)
3922 }),
3923 lsp_tree: LanguageServerTree::new(
3924 manifest_tree,
3925 languages.clone(),
3926 toolchain_store.clone(),
3927 ),
3928 toolchain_store,
3929 registered_buffers: HashMap::default(),
3930 buffers_opened_in_servers: HashMap::default(),
3931 buffer_pull_diagnostics_result_ids: HashMap::default(),
3932 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3933 .manifest_file_names(),
3934 }),
3935 last_formatting_failure: None,
3936 downstream_client: None,
3937 buffer_store,
3938 worktree_store,
3939 languages: languages.clone(),
3940 language_server_statuses: Default::default(),
3941 nonce: StdRng::from_os_rng().random(),
3942 diagnostic_summaries: HashMap::default(),
3943 lsp_server_capabilities: HashMap::default(),
3944 lsp_data: HashMap::default(),
3945 next_hint_id: Arc::default(),
3946 active_entry: None,
3947 _maintain_workspace_config,
3948 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3949 }
3950 }
3951
3952 fn send_lsp_proto_request<R: LspCommand>(
3953 &self,
3954 buffer: Entity<Buffer>,
3955 client: AnyProtoClient,
3956 upstream_project_id: u64,
3957 request: R,
3958 cx: &mut Context<LspStore>,
3959 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3960 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3961 return Task::ready(Ok(R::Response::default()));
3962 }
3963 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3964 cx.spawn(async move |this, cx| {
3965 let response = client.request(message).await?;
3966 let this = this.upgrade().context("project dropped")?;
3967 request
3968 .response_from_proto(response, this, buffer, cx.clone())
3969 .await
3970 })
3971 }
3972
3973 pub(super) fn new_remote(
3974 buffer_store: Entity<BufferStore>,
3975 worktree_store: Entity<WorktreeStore>,
3976 languages: Arc<LanguageRegistry>,
3977 upstream_client: AnyProtoClient,
3978 project_id: u64,
3979 cx: &mut Context<Self>,
3980 ) -> Self {
3981 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3982 .detach();
3983 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3984 .detach();
3985 subscribe_to_binary_statuses(&languages, cx).detach();
3986 let _maintain_workspace_config = {
3987 let (sender, receiver) = watch::channel();
3988 (Self::maintain_workspace_config(receiver, cx), sender)
3989 };
3990 Self {
3991 mode: LspStoreMode::Remote(RemoteLspStore {
3992 upstream_client: Some(upstream_client),
3993 upstream_project_id: project_id,
3994 }),
3995 downstream_client: None,
3996 last_formatting_failure: None,
3997 buffer_store,
3998 worktree_store,
3999 languages: languages.clone(),
4000 language_server_statuses: Default::default(),
4001 nonce: StdRng::from_os_rng().random(),
4002 diagnostic_summaries: HashMap::default(),
4003 lsp_server_capabilities: HashMap::default(),
4004 next_hint_id: Arc::default(),
4005 lsp_data: HashMap::default(),
4006 active_entry: None,
4007
4008 _maintain_workspace_config,
4009 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4010 }
4011 }
4012
4013 fn on_buffer_store_event(
4014 &mut self,
4015 _: Entity<BufferStore>,
4016 event: &BufferStoreEvent,
4017 cx: &mut Context<Self>,
4018 ) {
4019 match event {
4020 BufferStoreEvent::BufferAdded(buffer) => {
4021 self.on_buffer_added(buffer, cx).log_err();
4022 }
4023 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4024 let buffer_id = buffer.read(cx).remote_id();
4025 if let Some(local) = self.as_local_mut()
4026 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4027 {
4028 local.reset_buffer(buffer, old_file, cx);
4029
4030 if local.registered_buffers.contains_key(&buffer_id) {
4031 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4032 }
4033 }
4034
4035 self.detect_language_for_buffer(buffer, cx);
4036 if let Some(local) = self.as_local_mut() {
4037 local.initialize_buffer(buffer, cx);
4038 if local.registered_buffers.contains_key(&buffer_id) {
4039 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4040 }
4041 }
4042 }
4043 _ => {}
4044 }
4045 }
4046
4047 fn on_worktree_store_event(
4048 &mut self,
4049 _: Entity<WorktreeStore>,
4050 event: &WorktreeStoreEvent,
4051 cx: &mut Context<Self>,
4052 ) {
4053 match event {
4054 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4055 if !worktree.read(cx).is_local() {
4056 return;
4057 }
4058 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4059 worktree::Event::UpdatedEntries(changes) => {
4060 this.update_local_worktree_language_servers(&worktree, changes, cx);
4061 }
4062 worktree::Event::UpdatedGitRepositories(_)
4063 | worktree::Event::DeletedEntry(_) => {}
4064 })
4065 .detach()
4066 }
4067 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4068 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4069 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4070 }
4071 WorktreeStoreEvent::WorktreeReleased(..)
4072 | WorktreeStoreEvent::WorktreeOrderChanged
4073 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4074 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4075 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4076 }
4077 }
4078
4079 fn on_prettier_store_event(
4080 &mut self,
4081 _: Entity<PrettierStore>,
4082 event: &PrettierStoreEvent,
4083 cx: &mut Context<Self>,
4084 ) {
4085 match event {
4086 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4087 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4088 }
4089 PrettierStoreEvent::LanguageServerAdded {
4090 new_server_id,
4091 name,
4092 prettier_server,
4093 } => {
4094 self.register_supplementary_language_server(
4095 *new_server_id,
4096 name.clone(),
4097 prettier_server.clone(),
4098 cx,
4099 );
4100 }
4101 }
4102 }
4103
4104 fn on_toolchain_store_event(
4105 &mut self,
4106 _: Entity<LocalToolchainStore>,
4107 event: &ToolchainStoreEvent,
4108 _: &mut Context<Self>,
4109 ) {
4110 if let ToolchainStoreEvent::ToolchainActivated = event {
4111 self.request_workspace_config_refresh()
4112 }
4113 }
4114
4115 fn request_workspace_config_refresh(&mut self) {
4116 *self._maintain_workspace_config.1.borrow_mut() = ();
4117 }
4118
4119 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4120 self.as_local().map(|local| local.prettier_store.clone())
4121 }
4122
4123 fn on_buffer_event(
4124 &mut self,
4125 buffer: Entity<Buffer>,
4126 event: &language::BufferEvent,
4127 cx: &mut Context<Self>,
4128 ) {
4129 match event {
4130 language::BufferEvent::Edited => {
4131 self.on_buffer_edited(buffer, cx);
4132 }
4133
4134 language::BufferEvent::Saved => {
4135 self.on_buffer_saved(buffer, cx);
4136 }
4137
4138 _ => {}
4139 }
4140 }
4141
4142 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4143 buffer
4144 .read(cx)
4145 .set_language_registry(self.languages.clone());
4146
4147 cx.subscribe(buffer, |this, buffer, event, cx| {
4148 this.on_buffer_event(buffer, event, cx);
4149 })
4150 .detach();
4151
4152 self.detect_language_for_buffer(buffer, cx);
4153 if let Some(local) = self.as_local_mut() {
4154 local.initialize_buffer(buffer, cx);
4155 }
4156
4157 Ok(())
4158 }
4159
4160 pub(crate) fn register_buffer_with_language_servers(
4161 &mut self,
4162 buffer: &Entity<Buffer>,
4163 only_register_servers: HashSet<LanguageServerSelector>,
4164 ignore_refcounts: bool,
4165 cx: &mut Context<Self>,
4166 ) -> OpenLspBufferHandle {
4167 let buffer_id = buffer.read(cx).remote_id();
4168 let handle = cx.new(|_| buffer.clone());
4169 if let Some(local) = self.as_local_mut() {
4170 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4171 if !ignore_refcounts {
4172 *refcount += 1;
4173 }
4174
4175 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4176 // 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
4177 // 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
4178 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4179 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4180 return handle;
4181 };
4182 if !file.is_local() {
4183 return handle;
4184 }
4185
4186 if ignore_refcounts || *refcount == 1 {
4187 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4188 }
4189 if !ignore_refcounts {
4190 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4191 let refcount = {
4192 let local = lsp_store.as_local_mut().unwrap();
4193 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4194 debug_panic!("bad refcounting");
4195 return;
4196 };
4197
4198 *refcount -= 1;
4199 *refcount
4200 };
4201 if refcount == 0 {
4202 lsp_store.lsp_data.remove(&buffer_id);
4203 let local = lsp_store.as_local_mut().unwrap();
4204 local.registered_buffers.remove(&buffer_id);
4205 local.buffers_opened_in_servers.remove(&buffer_id);
4206 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4207 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4208 }
4209 }
4210 })
4211 .detach();
4212 }
4213 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4214 let buffer_id = buffer.read(cx).remote_id().to_proto();
4215 cx.background_spawn(async move {
4216 upstream_client
4217 .request(proto::RegisterBufferWithLanguageServers {
4218 project_id: upstream_project_id,
4219 buffer_id,
4220 only_servers: only_register_servers
4221 .into_iter()
4222 .map(|selector| {
4223 let selector = match selector {
4224 LanguageServerSelector::Id(language_server_id) => {
4225 proto::language_server_selector::Selector::ServerId(
4226 language_server_id.to_proto(),
4227 )
4228 }
4229 LanguageServerSelector::Name(language_server_name) => {
4230 proto::language_server_selector::Selector::Name(
4231 language_server_name.to_string(),
4232 )
4233 }
4234 };
4235 proto::LanguageServerSelector {
4236 selector: Some(selector),
4237 }
4238 })
4239 .collect(),
4240 })
4241 .await
4242 })
4243 .detach();
4244 } else {
4245 // Our remote connection got closed
4246 }
4247 handle
4248 }
4249
4250 fn maintain_buffer_languages(
4251 languages: Arc<LanguageRegistry>,
4252 cx: &mut Context<Self>,
4253 ) -> Task<()> {
4254 let mut subscription = languages.subscribe();
4255 let mut prev_reload_count = languages.reload_count();
4256 cx.spawn(async move |this, cx| {
4257 while let Some(()) = subscription.next().await {
4258 if let Some(this) = this.upgrade() {
4259 // If the language registry has been reloaded, then remove and
4260 // re-assign the languages on all open buffers.
4261 let reload_count = languages.reload_count();
4262 if reload_count > prev_reload_count {
4263 prev_reload_count = reload_count;
4264 this.update(cx, |this, cx| {
4265 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4266 for buffer in buffer_store.buffers() {
4267 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4268 {
4269 buffer
4270 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4271 if let Some(local) = this.as_local_mut() {
4272 local.reset_buffer(&buffer, &f, cx);
4273
4274 if local
4275 .registered_buffers
4276 .contains_key(&buffer.read(cx).remote_id())
4277 && let Some(file_url) =
4278 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4279 {
4280 local.unregister_buffer_from_language_servers(
4281 &buffer, &file_url, cx,
4282 );
4283 }
4284 }
4285 }
4286 }
4287 });
4288 })
4289 .ok();
4290 }
4291
4292 this.update(cx, |this, cx| {
4293 let mut plain_text_buffers = Vec::new();
4294 let mut buffers_with_unknown_injections = Vec::new();
4295 for handle in this.buffer_store.read(cx).buffers() {
4296 let buffer = handle.read(cx);
4297 if buffer.language().is_none()
4298 || buffer.language() == Some(&*language::PLAIN_TEXT)
4299 {
4300 plain_text_buffers.push(handle);
4301 } else if buffer.contains_unknown_injections() {
4302 buffers_with_unknown_injections.push(handle);
4303 }
4304 }
4305
4306 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4307 // and reused later in the invisible worktrees.
4308 plain_text_buffers.sort_by_key(|buffer| {
4309 Reverse(
4310 File::from_dyn(buffer.read(cx).file())
4311 .map(|file| file.worktree.read(cx).is_visible()),
4312 )
4313 });
4314
4315 for buffer in plain_text_buffers {
4316 this.detect_language_for_buffer(&buffer, cx);
4317 if let Some(local) = this.as_local_mut() {
4318 local.initialize_buffer(&buffer, cx);
4319 if local
4320 .registered_buffers
4321 .contains_key(&buffer.read(cx).remote_id())
4322 {
4323 local.register_buffer_with_language_servers(
4324 &buffer,
4325 HashSet::default(),
4326 cx,
4327 );
4328 }
4329 }
4330 }
4331
4332 for buffer in buffers_with_unknown_injections {
4333 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4334 }
4335 })
4336 .ok();
4337 }
4338 }
4339 })
4340 }
4341
4342 fn detect_language_for_buffer(
4343 &mut self,
4344 buffer_handle: &Entity<Buffer>,
4345 cx: &mut Context<Self>,
4346 ) -> Option<language::AvailableLanguage> {
4347 // If the buffer has a language, set it and start the language server if we haven't already.
4348 let buffer = buffer_handle.read(cx);
4349 let file = buffer.file()?;
4350
4351 let content = buffer.as_rope();
4352 let available_language = self.languages.language_for_file(file, Some(content), cx);
4353 if let Some(available_language) = &available_language {
4354 if let Some(Ok(Ok(new_language))) = self
4355 .languages
4356 .load_language(available_language)
4357 .now_or_never()
4358 {
4359 self.set_language_for_buffer(buffer_handle, new_language, cx);
4360 }
4361 } else {
4362 cx.emit(LspStoreEvent::LanguageDetected {
4363 buffer: buffer_handle.clone(),
4364 new_language: None,
4365 });
4366 }
4367
4368 available_language
4369 }
4370
4371 pub(crate) fn set_language_for_buffer(
4372 &mut self,
4373 buffer_entity: &Entity<Buffer>,
4374 new_language: Arc<Language>,
4375 cx: &mut Context<Self>,
4376 ) {
4377 let buffer = buffer_entity.read(cx);
4378 let buffer_file = buffer.file().cloned();
4379 let buffer_id = buffer.remote_id();
4380 if let Some(local_store) = self.as_local_mut()
4381 && local_store.registered_buffers.contains_key(&buffer_id)
4382 && let Some(abs_path) =
4383 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4384 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4385 {
4386 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4387 }
4388 buffer_entity.update(cx, |buffer, cx| {
4389 if buffer
4390 .language()
4391 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4392 {
4393 buffer.set_language(Some(new_language.clone()), cx);
4394 }
4395 });
4396
4397 let settings =
4398 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4399 let buffer_file = File::from_dyn(buffer_file.as_ref());
4400
4401 let worktree_id = if let Some(file) = buffer_file {
4402 let worktree = file.worktree.clone();
4403
4404 if let Some(local) = self.as_local_mut()
4405 && local.registered_buffers.contains_key(&buffer_id)
4406 {
4407 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4408 }
4409 Some(worktree.read(cx).id())
4410 } else {
4411 None
4412 };
4413
4414 if settings.prettier.allowed
4415 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4416 {
4417 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4418 if let Some(prettier_store) = prettier_store {
4419 prettier_store.update(cx, |prettier_store, cx| {
4420 prettier_store.install_default_prettier(
4421 worktree_id,
4422 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4423 cx,
4424 )
4425 })
4426 }
4427 }
4428
4429 cx.emit(LspStoreEvent::LanguageDetected {
4430 buffer: buffer_entity.clone(),
4431 new_language: Some(new_language),
4432 })
4433 }
4434
4435 pub fn buffer_store(&self) -> Entity<BufferStore> {
4436 self.buffer_store.clone()
4437 }
4438
4439 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4440 self.active_entry = active_entry;
4441 }
4442
4443 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4444 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4445 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4446 {
4447 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4448 summaries
4449 .iter()
4450 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4451 });
4452 if let Some(summary) = summaries.next() {
4453 client
4454 .send(proto::UpdateDiagnosticSummary {
4455 project_id: downstream_project_id,
4456 worktree_id: worktree.id().to_proto(),
4457 summary: Some(summary),
4458 more_summaries: summaries.collect(),
4459 })
4460 .log_err();
4461 }
4462 }
4463 }
4464
4465 fn is_capable_for_proto_request<R>(
4466 &self,
4467 buffer: &Entity<Buffer>,
4468 request: &R,
4469 cx: &App,
4470 ) -> bool
4471 where
4472 R: LspCommand,
4473 {
4474 self.check_if_capable_for_proto_request(
4475 buffer,
4476 |capabilities| {
4477 request.check_capabilities(AdapterServerCapabilities {
4478 server_capabilities: capabilities.clone(),
4479 code_action_kinds: None,
4480 })
4481 },
4482 cx,
4483 )
4484 }
4485
4486 fn check_if_capable_for_proto_request<F>(
4487 &self,
4488 buffer: &Entity<Buffer>,
4489 check: F,
4490 cx: &App,
4491 ) -> bool
4492 where
4493 F: FnMut(&lsp::ServerCapabilities) -> bool,
4494 {
4495 let Some(language) = buffer.read(cx).language().cloned() else {
4496 return false;
4497 };
4498 let relevant_language_servers = self
4499 .languages
4500 .lsp_adapters(&language.name())
4501 .into_iter()
4502 .map(|lsp_adapter| lsp_adapter.name())
4503 .collect::<HashSet<_>>();
4504 self.language_server_statuses
4505 .iter()
4506 .filter_map(|(server_id, server_status)| {
4507 relevant_language_servers
4508 .contains(&server_status.name)
4509 .then_some(server_id)
4510 })
4511 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4512 .any(check)
4513 }
4514
4515 fn all_capable_for_proto_request<F>(
4516 &self,
4517 buffer: &Entity<Buffer>,
4518 mut check: F,
4519 cx: &App,
4520 ) -> Vec<lsp::LanguageServerId>
4521 where
4522 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4523 {
4524 let Some(language) = buffer.read(cx).language().cloned() else {
4525 return Vec::default();
4526 };
4527 let relevant_language_servers = self
4528 .languages
4529 .lsp_adapters(&language.name())
4530 .into_iter()
4531 .map(|lsp_adapter| lsp_adapter.name())
4532 .collect::<HashSet<_>>();
4533 self.language_server_statuses
4534 .iter()
4535 .filter_map(|(server_id, server_status)| {
4536 relevant_language_servers
4537 .contains(&server_status.name)
4538 .then_some((server_id, &server_status.name))
4539 })
4540 .filter_map(|(server_id, server_name)| {
4541 self.lsp_server_capabilities
4542 .get(server_id)
4543 .map(|c| (server_id, server_name, c))
4544 })
4545 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4546 .map(|(server_id, _, _)| *server_id)
4547 .collect()
4548 }
4549
4550 pub fn request_lsp<R>(
4551 &mut self,
4552 buffer: Entity<Buffer>,
4553 server: LanguageServerToQuery,
4554 request: R,
4555 cx: &mut Context<Self>,
4556 ) -> Task<Result<R::Response>>
4557 where
4558 R: LspCommand,
4559 <R::LspRequest as lsp::request::Request>::Result: Send,
4560 <R::LspRequest as lsp::request::Request>::Params: Send,
4561 {
4562 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4563 return self.send_lsp_proto_request(
4564 buffer,
4565 upstream_client,
4566 upstream_project_id,
4567 request,
4568 cx,
4569 );
4570 }
4571
4572 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4573 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4574 local
4575 .language_servers_for_buffer(buffer, cx)
4576 .find(|(_, server)| {
4577 request.check_capabilities(server.adapter_server_capabilities())
4578 })
4579 .map(|(_, server)| server.clone())
4580 }),
4581 LanguageServerToQuery::Other(id) => self
4582 .language_server_for_local_buffer(buffer, id, cx)
4583 .and_then(|(_, server)| {
4584 request
4585 .check_capabilities(server.adapter_server_capabilities())
4586 .then(|| Arc::clone(server))
4587 }),
4588 }) else {
4589 return Task::ready(Ok(Default::default()));
4590 };
4591
4592 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4593
4594 let Some(file) = file else {
4595 return Task::ready(Ok(Default::default()));
4596 };
4597
4598 let lsp_params = match request.to_lsp_params_or_response(
4599 &file.abs_path(cx),
4600 buffer.read(cx),
4601 &language_server,
4602 cx,
4603 ) {
4604 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4605 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4606 Err(err) => {
4607 let message = format!(
4608 "{} via {} failed: {}",
4609 request.display_name(),
4610 language_server.name(),
4611 err
4612 );
4613 // rust-analyzer likes to error with this when its still loading up
4614 if !message.ends_with("content modified") {
4615 log::warn!("{message}");
4616 }
4617 return Task::ready(Err(anyhow!(message)));
4618 }
4619 };
4620
4621 let status = request.status();
4622 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4623 return Task::ready(Ok(Default::default()));
4624 }
4625 cx.spawn(async move |this, cx| {
4626 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4627
4628 let id = lsp_request.id();
4629 let _cleanup = if status.is_some() {
4630 cx.update(|cx| {
4631 this.update(cx, |this, cx| {
4632 this.on_lsp_work_start(
4633 language_server.server_id(),
4634 ProgressToken::Number(id),
4635 LanguageServerProgress {
4636 is_disk_based_diagnostics_progress: false,
4637 is_cancellable: false,
4638 title: None,
4639 message: status.clone(),
4640 percentage: None,
4641 last_update_at: cx.background_executor().now(),
4642 },
4643 cx,
4644 );
4645 })
4646 })
4647 .log_err();
4648
4649 Some(defer(|| {
4650 cx.update(|cx| {
4651 this.update(cx, |this, cx| {
4652 this.on_lsp_work_end(
4653 language_server.server_id(),
4654 ProgressToken::Number(id),
4655 cx,
4656 );
4657 })
4658 })
4659 .log_err();
4660 }))
4661 } else {
4662 None
4663 };
4664
4665 let result = lsp_request.await.into_response();
4666
4667 let response = result.map_err(|err| {
4668 let message = format!(
4669 "{} via {} failed: {}",
4670 request.display_name(),
4671 language_server.name(),
4672 err
4673 );
4674 // rust-analyzer likes to error with this when its still loading up
4675 if !message.ends_with("content modified") {
4676 log::warn!("{message}");
4677 }
4678 anyhow::anyhow!(message)
4679 })?;
4680
4681 request
4682 .response_from_lsp(
4683 response,
4684 this.upgrade().context("no app context")?,
4685 buffer,
4686 language_server.server_id(),
4687 cx.clone(),
4688 )
4689 .await
4690 })
4691 }
4692
4693 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4694 let mut language_formatters_to_check = Vec::new();
4695 for buffer in self.buffer_store.read(cx).buffers() {
4696 let buffer = buffer.read(cx);
4697 let buffer_file = File::from_dyn(buffer.file());
4698 let buffer_language = buffer.language();
4699 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4700 if buffer_language.is_some() {
4701 language_formatters_to_check.push((
4702 buffer_file.map(|f| f.worktree_id(cx)),
4703 settings.into_owned(),
4704 ));
4705 }
4706 }
4707
4708 self.request_workspace_config_refresh();
4709
4710 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4711 prettier_store.update(cx, |prettier_store, cx| {
4712 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4713 })
4714 }
4715
4716 cx.notify();
4717 }
4718
4719 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4720 let buffer_store = self.buffer_store.clone();
4721 let Some(local) = self.as_local_mut() else {
4722 return;
4723 };
4724 let mut adapters = BTreeMap::default();
4725 let get_adapter = {
4726 let languages = local.languages.clone();
4727 let environment = local.environment.clone();
4728 let weak = local.weak.clone();
4729 let worktree_store = local.worktree_store.clone();
4730 let http_client = local.http_client.clone();
4731 let fs = local.fs.clone();
4732 move |worktree_id, cx: &mut App| {
4733 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4734 Some(LocalLspAdapterDelegate::new(
4735 languages.clone(),
4736 &environment,
4737 weak.clone(),
4738 &worktree,
4739 http_client.clone(),
4740 fs.clone(),
4741 cx,
4742 ))
4743 }
4744 };
4745
4746 let mut messages_to_report = Vec::new();
4747 let (new_tree, to_stop) = {
4748 let mut rebase = local.lsp_tree.rebase();
4749 let buffers = buffer_store
4750 .read(cx)
4751 .buffers()
4752 .filter_map(|buffer| {
4753 let raw_buffer = buffer.read(cx);
4754 if !local
4755 .registered_buffers
4756 .contains_key(&raw_buffer.remote_id())
4757 {
4758 return None;
4759 }
4760 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4761 let language = raw_buffer.language().cloned()?;
4762 Some((file, language, raw_buffer.remote_id()))
4763 })
4764 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4765 for (file, language, buffer_id) in buffers {
4766 let worktree_id = file.worktree_id(cx);
4767 let Some(worktree) = local
4768 .worktree_store
4769 .read(cx)
4770 .worktree_for_id(worktree_id, cx)
4771 else {
4772 continue;
4773 };
4774
4775 if let Some((_, apply)) = local.reuse_existing_language_server(
4776 rebase.server_tree(),
4777 &worktree,
4778 &language.name(),
4779 cx,
4780 ) {
4781 (apply)(rebase.server_tree());
4782 } else if let Some(lsp_delegate) = adapters
4783 .entry(worktree_id)
4784 .or_insert_with(|| get_adapter(worktree_id, cx))
4785 .clone()
4786 {
4787 let delegate =
4788 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4789 let path = file
4790 .path()
4791 .parent()
4792 .map(Arc::from)
4793 .unwrap_or_else(|| file.path().clone());
4794 let worktree_path = ProjectPath { worktree_id, path };
4795 let abs_path = file.abs_path(cx);
4796 let nodes = rebase
4797 .walk(
4798 worktree_path,
4799 language.name(),
4800 language.manifest(),
4801 delegate.clone(),
4802 cx,
4803 )
4804 .collect::<Vec<_>>();
4805 for node in nodes {
4806 let server_id = node.server_id_or_init(|disposition| {
4807 let path = &disposition.path;
4808 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4809 let key = LanguageServerSeed {
4810 worktree_id,
4811 name: disposition.server_name.clone(),
4812 settings: disposition.settings.clone(),
4813 toolchain: local.toolchain_store.read(cx).active_toolchain(
4814 path.worktree_id,
4815 &path.path,
4816 language.name(),
4817 ),
4818 };
4819 local.language_server_ids.remove(&key);
4820
4821 let server_id = local.get_or_insert_language_server(
4822 &worktree,
4823 lsp_delegate.clone(),
4824 disposition,
4825 &language.name(),
4826 cx,
4827 );
4828 if let Some(state) = local.language_servers.get(&server_id)
4829 && let Ok(uri) = uri
4830 {
4831 state.add_workspace_folder(uri);
4832 };
4833 server_id
4834 });
4835
4836 if let Some(language_server_id) = server_id {
4837 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4838 language_server_id,
4839 name: node.name(),
4840 message:
4841 proto::update_language_server::Variant::RegisteredForBuffer(
4842 proto::RegisteredForBuffer {
4843 buffer_abs_path: abs_path
4844 .to_string_lossy()
4845 .into_owned(),
4846 buffer_id: buffer_id.to_proto(),
4847 },
4848 ),
4849 });
4850 }
4851 }
4852 } else {
4853 continue;
4854 }
4855 }
4856 rebase.finish()
4857 };
4858 for message in messages_to_report {
4859 cx.emit(message);
4860 }
4861 local.lsp_tree = new_tree;
4862 for (id, _) in to_stop {
4863 self.stop_local_language_server(id, cx).detach();
4864 }
4865 }
4866
4867 pub fn apply_code_action(
4868 &self,
4869 buffer_handle: Entity<Buffer>,
4870 mut action: CodeAction,
4871 push_to_history: bool,
4872 cx: &mut Context<Self>,
4873 ) -> Task<Result<ProjectTransaction>> {
4874 if let Some((upstream_client, project_id)) = self.upstream_client() {
4875 let request = proto::ApplyCodeAction {
4876 project_id,
4877 buffer_id: buffer_handle.read(cx).remote_id().into(),
4878 action: Some(Self::serialize_code_action(&action)),
4879 };
4880 let buffer_store = self.buffer_store();
4881 cx.spawn(async move |_, cx| {
4882 let response = upstream_client
4883 .request(request)
4884 .await?
4885 .transaction
4886 .context("missing transaction")?;
4887
4888 buffer_store
4889 .update(cx, |buffer_store, cx| {
4890 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4891 })?
4892 .await
4893 })
4894 } else if self.mode.is_local() {
4895 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4896 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4897 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4898 }) else {
4899 return Task::ready(Ok(ProjectTransaction::default()));
4900 };
4901 cx.spawn(async move |this, cx| {
4902 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4903 .await
4904 .context("resolving a code action")?;
4905 if let Some(edit) = action.lsp_action.edit()
4906 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4907 return LocalLspStore::deserialize_workspace_edit(
4908 this.upgrade().context("no app present")?,
4909 edit.clone(),
4910 push_to_history,
4911
4912 lang_server.clone(),
4913 cx,
4914 )
4915 .await;
4916 }
4917
4918 if let Some(command) = action.lsp_action.command() {
4919 let server_capabilities = lang_server.capabilities();
4920 let available_commands = server_capabilities
4921 .execute_command_provider
4922 .as_ref()
4923 .map(|options| options.commands.as_slice())
4924 .unwrap_or_default();
4925 if available_commands.contains(&command.command) {
4926 this.update(cx, |this, _| {
4927 this.as_local_mut()
4928 .unwrap()
4929 .last_workspace_edits_by_language_server
4930 .remove(&lang_server.server_id());
4931 })?;
4932
4933 let _result = lang_server
4934 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4935 command: command.command.clone(),
4936 arguments: command.arguments.clone().unwrap_or_default(),
4937 ..lsp::ExecuteCommandParams::default()
4938 })
4939 .await.into_response()
4940 .context("execute command")?;
4941
4942 return this.update(cx, |this, _| {
4943 this.as_local_mut()
4944 .unwrap()
4945 .last_workspace_edits_by_language_server
4946 .remove(&lang_server.server_id())
4947 .unwrap_or_default()
4948 });
4949 } else {
4950 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4951 }
4952 }
4953
4954 Ok(ProjectTransaction::default())
4955 })
4956 } else {
4957 Task::ready(Err(anyhow!("no upstream client and not local")))
4958 }
4959 }
4960
4961 pub fn apply_code_action_kind(
4962 &mut self,
4963 buffers: HashSet<Entity<Buffer>>,
4964 kind: CodeActionKind,
4965 push_to_history: bool,
4966 cx: &mut Context<Self>,
4967 ) -> Task<anyhow::Result<ProjectTransaction>> {
4968 if self.as_local().is_some() {
4969 cx.spawn(async move |lsp_store, cx| {
4970 let buffers = buffers.into_iter().collect::<Vec<_>>();
4971 let result = LocalLspStore::execute_code_action_kind_locally(
4972 lsp_store.clone(),
4973 buffers,
4974 kind,
4975 push_to_history,
4976 cx,
4977 )
4978 .await;
4979 lsp_store.update(cx, |lsp_store, _| {
4980 lsp_store.update_last_formatting_failure(&result);
4981 })?;
4982 result
4983 })
4984 } else if let Some((client, project_id)) = self.upstream_client() {
4985 let buffer_store = self.buffer_store();
4986 cx.spawn(async move |lsp_store, cx| {
4987 let result = client
4988 .request(proto::ApplyCodeActionKind {
4989 project_id,
4990 kind: kind.as_str().to_owned(),
4991 buffer_ids: buffers
4992 .iter()
4993 .map(|buffer| {
4994 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4995 })
4996 .collect::<Result<_>>()?,
4997 })
4998 .await
4999 .and_then(|result| result.transaction.context("missing transaction"));
5000 lsp_store.update(cx, |lsp_store, _| {
5001 lsp_store.update_last_formatting_failure(&result);
5002 })?;
5003
5004 let transaction_response = result?;
5005 buffer_store
5006 .update(cx, |buffer_store, cx| {
5007 buffer_store.deserialize_project_transaction(
5008 transaction_response,
5009 push_to_history,
5010 cx,
5011 )
5012 })?
5013 .await
5014 })
5015 } else {
5016 Task::ready(Ok(ProjectTransaction::default()))
5017 }
5018 }
5019
5020 pub fn resolved_hint(
5021 &mut self,
5022 buffer_id: BufferId,
5023 id: InlayId,
5024 cx: &mut Context<Self>,
5025 ) -> Option<ResolvedHint> {
5026 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5027
5028 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5029 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5030 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5031 let (server_id, resolve_data) = match &hint.resolve_state {
5032 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5033 ResolveState::Resolving => {
5034 return Some(ResolvedHint::Resolving(
5035 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5036 ));
5037 }
5038 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5039 };
5040
5041 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5042 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5043 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5044 id,
5045 cx.spawn(async move |lsp_store, cx| {
5046 let resolved_hint = resolve_task.await;
5047 lsp_store
5048 .update(cx, |lsp_store, _| {
5049 if let Some(old_inlay_hint) = lsp_store
5050 .lsp_data
5051 .get_mut(&buffer_id)
5052 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5053 {
5054 match resolved_hint {
5055 Ok(resolved_hint) => {
5056 *old_inlay_hint = resolved_hint;
5057 }
5058 Err(e) => {
5059 old_inlay_hint.resolve_state =
5060 ResolveState::CanResolve(server_id, resolve_data);
5061 log::error!("Inlay hint resolve failed: {e:#}");
5062 }
5063 }
5064 }
5065 })
5066 .ok();
5067 })
5068 .shared(),
5069 );
5070 debug_assert!(
5071 previous_task.is_none(),
5072 "Did not change hint's resolve state after spawning its resolve"
5073 );
5074 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5075 None
5076 }
5077
5078 fn resolve_inlay_hint(
5079 &self,
5080 mut hint: InlayHint,
5081 buffer: Entity<Buffer>,
5082 server_id: LanguageServerId,
5083 cx: &mut Context<Self>,
5084 ) -> Task<anyhow::Result<InlayHint>> {
5085 if let Some((upstream_client, project_id)) = self.upstream_client() {
5086 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5087 {
5088 hint.resolve_state = ResolveState::Resolved;
5089 return Task::ready(Ok(hint));
5090 }
5091 let request = proto::ResolveInlayHint {
5092 project_id,
5093 buffer_id: buffer.read(cx).remote_id().into(),
5094 language_server_id: server_id.0 as u64,
5095 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5096 };
5097 cx.background_spawn(async move {
5098 let response = upstream_client
5099 .request(request)
5100 .await
5101 .context("inlay hints proto request")?;
5102 match response.hint {
5103 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5104 .context("inlay hints proto resolve response conversion"),
5105 None => Ok(hint),
5106 }
5107 })
5108 } else {
5109 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5110 self.language_server_for_local_buffer(buffer, server_id, cx)
5111 .map(|(_, server)| server.clone())
5112 }) else {
5113 return Task::ready(Ok(hint));
5114 };
5115 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5116 return Task::ready(Ok(hint));
5117 }
5118 let buffer_snapshot = buffer.read(cx).snapshot();
5119 cx.spawn(async move |_, cx| {
5120 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5121 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5122 );
5123 let resolved_hint = resolve_task
5124 .await
5125 .into_response()
5126 .context("inlay hint resolve LSP request")?;
5127 let resolved_hint = InlayHints::lsp_to_project_hint(
5128 resolved_hint,
5129 &buffer,
5130 server_id,
5131 ResolveState::Resolved,
5132 false,
5133 cx,
5134 )
5135 .await?;
5136 Ok(resolved_hint)
5137 })
5138 }
5139 }
5140
5141 pub fn resolve_color_presentation(
5142 &mut self,
5143 mut color: DocumentColor,
5144 buffer: Entity<Buffer>,
5145 server_id: LanguageServerId,
5146 cx: &mut Context<Self>,
5147 ) -> Task<Result<DocumentColor>> {
5148 if color.resolved {
5149 return Task::ready(Ok(color));
5150 }
5151
5152 if let Some((upstream_client, project_id)) = self.upstream_client() {
5153 let start = color.lsp_range.start;
5154 let end = color.lsp_range.end;
5155 let request = proto::GetColorPresentation {
5156 project_id,
5157 server_id: server_id.to_proto(),
5158 buffer_id: buffer.read(cx).remote_id().into(),
5159 color: Some(proto::ColorInformation {
5160 red: color.color.red,
5161 green: color.color.green,
5162 blue: color.color.blue,
5163 alpha: color.color.alpha,
5164 lsp_range_start: Some(proto::PointUtf16 {
5165 row: start.line,
5166 column: start.character,
5167 }),
5168 lsp_range_end: Some(proto::PointUtf16 {
5169 row: end.line,
5170 column: end.character,
5171 }),
5172 }),
5173 };
5174 cx.background_spawn(async move {
5175 let response = upstream_client
5176 .request(request)
5177 .await
5178 .context("color presentation proto request")?;
5179 color.resolved = true;
5180 color.color_presentations = response
5181 .presentations
5182 .into_iter()
5183 .map(|presentation| ColorPresentation {
5184 label: SharedString::from(presentation.label),
5185 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5186 additional_text_edits: presentation
5187 .additional_text_edits
5188 .into_iter()
5189 .filter_map(deserialize_lsp_edit)
5190 .collect(),
5191 })
5192 .collect();
5193 Ok(color)
5194 })
5195 } else {
5196 let path = match buffer
5197 .update(cx, |buffer, cx| {
5198 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5199 })
5200 .context("buffer with the missing path")
5201 {
5202 Ok(path) => path,
5203 Err(e) => return Task::ready(Err(e)),
5204 };
5205 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5206 self.language_server_for_local_buffer(buffer, server_id, cx)
5207 .map(|(_, server)| server.clone())
5208 }) else {
5209 return Task::ready(Ok(color));
5210 };
5211 cx.background_spawn(async move {
5212 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5213 lsp::ColorPresentationParams {
5214 text_document: make_text_document_identifier(&path)?,
5215 color: color.color,
5216 range: color.lsp_range,
5217 work_done_progress_params: Default::default(),
5218 partial_result_params: Default::default(),
5219 },
5220 );
5221 color.color_presentations = resolve_task
5222 .await
5223 .into_response()
5224 .context("color presentation resolve LSP request")?
5225 .into_iter()
5226 .map(|presentation| ColorPresentation {
5227 label: SharedString::from(presentation.label),
5228 text_edit: presentation.text_edit,
5229 additional_text_edits: presentation
5230 .additional_text_edits
5231 .unwrap_or_default(),
5232 })
5233 .collect();
5234 color.resolved = true;
5235 Ok(color)
5236 })
5237 }
5238 }
5239
5240 pub(crate) fn linked_edits(
5241 &mut self,
5242 buffer: &Entity<Buffer>,
5243 position: Anchor,
5244 cx: &mut Context<Self>,
5245 ) -> Task<Result<Vec<Range<Anchor>>>> {
5246 let snapshot = buffer.read(cx).snapshot();
5247 let scope = snapshot.language_scope_at(position);
5248 let Some(server_id) = self
5249 .as_local()
5250 .and_then(|local| {
5251 buffer.update(cx, |buffer, cx| {
5252 local
5253 .language_servers_for_buffer(buffer, cx)
5254 .filter(|(_, server)| {
5255 LinkedEditingRange::check_server_capabilities(server.capabilities())
5256 })
5257 .filter(|(adapter, _)| {
5258 scope
5259 .as_ref()
5260 .map(|scope| scope.language_allowed(&adapter.name))
5261 .unwrap_or(true)
5262 })
5263 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5264 .next()
5265 })
5266 })
5267 .or_else(|| {
5268 self.upstream_client()
5269 .is_some()
5270 .then_some(LanguageServerToQuery::FirstCapable)
5271 })
5272 .filter(|_| {
5273 maybe!({
5274 let language = buffer.read(cx).language_at(position)?;
5275 Some(
5276 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5277 .linked_edits,
5278 )
5279 }) == Some(true)
5280 })
5281 else {
5282 return Task::ready(Ok(Vec::new()));
5283 };
5284
5285 self.request_lsp(
5286 buffer.clone(),
5287 server_id,
5288 LinkedEditingRange { position },
5289 cx,
5290 )
5291 }
5292
5293 fn apply_on_type_formatting(
5294 &mut self,
5295 buffer: Entity<Buffer>,
5296 position: Anchor,
5297 trigger: String,
5298 cx: &mut Context<Self>,
5299 ) -> Task<Result<Option<Transaction>>> {
5300 if let Some((client, project_id)) = self.upstream_client() {
5301 if !self.check_if_capable_for_proto_request(
5302 &buffer,
5303 |capabilities| {
5304 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5305 },
5306 cx,
5307 ) {
5308 return Task::ready(Ok(None));
5309 }
5310 let request = proto::OnTypeFormatting {
5311 project_id,
5312 buffer_id: buffer.read(cx).remote_id().into(),
5313 position: Some(serialize_anchor(&position)),
5314 trigger,
5315 version: serialize_version(&buffer.read(cx).version()),
5316 };
5317 cx.background_spawn(async move {
5318 client
5319 .request(request)
5320 .await?
5321 .transaction
5322 .map(language::proto::deserialize_transaction)
5323 .transpose()
5324 })
5325 } else if let Some(local) = self.as_local_mut() {
5326 let buffer_id = buffer.read(cx).remote_id();
5327 local.buffers_being_formatted.insert(buffer_id);
5328 cx.spawn(async move |this, cx| {
5329 let _cleanup = defer({
5330 let this = this.clone();
5331 let mut cx = cx.clone();
5332 move || {
5333 this.update(&mut cx, |this, _| {
5334 if let Some(local) = this.as_local_mut() {
5335 local.buffers_being_formatted.remove(&buffer_id);
5336 }
5337 })
5338 .ok();
5339 }
5340 });
5341
5342 buffer
5343 .update(cx, |buffer, _| {
5344 buffer.wait_for_edits(Some(position.timestamp))
5345 })?
5346 .await?;
5347 this.update(cx, |this, cx| {
5348 let position = position.to_point_utf16(buffer.read(cx));
5349 this.on_type_format(buffer, position, trigger, false, cx)
5350 })?
5351 .await
5352 })
5353 } else {
5354 Task::ready(Err(anyhow!("No upstream client or local language server")))
5355 }
5356 }
5357
5358 pub fn on_type_format<T: ToPointUtf16>(
5359 &mut self,
5360 buffer: Entity<Buffer>,
5361 position: T,
5362 trigger: String,
5363 push_to_history: bool,
5364 cx: &mut Context<Self>,
5365 ) -> Task<Result<Option<Transaction>>> {
5366 let position = position.to_point_utf16(buffer.read(cx));
5367 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5368 }
5369
5370 fn on_type_format_impl(
5371 &mut self,
5372 buffer: Entity<Buffer>,
5373 position: PointUtf16,
5374 trigger: String,
5375 push_to_history: bool,
5376 cx: &mut Context<Self>,
5377 ) -> Task<Result<Option<Transaction>>> {
5378 let options = buffer.update(cx, |buffer, cx| {
5379 lsp_command::lsp_formatting_options(
5380 language_settings(
5381 buffer.language_at(position).map(|l| l.name()),
5382 buffer.file(),
5383 cx,
5384 )
5385 .as_ref(),
5386 )
5387 });
5388
5389 cx.spawn(async move |this, cx| {
5390 if let Some(waiter) =
5391 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5392 {
5393 waiter.await?;
5394 }
5395 cx.update(|cx| {
5396 this.update(cx, |this, cx| {
5397 this.request_lsp(
5398 buffer.clone(),
5399 LanguageServerToQuery::FirstCapable,
5400 OnTypeFormatting {
5401 position,
5402 trigger,
5403 options,
5404 push_to_history,
5405 },
5406 cx,
5407 )
5408 })
5409 })??
5410 .await
5411 })
5412 }
5413
5414 pub fn definitions(
5415 &mut self,
5416 buffer: &Entity<Buffer>,
5417 position: PointUtf16,
5418 cx: &mut Context<Self>,
5419 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5420 if let Some((upstream_client, project_id)) = self.upstream_client() {
5421 let request = GetDefinitions { position };
5422 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5423 return Task::ready(Ok(None));
5424 }
5425 let request_task = upstream_client.request_lsp(
5426 project_id,
5427 None,
5428 LSP_REQUEST_TIMEOUT,
5429 cx.background_executor().clone(),
5430 request.to_proto(project_id, buffer.read(cx)),
5431 );
5432 let buffer = buffer.clone();
5433 cx.spawn(async move |weak_lsp_store, cx| {
5434 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5435 return Ok(None);
5436 };
5437 let Some(responses) = request_task.await? else {
5438 return Ok(None);
5439 };
5440 let actions = join_all(responses.payload.into_iter().map(|response| {
5441 GetDefinitions { position }.response_from_proto(
5442 response.response,
5443 lsp_store.clone(),
5444 buffer.clone(),
5445 cx.clone(),
5446 )
5447 }))
5448 .await;
5449
5450 Ok(Some(
5451 actions
5452 .into_iter()
5453 .collect::<Result<Vec<Vec<_>>>>()?
5454 .into_iter()
5455 .flatten()
5456 .dedup()
5457 .collect(),
5458 ))
5459 })
5460 } else {
5461 let definitions_task = self.request_multiple_lsp_locally(
5462 buffer,
5463 Some(position),
5464 GetDefinitions { position },
5465 cx,
5466 );
5467 cx.background_spawn(async move {
5468 Ok(Some(
5469 definitions_task
5470 .await
5471 .into_iter()
5472 .flat_map(|(_, definitions)| definitions)
5473 .dedup()
5474 .collect(),
5475 ))
5476 })
5477 }
5478 }
5479
5480 pub fn declarations(
5481 &mut self,
5482 buffer: &Entity<Buffer>,
5483 position: PointUtf16,
5484 cx: &mut Context<Self>,
5485 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5486 if let Some((upstream_client, project_id)) = self.upstream_client() {
5487 let request = GetDeclarations { position };
5488 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5489 return Task::ready(Ok(None));
5490 }
5491 let request_task = upstream_client.request_lsp(
5492 project_id,
5493 None,
5494 LSP_REQUEST_TIMEOUT,
5495 cx.background_executor().clone(),
5496 request.to_proto(project_id, buffer.read(cx)),
5497 );
5498 let buffer = buffer.clone();
5499 cx.spawn(async move |weak_lsp_store, cx| {
5500 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5501 return Ok(None);
5502 };
5503 let Some(responses) = request_task.await? else {
5504 return Ok(None);
5505 };
5506 let actions = join_all(responses.payload.into_iter().map(|response| {
5507 GetDeclarations { position }.response_from_proto(
5508 response.response,
5509 lsp_store.clone(),
5510 buffer.clone(),
5511 cx.clone(),
5512 )
5513 }))
5514 .await;
5515
5516 Ok(Some(
5517 actions
5518 .into_iter()
5519 .collect::<Result<Vec<Vec<_>>>>()?
5520 .into_iter()
5521 .flatten()
5522 .dedup()
5523 .collect(),
5524 ))
5525 })
5526 } else {
5527 let declarations_task = self.request_multiple_lsp_locally(
5528 buffer,
5529 Some(position),
5530 GetDeclarations { position },
5531 cx,
5532 );
5533 cx.background_spawn(async move {
5534 Ok(Some(
5535 declarations_task
5536 .await
5537 .into_iter()
5538 .flat_map(|(_, declarations)| declarations)
5539 .dedup()
5540 .collect(),
5541 ))
5542 })
5543 }
5544 }
5545
5546 pub fn type_definitions(
5547 &mut self,
5548 buffer: &Entity<Buffer>,
5549 position: PointUtf16,
5550 cx: &mut Context<Self>,
5551 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5552 if let Some((upstream_client, project_id)) = self.upstream_client() {
5553 let request = GetTypeDefinitions { position };
5554 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5555 return Task::ready(Ok(None));
5556 }
5557 let request_task = upstream_client.request_lsp(
5558 project_id,
5559 None,
5560 LSP_REQUEST_TIMEOUT,
5561 cx.background_executor().clone(),
5562 request.to_proto(project_id, buffer.read(cx)),
5563 );
5564 let buffer = buffer.clone();
5565 cx.spawn(async move |weak_lsp_store, cx| {
5566 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5567 return Ok(None);
5568 };
5569 let Some(responses) = request_task.await? else {
5570 return Ok(None);
5571 };
5572 let actions = join_all(responses.payload.into_iter().map(|response| {
5573 GetTypeDefinitions { position }.response_from_proto(
5574 response.response,
5575 lsp_store.clone(),
5576 buffer.clone(),
5577 cx.clone(),
5578 )
5579 }))
5580 .await;
5581
5582 Ok(Some(
5583 actions
5584 .into_iter()
5585 .collect::<Result<Vec<Vec<_>>>>()?
5586 .into_iter()
5587 .flatten()
5588 .dedup()
5589 .collect(),
5590 ))
5591 })
5592 } else {
5593 let type_definitions_task = self.request_multiple_lsp_locally(
5594 buffer,
5595 Some(position),
5596 GetTypeDefinitions { position },
5597 cx,
5598 );
5599 cx.background_spawn(async move {
5600 Ok(Some(
5601 type_definitions_task
5602 .await
5603 .into_iter()
5604 .flat_map(|(_, type_definitions)| type_definitions)
5605 .dedup()
5606 .collect(),
5607 ))
5608 })
5609 }
5610 }
5611
5612 pub fn implementations(
5613 &mut self,
5614 buffer: &Entity<Buffer>,
5615 position: PointUtf16,
5616 cx: &mut Context<Self>,
5617 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5618 if let Some((upstream_client, project_id)) = self.upstream_client() {
5619 let request = GetImplementations { position };
5620 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5621 return Task::ready(Ok(None));
5622 }
5623 let request_task = upstream_client.request_lsp(
5624 project_id,
5625 None,
5626 LSP_REQUEST_TIMEOUT,
5627 cx.background_executor().clone(),
5628 request.to_proto(project_id, buffer.read(cx)),
5629 );
5630 let buffer = buffer.clone();
5631 cx.spawn(async move |weak_lsp_store, cx| {
5632 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5633 return Ok(None);
5634 };
5635 let Some(responses) = request_task.await? else {
5636 return Ok(None);
5637 };
5638 let actions = join_all(responses.payload.into_iter().map(|response| {
5639 GetImplementations { position }.response_from_proto(
5640 response.response,
5641 lsp_store.clone(),
5642 buffer.clone(),
5643 cx.clone(),
5644 )
5645 }))
5646 .await;
5647
5648 Ok(Some(
5649 actions
5650 .into_iter()
5651 .collect::<Result<Vec<Vec<_>>>>()?
5652 .into_iter()
5653 .flatten()
5654 .dedup()
5655 .collect(),
5656 ))
5657 })
5658 } else {
5659 let implementations_task = self.request_multiple_lsp_locally(
5660 buffer,
5661 Some(position),
5662 GetImplementations { position },
5663 cx,
5664 );
5665 cx.background_spawn(async move {
5666 Ok(Some(
5667 implementations_task
5668 .await
5669 .into_iter()
5670 .flat_map(|(_, implementations)| implementations)
5671 .dedup()
5672 .collect(),
5673 ))
5674 })
5675 }
5676 }
5677
5678 pub fn references(
5679 &mut self,
5680 buffer: &Entity<Buffer>,
5681 position: PointUtf16,
5682 cx: &mut Context<Self>,
5683 ) -> Task<Result<Option<Vec<Location>>>> {
5684 if let Some((upstream_client, project_id)) = self.upstream_client() {
5685 let request = GetReferences { position };
5686 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5687 return Task::ready(Ok(None));
5688 }
5689
5690 let request_task = upstream_client.request_lsp(
5691 project_id,
5692 None,
5693 LSP_REQUEST_TIMEOUT,
5694 cx.background_executor().clone(),
5695 request.to_proto(project_id, buffer.read(cx)),
5696 );
5697 let buffer = buffer.clone();
5698 cx.spawn(async move |weak_lsp_store, cx| {
5699 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5700 return Ok(None);
5701 };
5702 let Some(responses) = request_task.await? else {
5703 return Ok(None);
5704 };
5705
5706 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5707 GetReferences { position }.response_from_proto(
5708 lsp_response.response,
5709 lsp_store.clone(),
5710 buffer.clone(),
5711 cx.clone(),
5712 )
5713 }))
5714 .await
5715 .into_iter()
5716 .collect::<Result<Vec<Vec<_>>>>()?
5717 .into_iter()
5718 .flatten()
5719 .dedup()
5720 .collect();
5721 Ok(Some(locations))
5722 })
5723 } else {
5724 let references_task = self.request_multiple_lsp_locally(
5725 buffer,
5726 Some(position),
5727 GetReferences { position },
5728 cx,
5729 );
5730 cx.background_spawn(async move {
5731 Ok(Some(
5732 references_task
5733 .await
5734 .into_iter()
5735 .flat_map(|(_, references)| references)
5736 .dedup()
5737 .collect(),
5738 ))
5739 })
5740 }
5741 }
5742
5743 pub fn code_actions(
5744 &mut self,
5745 buffer: &Entity<Buffer>,
5746 range: Range<Anchor>,
5747 kinds: Option<Vec<CodeActionKind>>,
5748 cx: &mut Context<Self>,
5749 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5750 if let Some((upstream_client, project_id)) = self.upstream_client() {
5751 let request = GetCodeActions {
5752 range: range.clone(),
5753 kinds: kinds.clone(),
5754 };
5755 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5756 return Task::ready(Ok(None));
5757 }
5758 let request_task = upstream_client.request_lsp(
5759 project_id,
5760 None,
5761 LSP_REQUEST_TIMEOUT,
5762 cx.background_executor().clone(),
5763 request.to_proto(project_id, buffer.read(cx)),
5764 );
5765 let buffer = buffer.clone();
5766 cx.spawn(async move |weak_lsp_store, cx| {
5767 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5768 return Ok(None);
5769 };
5770 let Some(responses) = request_task.await? else {
5771 return Ok(None);
5772 };
5773 let actions = join_all(responses.payload.into_iter().map(|response| {
5774 GetCodeActions {
5775 range: range.clone(),
5776 kinds: kinds.clone(),
5777 }
5778 .response_from_proto(
5779 response.response,
5780 lsp_store.clone(),
5781 buffer.clone(),
5782 cx.clone(),
5783 )
5784 }))
5785 .await;
5786
5787 Ok(Some(
5788 actions
5789 .into_iter()
5790 .collect::<Result<Vec<Vec<_>>>>()?
5791 .into_iter()
5792 .flatten()
5793 .collect(),
5794 ))
5795 })
5796 } else {
5797 let all_actions_task = self.request_multiple_lsp_locally(
5798 buffer,
5799 Some(range.start),
5800 GetCodeActions { range, kinds },
5801 cx,
5802 );
5803 cx.background_spawn(async move {
5804 Ok(Some(
5805 all_actions_task
5806 .await
5807 .into_iter()
5808 .flat_map(|(_, actions)| actions)
5809 .collect(),
5810 ))
5811 })
5812 }
5813 }
5814
5815 pub fn code_lens_actions(
5816 &mut self,
5817 buffer: &Entity<Buffer>,
5818 cx: &mut Context<Self>,
5819 ) -> CodeLensTask {
5820 let version_queried_for = buffer.read(cx).version();
5821 let buffer_id = buffer.read(cx).remote_id();
5822 let existing_servers = self.as_local().map(|local| {
5823 local
5824 .buffers_opened_in_servers
5825 .get(&buffer_id)
5826 .cloned()
5827 .unwrap_or_default()
5828 });
5829
5830 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5831 if let Some(cached_lens) = &lsp_data.code_lens {
5832 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5833 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5834 existing_servers != cached_lens.lens.keys().copied().collect()
5835 });
5836 if !has_different_servers {
5837 return Task::ready(Ok(Some(
5838 cached_lens.lens.values().flatten().cloned().collect(),
5839 )))
5840 .shared();
5841 }
5842 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5843 if !version_queried_for.changed_since(updating_for) {
5844 return running_update.clone();
5845 }
5846 }
5847 }
5848 }
5849
5850 let lens_lsp_data = self
5851 .latest_lsp_data(buffer, cx)
5852 .code_lens
5853 .get_or_insert_default();
5854 let buffer = buffer.clone();
5855 let query_version_queried_for = version_queried_for.clone();
5856 let new_task = cx
5857 .spawn(async move |lsp_store, cx| {
5858 cx.background_executor()
5859 .timer(Duration::from_millis(30))
5860 .await;
5861 let fetched_lens = lsp_store
5862 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5863 .map_err(Arc::new)?
5864 .await
5865 .context("fetching code lens")
5866 .map_err(Arc::new);
5867 let fetched_lens = match fetched_lens {
5868 Ok(fetched_lens) => fetched_lens,
5869 Err(e) => {
5870 lsp_store
5871 .update(cx, |lsp_store, _| {
5872 if let Some(lens_lsp_data) = lsp_store
5873 .lsp_data
5874 .get_mut(&buffer_id)
5875 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5876 {
5877 lens_lsp_data.update = None;
5878 }
5879 })
5880 .ok();
5881 return Err(e);
5882 }
5883 };
5884
5885 lsp_store
5886 .update(cx, |lsp_store, _| {
5887 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5888 let code_lens = lsp_data.code_lens.as_mut()?;
5889 if let Some(fetched_lens) = fetched_lens {
5890 if lsp_data.buffer_version == query_version_queried_for {
5891 code_lens.lens.extend(fetched_lens);
5892 } else if !lsp_data
5893 .buffer_version
5894 .changed_since(&query_version_queried_for)
5895 {
5896 lsp_data.buffer_version = query_version_queried_for;
5897 code_lens.lens = fetched_lens;
5898 }
5899 }
5900 code_lens.update = None;
5901 Some(code_lens.lens.values().flatten().cloned().collect())
5902 })
5903 .map_err(Arc::new)
5904 })
5905 .shared();
5906 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5907 new_task
5908 }
5909
5910 fn fetch_code_lens(
5911 &mut self,
5912 buffer: &Entity<Buffer>,
5913 cx: &mut Context<Self>,
5914 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5915 if let Some((upstream_client, project_id)) = self.upstream_client() {
5916 let request = GetCodeLens;
5917 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5918 return Task::ready(Ok(None));
5919 }
5920 let request_task = upstream_client.request_lsp(
5921 project_id,
5922 None,
5923 LSP_REQUEST_TIMEOUT,
5924 cx.background_executor().clone(),
5925 request.to_proto(project_id, buffer.read(cx)),
5926 );
5927 let buffer = buffer.clone();
5928 cx.spawn(async move |weak_lsp_store, cx| {
5929 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5930 return Ok(None);
5931 };
5932 let Some(responses) = request_task.await? else {
5933 return Ok(None);
5934 };
5935
5936 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5937 let lsp_store = lsp_store.clone();
5938 let buffer = buffer.clone();
5939 let cx = cx.clone();
5940 async move {
5941 (
5942 LanguageServerId::from_proto(response.server_id),
5943 GetCodeLens
5944 .response_from_proto(response.response, lsp_store, buffer, cx)
5945 .await,
5946 )
5947 }
5948 }))
5949 .await;
5950
5951 let mut has_errors = false;
5952 let code_lens_actions = code_lens_actions
5953 .into_iter()
5954 .filter_map(|(server_id, code_lens)| match code_lens {
5955 Ok(code_lens) => Some((server_id, code_lens)),
5956 Err(e) => {
5957 has_errors = true;
5958 log::error!("{e:#}");
5959 None
5960 }
5961 })
5962 .collect::<HashMap<_, _>>();
5963 anyhow::ensure!(
5964 !has_errors || !code_lens_actions.is_empty(),
5965 "Failed to fetch code lens"
5966 );
5967 Ok(Some(code_lens_actions))
5968 })
5969 } else {
5970 let code_lens_actions_task =
5971 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5972 cx.background_spawn(async move {
5973 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5974 })
5975 }
5976 }
5977
5978 #[inline(never)]
5979 pub fn completions(
5980 &self,
5981 buffer: &Entity<Buffer>,
5982 position: PointUtf16,
5983 context: CompletionContext,
5984 cx: &mut Context<Self>,
5985 ) -> Task<Result<Vec<CompletionResponse>>> {
5986 let language_registry = self.languages.clone();
5987
5988 if let Some((upstream_client, project_id)) = self.upstream_client() {
5989 let snapshot = buffer.read(cx).snapshot();
5990 let offset = position.to_offset(&snapshot);
5991 let scope = snapshot.language_scope_at(offset);
5992 let capable_lsps = self.all_capable_for_proto_request(
5993 buffer,
5994 |server_name, capabilities| {
5995 capabilities.completion_provider.is_some()
5996 && scope
5997 .as_ref()
5998 .map(|scope| scope.language_allowed(server_name))
5999 .unwrap_or(true)
6000 },
6001 cx,
6002 );
6003 if capable_lsps.is_empty() {
6004 return Task::ready(Ok(Vec::new()));
6005 }
6006
6007 let language = buffer.read(cx).language().cloned();
6008
6009 // In the future, we should provide project guests with the names of LSP adapters,
6010 // so that they can use the correct LSP adapter when computing labels. For now,
6011 // guests just use the first LSP adapter associated with the buffer's language.
6012 let lsp_adapter = language.as_ref().and_then(|language| {
6013 language_registry
6014 .lsp_adapters(&language.name())
6015 .first()
6016 .cloned()
6017 });
6018
6019 let buffer = buffer.clone();
6020
6021 cx.spawn(async move |this, cx| {
6022 let requests = join_all(
6023 capable_lsps
6024 .into_iter()
6025 .map(|id| {
6026 let request = GetCompletions {
6027 position,
6028 context: context.clone(),
6029 server_id: Some(id),
6030 };
6031 let buffer = buffer.clone();
6032 let language = language.clone();
6033 let lsp_adapter = lsp_adapter.clone();
6034 let upstream_client = upstream_client.clone();
6035 let response = this
6036 .update(cx, |this, cx| {
6037 this.send_lsp_proto_request(
6038 buffer,
6039 upstream_client,
6040 project_id,
6041 request,
6042 cx,
6043 )
6044 })
6045 .log_err();
6046 async move {
6047 let response = response?.await.log_err()?;
6048
6049 let completions = populate_labels_for_completions(
6050 response.completions,
6051 language,
6052 lsp_adapter,
6053 )
6054 .await;
6055
6056 Some(CompletionResponse {
6057 completions,
6058 display_options: CompletionDisplayOptions::default(),
6059 is_incomplete: response.is_incomplete,
6060 })
6061 }
6062 })
6063 .collect::<Vec<_>>(),
6064 );
6065 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6066 })
6067 } else if let Some(local) = self.as_local() {
6068 let snapshot = buffer.read(cx).snapshot();
6069 let offset = position.to_offset(&snapshot);
6070 let scope = snapshot.language_scope_at(offset);
6071 let language = snapshot.language().cloned();
6072 let completion_settings = language_settings(
6073 language.as_ref().map(|language| language.name()),
6074 buffer.read(cx).file(),
6075 cx,
6076 )
6077 .completions
6078 .clone();
6079 if !completion_settings.lsp {
6080 return Task::ready(Ok(Vec::new()));
6081 }
6082
6083 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6084 local
6085 .language_servers_for_buffer(buffer, cx)
6086 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6087 .filter(|(adapter, _)| {
6088 scope
6089 .as_ref()
6090 .map(|scope| scope.language_allowed(&adapter.name))
6091 .unwrap_or(true)
6092 })
6093 .map(|(_, server)| server.server_id())
6094 .collect()
6095 });
6096
6097 let buffer = buffer.clone();
6098 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6099 let lsp_timeout = if lsp_timeout > 0 {
6100 Some(Duration::from_millis(lsp_timeout))
6101 } else {
6102 None
6103 };
6104 cx.spawn(async move |this, cx| {
6105 let mut tasks = Vec::with_capacity(server_ids.len());
6106 this.update(cx, |lsp_store, cx| {
6107 for server_id in server_ids {
6108 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6109 let lsp_timeout = lsp_timeout
6110 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6111 let mut timeout = cx.background_spawn(async move {
6112 match lsp_timeout {
6113 Some(lsp_timeout) => {
6114 lsp_timeout.await;
6115 true
6116 },
6117 None => false,
6118 }
6119 }).fuse();
6120 let mut lsp_request = lsp_store.request_lsp(
6121 buffer.clone(),
6122 LanguageServerToQuery::Other(server_id),
6123 GetCompletions {
6124 position,
6125 context: context.clone(),
6126 server_id: Some(server_id),
6127 },
6128 cx,
6129 ).fuse();
6130 let new_task = cx.background_spawn(async move {
6131 select_biased! {
6132 response = lsp_request => anyhow::Ok(Some(response?)),
6133 timeout_happened = timeout => {
6134 if timeout_happened {
6135 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6136 Ok(None)
6137 } else {
6138 let completions = lsp_request.await?;
6139 Ok(Some(completions))
6140 }
6141 },
6142 }
6143 });
6144 tasks.push((lsp_adapter, new_task));
6145 }
6146 })?;
6147
6148 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6149 let completion_response = task.await.ok()??;
6150 let completions = populate_labels_for_completions(
6151 completion_response.completions,
6152 language.clone(),
6153 lsp_adapter,
6154 )
6155 .await;
6156 Some(CompletionResponse {
6157 completions,
6158 display_options: CompletionDisplayOptions::default(),
6159 is_incomplete: completion_response.is_incomplete,
6160 })
6161 });
6162
6163 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6164
6165 Ok(responses.into_iter().flatten().collect())
6166 })
6167 } else {
6168 Task::ready(Err(anyhow!("No upstream client or local language server")))
6169 }
6170 }
6171
6172 pub fn resolve_completions(
6173 &self,
6174 buffer: Entity<Buffer>,
6175 completion_indices: Vec<usize>,
6176 completions: Rc<RefCell<Box<[Completion]>>>,
6177 cx: &mut Context<Self>,
6178 ) -> Task<Result<bool>> {
6179 let client = self.upstream_client();
6180 let buffer_id = buffer.read(cx).remote_id();
6181 let buffer_snapshot = buffer.read(cx).snapshot();
6182
6183 if !self.check_if_capable_for_proto_request(
6184 &buffer,
6185 GetCompletions::can_resolve_completions,
6186 cx,
6187 ) {
6188 return Task::ready(Ok(false));
6189 }
6190 cx.spawn(async move |lsp_store, cx| {
6191 let mut did_resolve = false;
6192 if let Some((client, project_id)) = client {
6193 for completion_index in completion_indices {
6194 let server_id = {
6195 let completion = &completions.borrow()[completion_index];
6196 completion.source.server_id()
6197 };
6198 if let Some(server_id) = server_id {
6199 if Self::resolve_completion_remote(
6200 project_id,
6201 server_id,
6202 buffer_id,
6203 completions.clone(),
6204 completion_index,
6205 client.clone(),
6206 )
6207 .await
6208 .log_err()
6209 .is_some()
6210 {
6211 did_resolve = true;
6212 }
6213 } else {
6214 resolve_word_completion(
6215 &buffer_snapshot,
6216 &mut completions.borrow_mut()[completion_index],
6217 );
6218 }
6219 }
6220 } else {
6221 for completion_index in completion_indices {
6222 let server_id = {
6223 let completion = &completions.borrow()[completion_index];
6224 completion.source.server_id()
6225 };
6226 if let Some(server_id) = server_id {
6227 let server_and_adapter = lsp_store
6228 .read_with(cx, |lsp_store, _| {
6229 let server = lsp_store.language_server_for_id(server_id)?;
6230 let adapter =
6231 lsp_store.language_server_adapter_for_id(server.server_id())?;
6232 Some((server, adapter))
6233 })
6234 .ok()
6235 .flatten();
6236 let Some((server, adapter)) = server_and_adapter else {
6237 continue;
6238 };
6239
6240 let resolved = Self::resolve_completion_local(
6241 server,
6242 completions.clone(),
6243 completion_index,
6244 )
6245 .await
6246 .log_err()
6247 .is_some();
6248 if resolved {
6249 Self::regenerate_completion_labels(
6250 adapter,
6251 &buffer_snapshot,
6252 completions.clone(),
6253 completion_index,
6254 )
6255 .await
6256 .log_err();
6257 did_resolve = true;
6258 }
6259 } else {
6260 resolve_word_completion(
6261 &buffer_snapshot,
6262 &mut completions.borrow_mut()[completion_index],
6263 );
6264 }
6265 }
6266 }
6267
6268 Ok(did_resolve)
6269 })
6270 }
6271
6272 async fn resolve_completion_local(
6273 server: Arc<lsp::LanguageServer>,
6274 completions: Rc<RefCell<Box<[Completion]>>>,
6275 completion_index: usize,
6276 ) -> Result<()> {
6277 let server_id = server.server_id();
6278 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6279 return Ok(());
6280 }
6281
6282 let request = {
6283 let completion = &completions.borrow()[completion_index];
6284 match &completion.source {
6285 CompletionSource::Lsp {
6286 lsp_completion,
6287 resolved,
6288 server_id: completion_server_id,
6289 ..
6290 } => {
6291 if *resolved {
6292 return Ok(());
6293 }
6294 anyhow::ensure!(
6295 server_id == *completion_server_id,
6296 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6297 );
6298 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6299 }
6300 CompletionSource::BufferWord { .. }
6301 | CompletionSource::Dap { .. }
6302 | CompletionSource::Custom => {
6303 return Ok(());
6304 }
6305 }
6306 };
6307 let resolved_completion = request
6308 .await
6309 .into_response()
6310 .context("resolve completion")?;
6311
6312 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6313 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6314
6315 let mut completions = completions.borrow_mut();
6316 let completion = &mut completions[completion_index];
6317 if let CompletionSource::Lsp {
6318 lsp_completion,
6319 resolved,
6320 server_id: completion_server_id,
6321 ..
6322 } = &mut completion.source
6323 {
6324 if *resolved {
6325 return Ok(());
6326 }
6327 anyhow::ensure!(
6328 server_id == *completion_server_id,
6329 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6330 );
6331 *lsp_completion = Box::new(resolved_completion);
6332 *resolved = true;
6333 }
6334 Ok(())
6335 }
6336
6337 async fn regenerate_completion_labels(
6338 adapter: Arc<CachedLspAdapter>,
6339 snapshot: &BufferSnapshot,
6340 completions: Rc<RefCell<Box<[Completion]>>>,
6341 completion_index: usize,
6342 ) -> Result<()> {
6343 let completion_item = completions.borrow()[completion_index]
6344 .source
6345 .lsp_completion(true)
6346 .map(Cow::into_owned);
6347 if let Some(lsp_documentation) = completion_item
6348 .as_ref()
6349 .and_then(|completion_item| completion_item.documentation.clone())
6350 {
6351 let mut completions = completions.borrow_mut();
6352 let completion = &mut completions[completion_index];
6353 completion.documentation = Some(lsp_documentation.into());
6354 } else {
6355 let mut completions = completions.borrow_mut();
6356 let completion = &mut completions[completion_index];
6357 completion.documentation = Some(CompletionDocumentation::Undocumented);
6358 }
6359
6360 let mut new_label = match completion_item {
6361 Some(completion_item) => {
6362 // 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
6363 // So we have to update the label here anyway...
6364 let language = snapshot.language();
6365 match language {
6366 Some(language) => {
6367 adapter
6368 .labels_for_completions(
6369 std::slice::from_ref(&completion_item),
6370 language,
6371 )
6372 .await?
6373 }
6374 None => Vec::new(),
6375 }
6376 .pop()
6377 .flatten()
6378 .unwrap_or_else(|| {
6379 CodeLabel::fallback_for_completion(
6380 &completion_item,
6381 language.map(|language| language.as_ref()),
6382 )
6383 })
6384 }
6385 None => CodeLabel::plain(
6386 completions.borrow()[completion_index].new_text.clone(),
6387 None,
6388 ),
6389 };
6390 ensure_uniform_list_compatible_label(&mut new_label);
6391
6392 let mut completions = completions.borrow_mut();
6393 let completion = &mut completions[completion_index];
6394 if completion.label.filter_text() == new_label.filter_text() {
6395 completion.label = new_label;
6396 } else {
6397 log::error!(
6398 "Resolved completion changed display label from {} to {}. \
6399 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6400 completion.label.text(),
6401 new_label.text(),
6402 completion.label.filter_text(),
6403 new_label.filter_text()
6404 );
6405 }
6406
6407 Ok(())
6408 }
6409
6410 async fn resolve_completion_remote(
6411 project_id: u64,
6412 server_id: LanguageServerId,
6413 buffer_id: BufferId,
6414 completions: Rc<RefCell<Box<[Completion]>>>,
6415 completion_index: usize,
6416 client: AnyProtoClient,
6417 ) -> Result<()> {
6418 let lsp_completion = {
6419 let completion = &completions.borrow()[completion_index];
6420 match &completion.source {
6421 CompletionSource::Lsp {
6422 lsp_completion,
6423 resolved,
6424 server_id: completion_server_id,
6425 ..
6426 } => {
6427 anyhow::ensure!(
6428 server_id == *completion_server_id,
6429 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6430 );
6431 if *resolved {
6432 return Ok(());
6433 }
6434 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6435 }
6436 CompletionSource::Custom
6437 | CompletionSource::Dap { .. }
6438 | CompletionSource::BufferWord { .. } => {
6439 return Ok(());
6440 }
6441 }
6442 };
6443 let request = proto::ResolveCompletionDocumentation {
6444 project_id,
6445 language_server_id: server_id.0 as u64,
6446 lsp_completion,
6447 buffer_id: buffer_id.into(),
6448 };
6449
6450 let response = client
6451 .request(request)
6452 .await
6453 .context("completion documentation resolve proto request")?;
6454 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6455
6456 let documentation = if response.documentation.is_empty() {
6457 CompletionDocumentation::Undocumented
6458 } else if response.documentation_is_markdown {
6459 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6460 } else if response.documentation.lines().count() <= 1 {
6461 CompletionDocumentation::SingleLine(response.documentation.into())
6462 } else {
6463 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6464 };
6465
6466 let mut completions = completions.borrow_mut();
6467 let completion = &mut completions[completion_index];
6468 completion.documentation = Some(documentation);
6469 if let CompletionSource::Lsp {
6470 insert_range,
6471 lsp_completion,
6472 resolved,
6473 server_id: completion_server_id,
6474 lsp_defaults: _,
6475 } = &mut completion.source
6476 {
6477 let completion_insert_range = response
6478 .old_insert_start
6479 .and_then(deserialize_anchor)
6480 .zip(response.old_insert_end.and_then(deserialize_anchor));
6481 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6482
6483 if *resolved {
6484 return Ok(());
6485 }
6486 anyhow::ensure!(
6487 server_id == *completion_server_id,
6488 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6489 );
6490 *lsp_completion = Box::new(resolved_lsp_completion);
6491 *resolved = true;
6492 }
6493
6494 let replace_range = response
6495 .old_replace_start
6496 .and_then(deserialize_anchor)
6497 .zip(response.old_replace_end.and_then(deserialize_anchor));
6498 if let Some((old_replace_start, old_replace_end)) = replace_range
6499 && !response.new_text.is_empty()
6500 {
6501 completion.new_text = response.new_text;
6502 completion.replace_range = old_replace_start..old_replace_end;
6503 }
6504
6505 Ok(())
6506 }
6507
6508 pub fn apply_additional_edits_for_completion(
6509 &self,
6510 buffer_handle: Entity<Buffer>,
6511 completions: Rc<RefCell<Box<[Completion]>>>,
6512 completion_index: usize,
6513 push_to_history: bool,
6514 cx: &mut Context<Self>,
6515 ) -> Task<Result<Option<Transaction>>> {
6516 if let Some((client, project_id)) = self.upstream_client() {
6517 let buffer = buffer_handle.read(cx);
6518 let buffer_id = buffer.remote_id();
6519 cx.spawn(async move |_, cx| {
6520 let request = {
6521 let completion = completions.borrow()[completion_index].clone();
6522 proto::ApplyCompletionAdditionalEdits {
6523 project_id,
6524 buffer_id: buffer_id.into(),
6525 completion: Some(Self::serialize_completion(&CoreCompletion {
6526 replace_range: completion.replace_range,
6527 new_text: completion.new_text,
6528 source: completion.source,
6529 })),
6530 }
6531 };
6532
6533 if let Some(transaction) = client.request(request).await?.transaction {
6534 let transaction = language::proto::deserialize_transaction(transaction)?;
6535 buffer_handle
6536 .update(cx, |buffer, _| {
6537 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6538 })?
6539 .await?;
6540 if push_to_history {
6541 buffer_handle.update(cx, |buffer, _| {
6542 buffer.push_transaction(transaction.clone(), Instant::now());
6543 buffer.finalize_last_transaction();
6544 })?;
6545 }
6546 Ok(Some(transaction))
6547 } else {
6548 Ok(None)
6549 }
6550 })
6551 } else {
6552 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6553 let completion = &completions.borrow()[completion_index];
6554 let server_id = completion.source.server_id()?;
6555 Some(
6556 self.language_server_for_local_buffer(buffer, server_id, cx)?
6557 .1
6558 .clone(),
6559 )
6560 }) else {
6561 return Task::ready(Ok(None));
6562 };
6563
6564 cx.spawn(async move |this, cx| {
6565 Self::resolve_completion_local(
6566 server.clone(),
6567 completions.clone(),
6568 completion_index,
6569 )
6570 .await
6571 .context("resolving completion")?;
6572 let completion = completions.borrow()[completion_index].clone();
6573 let additional_text_edits = completion
6574 .source
6575 .lsp_completion(true)
6576 .as_ref()
6577 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6578 if let Some(edits) = additional_text_edits {
6579 let edits = this
6580 .update(cx, |this, cx| {
6581 this.as_local_mut().unwrap().edits_from_lsp(
6582 &buffer_handle,
6583 edits,
6584 server.server_id(),
6585 None,
6586 cx,
6587 )
6588 })?
6589 .await?;
6590
6591 buffer_handle.update(cx, |buffer, cx| {
6592 buffer.finalize_last_transaction();
6593 buffer.start_transaction();
6594
6595 for (range, text) in edits {
6596 let primary = &completion.replace_range;
6597
6598 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6599 // and the primary completion is just an insertion (empty range), then this is likely
6600 // an auto-import scenario and should not be considered overlapping
6601 // https://github.com/zed-industries/zed/issues/26136
6602 let is_file_start_auto_import = {
6603 let snapshot = buffer.snapshot();
6604 let primary_start_point = primary.start.to_point(&snapshot);
6605 let range_start_point = range.start.to_point(&snapshot);
6606
6607 let result = primary_start_point.row == 0
6608 && primary_start_point.column == 0
6609 && range_start_point.row == 0
6610 && range_start_point.column == 0;
6611
6612 result
6613 };
6614
6615 let has_overlap = if is_file_start_auto_import {
6616 false
6617 } else {
6618 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6619 && primary.end.cmp(&range.start, buffer).is_ge();
6620 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6621 && range.end.cmp(&primary.end, buffer).is_ge();
6622 let result = start_within || end_within;
6623 result
6624 };
6625
6626 //Skip additional edits which overlap with the primary completion edit
6627 //https://github.com/zed-industries/zed/pull/1871
6628 if !has_overlap {
6629 buffer.edit([(range, text)], None, cx);
6630 }
6631 }
6632
6633 let transaction = if buffer.end_transaction(cx).is_some() {
6634 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6635 if !push_to_history {
6636 buffer.forget_transaction(transaction.id);
6637 }
6638 Some(transaction)
6639 } else {
6640 None
6641 };
6642 Ok(transaction)
6643 })?
6644 } else {
6645 Ok(None)
6646 }
6647 })
6648 }
6649 }
6650
6651 pub fn pull_diagnostics(
6652 &mut self,
6653 buffer: Entity<Buffer>,
6654 cx: &mut Context<Self>,
6655 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6656 let buffer_id = buffer.read(cx).remote_id();
6657
6658 if let Some((client, upstream_project_id)) = self.upstream_client() {
6659 let mut suitable_capabilities = None;
6660 // Are we capable for proto request?
6661 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6662 &buffer,
6663 |capabilities| {
6664 if let Some(caps) = &capabilities.diagnostic_provider {
6665 suitable_capabilities = Some(caps.clone());
6666 true
6667 } else {
6668 false
6669 }
6670 },
6671 cx,
6672 );
6673 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6674 let Some(dynamic_caps) = suitable_capabilities else {
6675 return Task::ready(Ok(None));
6676 };
6677 assert!(any_server_has_diagnostics_provider);
6678
6679 let request = GetDocumentDiagnostics {
6680 previous_result_id: None,
6681 dynamic_caps,
6682 };
6683 let request_task = client.request_lsp(
6684 upstream_project_id,
6685 None,
6686 LSP_REQUEST_TIMEOUT,
6687 cx.background_executor().clone(),
6688 request.to_proto(upstream_project_id, buffer.read(cx)),
6689 );
6690 cx.background_spawn(async move {
6691 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6692 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6693 // Do not attempt to further process the dummy responses here.
6694 let _response = request_task.await?;
6695 Ok(None)
6696 })
6697 } else {
6698 let servers = buffer.update(cx, |buffer, cx| {
6699 self.language_servers_for_local_buffer(buffer, cx)
6700 .map(|(_, server)| server.clone())
6701 .collect::<Vec<_>>()
6702 });
6703
6704 let pull_diagnostics = servers
6705 .into_iter()
6706 .flat_map(|server| {
6707 let result = maybe!({
6708 let local = self.as_local()?;
6709 let server_id = server.server_id();
6710 let providers_with_identifiers = local
6711 .language_server_dynamic_registrations
6712 .get(&server_id)
6713 .into_iter()
6714 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6715 .collect::<Vec<_>>();
6716 Some(
6717 providers_with_identifiers
6718 .into_iter()
6719 .map(|dynamic_caps| {
6720 let result_id = self.result_id(server_id, buffer_id, cx);
6721 self.request_lsp(
6722 buffer.clone(),
6723 LanguageServerToQuery::Other(server_id),
6724 GetDocumentDiagnostics {
6725 previous_result_id: result_id,
6726 dynamic_caps,
6727 },
6728 cx,
6729 )
6730 })
6731 .collect::<Vec<_>>(),
6732 )
6733 });
6734
6735 result.unwrap_or_default()
6736 })
6737 .collect::<Vec<_>>();
6738
6739 cx.background_spawn(async move {
6740 let mut responses = Vec::new();
6741 for diagnostics in join_all(pull_diagnostics).await {
6742 responses.extend(diagnostics?);
6743 }
6744 Ok(Some(responses))
6745 })
6746 }
6747 }
6748
6749 pub fn applicable_inlay_chunks(
6750 &mut self,
6751 buffer: &Entity<Buffer>,
6752 ranges: &[Range<text::Anchor>],
6753 cx: &mut Context<Self>,
6754 ) -> Vec<Range<BufferRow>> {
6755 self.latest_lsp_data(buffer, cx)
6756 .inlay_hints
6757 .applicable_chunks(ranges)
6758 .map(|chunk| chunk.row_range())
6759 .collect()
6760 }
6761
6762 pub fn invalidate_inlay_hints<'a>(
6763 &'a mut self,
6764 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6765 ) {
6766 for buffer_id in for_buffers {
6767 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6768 lsp_data.inlay_hints.clear();
6769 }
6770 }
6771 }
6772
6773 pub fn inlay_hints(
6774 &mut self,
6775 invalidate: InvalidationStrategy,
6776 buffer: Entity<Buffer>,
6777 ranges: Vec<Range<text::Anchor>>,
6778 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6779 cx: &mut Context<Self>,
6780 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6781 let next_hint_id = self.next_hint_id.clone();
6782 let lsp_data = self.latest_lsp_data(&buffer, cx);
6783 let query_version = lsp_data.buffer_version.clone();
6784 let mut lsp_refresh_requested = false;
6785 let for_server = if let InvalidationStrategy::RefreshRequested {
6786 server_id,
6787 request_id,
6788 } = invalidate
6789 {
6790 let invalidated = lsp_data
6791 .inlay_hints
6792 .invalidate_for_server_refresh(server_id, request_id);
6793 lsp_refresh_requested = invalidated;
6794 Some(server_id)
6795 } else {
6796 None
6797 };
6798 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6799 let known_chunks = known_chunks
6800 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6801 .map(|(_, known_chunks)| known_chunks)
6802 .unwrap_or_default();
6803
6804 let mut hint_fetch_tasks = Vec::new();
6805 let mut cached_inlay_hints = None;
6806 let mut ranges_to_query = None;
6807 let applicable_chunks = existing_inlay_hints
6808 .applicable_chunks(ranges.as_slice())
6809 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6810 .collect::<Vec<_>>();
6811 if applicable_chunks.is_empty() {
6812 return HashMap::default();
6813 }
6814
6815 for row_chunk in applicable_chunks {
6816 match (
6817 existing_inlay_hints
6818 .cached_hints(&row_chunk)
6819 .filter(|_| !lsp_refresh_requested)
6820 .cloned(),
6821 existing_inlay_hints
6822 .fetched_hints(&row_chunk)
6823 .as_ref()
6824 .filter(|_| !lsp_refresh_requested)
6825 .cloned(),
6826 ) {
6827 (None, None) => {
6828 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6829 continue;
6830 };
6831 ranges_to_query
6832 .get_or_insert_with(Vec::new)
6833 .push((row_chunk, chunk_range));
6834 }
6835 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6836 (Some(cached_hints), None) => {
6837 for (server_id, cached_hints) in cached_hints {
6838 if for_server.is_none_or(|for_server| for_server == server_id) {
6839 cached_inlay_hints
6840 .get_or_insert_with(HashMap::default)
6841 .entry(row_chunk.row_range())
6842 .or_insert_with(HashMap::default)
6843 .entry(server_id)
6844 .or_insert_with(Vec::new)
6845 .extend(cached_hints);
6846 }
6847 }
6848 }
6849 (Some(cached_hints), Some(fetched_hints)) => {
6850 hint_fetch_tasks.push((row_chunk, fetched_hints));
6851 for (server_id, cached_hints) in cached_hints {
6852 if for_server.is_none_or(|for_server| for_server == server_id) {
6853 cached_inlay_hints
6854 .get_or_insert_with(HashMap::default)
6855 .entry(row_chunk.row_range())
6856 .or_insert_with(HashMap::default)
6857 .entry(server_id)
6858 .or_insert_with(Vec::new)
6859 .extend(cached_hints);
6860 }
6861 }
6862 }
6863 }
6864 }
6865
6866 if hint_fetch_tasks.is_empty()
6867 && ranges_to_query
6868 .as_ref()
6869 .is_none_or(|ranges| ranges.is_empty())
6870 && let Some(cached_inlay_hints) = cached_inlay_hints
6871 {
6872 cached_inlay_hints
6873 .into_iter()
6874 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6875 .collect()
6876 } else {
6877 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6878 let next_hint_id = next_hint_id.clone();
6879 let buffer = buffer.clone();
6880 let query_version = query_version.clone();
6881 let new_inlay_hints = cx
6882 .spawn(async move |lsp_store, cx| {
6883 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6884 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6885 })?;
6886 new_fetch_task
6887 .await
6888 .and_then(|new_hints_by_server| {
6889 lsp_store.update(cx, |lsp_store, cx| {
6890 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6891 let update_cache = lsp_data.buffer_version == query_version;
6892 if new_hints_by_server.is_empty() {
6893 if update_cache {
6894 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6895 }
6896 HashMap::default()
6897 } else {
6898 new_hints_by_server
6899 .into_iter()
6900 .map(|(server_id, new_hints)| {
6901 let new_hints = new_hints
6902 .into_iter()
6903 .map(|new_hint| {
6904 (
6905 InlayId::Hint(next_hint_id.fetch_add(
6906 1,
6907 atomic::Ordering::AcqRel,
6908 )),
6909 new_hint,
6910 )
6911 })
6912 .collect::<Vec<_>>();
6913 if update_cache {
6914 lsp_data.inlay_hints.insert_new_hints(
6915 chunk,
6916 server_id,
6917 new_hints.clone(),
6918 );
6919 }
6920 (server_id, new_hints)
6921 })
6922 .collect()
6923 }
6924 })
6925 })
6926 .map_err(Arc::new)
6927 })
6928 .shared();
6929
6930 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6931 *fetch_task = Some(new_inlay_hints.clone());
6932 hint_fetch_tasks.push((chunk, new_inlay_hints));
6933 }
6934
6935 cached_inlay_hints
6936 .unwrap_or_default()
6937 .into_iter()
6938 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6939 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6940 (
6941 chunk.row_range(),
6942 cx.spawn(async move |_, _| {
6943 hints_fetch.await.map_err(|e| {
6944 if e.error_code() != ErrorCode::Internal {
6945 anyhow!(e.error_code())
6946 } else {
6947 anyhow!("{e:#}")
6948 }
6949 })
6950 }),
6951 )
6952 }))
6953 .collect()
6954 }
6955 }
6956
6957 fn fetch_inlay_hints(
6958 &mut self,
6959 for_server: Option<LanguageServerId>,
6960 buffer: &Entity<Buffer>,
6961 range: Range<Anchor>,
6962 cx: &mut Context<Self>,
6963 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6964 let request = InlayHints {
6965 range: range.clone(),
6966 };
6967 if let Some((upstream_client, project_id)) = self.upstream_client() {
6968 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6969 return Task::ready(Ok(HashMap::default()));
6970 }
6971 let request_task = upstream_client.request_lsp(
6972 project_id,
6973 for_server.map(|id| id.to_proto()),
6974 LSP_REQUEST_TIMEOUT,
6975 cx.background_executor().clone(),
6976 request.to_proto(project_id, buffer.read(cx)),
6977 );
6978 let buffer = buffer.clone();
6979 cx.spawn(async move |weak_lsp_store, cx| {
6980 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6981 return Ok(HashMap::default());
6982 };
6983 let Some(responses) = request_task.await? else {
6984 return Ok(HashMap::default());
6985 };
6986
6987 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6988 let lsp_store = lsp_store.clone();
6989 let buffer = buffer.clone();
6990 let cx = cx.clone();
6991 let request = request.clone();
6992 async move {
6993 (
6994 LanguageServerId::from_proto(response.server_id),
6995 request
6996 .response_from_proto(response.response, lsp_store, buffer, cx)
6997 .await,
6998 )
6999 }
7000 }))
7001 .await;
7002
7003 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7004 let mut has_errors = false;
7005 let inlay_hints = inlay_hints
7006 .into_iter()
7007 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7008 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7009 Err(e) => {
7010 has_errors = true;
7011 log::error!("{e:#}");
7012 None
7013 }
7014 })
7015 .map(|(server_id, mut new_hints)| {
7016 new_hints.retain(|hint| {
7017 hint.position.is_valid(&buffer_snapshot)
7018 && range.start.is_valid(&buffer_snapshot)
7019 && range.end.is_valid(&buffer_snapshot)
7020 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7021 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7022 });
7023 (server_id, new_hints)
7024 })
7025 .collect::<HashMap<_, _>>();
7026 anyhow::ensure!(
7027 !has_errors || !inlay_hints.is_empty(),
7028 "Failed to fetch inlay hints"
7029 );
7030 Ok(inlay_hints)
7031 })
7032 } else {
7033 let inlay_hints_task = match for_server {
7034 Some(server_id) => {
7035 let server_task = self.request_lsp(
7036 buffer.clone(),
7037 LanguageServerToQuery::Other(server_id),
7038 request,
7039 cx,
7040 );
7041 cx.background_spawn(async move {
7042 let mut responses = Vec::new();
7043 match server_task.await {
7044 Ok(response) => responses.push((server_id, response)),
7045 // rust-analyzer likes to error with this when its still loading up
7046 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7047 Err(e) => log::error!(
7048 "Error handling response for inlay hints request: {e:#}"
7049 ),
7050 }
7051 responses
7052 })
7053 }
7054 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7055 };
7056 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7057 cx.background_spawn(async move {
7058 Ok(inlay_hints_task
7059 .await
7060 .into_iter()
7061 .map(|(server_id, mut new_hints)| {
7062 new_hints.retain(|hint| {
7063 hint.position.is_valid(&buffer_snapshot)
7064 && range.start.is_valid(&buffer_snapshot)
7065 && range.end.is_valid(&buffer_snapshot)
7066 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7067 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7068 });
7069 (server_id, new_hints)
7070 })
7071 .collect())
7072 })
7073 }
7074 }
7075
7076 pub fn pull_diagnostics_for_buffer(
7077 &mut self,
7078 buffer: Entity<Buffer>,
7079 cx: &mut Context<Self>,
7080 ) -> Task<anyhow::Result<()>> {
7081 let diagnostics = self.pull_diagnostics(buffer, cx);
7082 cx.spawn(async move |lsp_store, cx| {
7083 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7084 return Ok(());
7085 };
7086 lsp_store.update(cx, |lsp_store, cx| {
7087 if lsp_store.as_local().is_none() {
7088 return;
7089 }
7090
7091 let mut unchanged_buffers = HashSet::default();
7092 let mut changed_buffers = HashSet::default();
7093 let server_diagnostics_updates = diagnostics
7094 .into_iter()
7095 .filter_map(|diagnostics_set| match diagnostics_set {
7096 LspPullDiagnostics::Response {
7097 server_id,
7098 uri,
7099 diagnostics,
7100 } => Some((server_id, uri, diagnostics)),
7101 LspPullDiagnostics::Default => None,
7102 })
7103 .fold(
7104 HashMap::default(),
7105 |mut acc, (server_id, uri, diagnostics)| {
7106 let (result_id, diagnostics) = match diagnostics {
7107 PulledDiagnostics::Unchanged { result_id } => {
7108 unchanged_buffers.insert(uri.clone());
7109 (Some(result_id), Vec::new())
7110 }
7111 PulledDiagnostics::Changed {
7112 result_id,
7113 diagnostics,
7114 } => {
7115 changed_buffers.insert(uri.clone());
7116 (result_id, diagnostics)
7117 }
7118 };
7119 let disk_based_sources = Cow::Owned(
7120 lsp_store
7121 .language_server_adapter_for_id(server_id)
7122 .as_ref()
7123 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7124 .unwrap_or(&[])
7125 .to_vec(),
7126 );
7127 acc.entry(server_id).or_insert_with(Vec::new).push(
7128 DocumentDiagnosticsUpdate {
7129 server_id,
7130 diagnostics: lsp::PublishDiagnosticsParams {
7131 uri,
7132 diagnostics,
7133 version: None,
7134 },
7135 result_id,
7136 disk_based_sources,
7137 },
7138 );
7139 acc
7140 },
7141 );
7142
7143 for diagnostic_updates in server_diagnostics_updates.into_values() {
7144 lsp_store
7145 .merge_lsp_diagnostics(
7146 DiagnosticSourceKind::Pulled,
7147 diagnostic_updates,
7148 |buffer, old_diagnostic, cx| {
7149 File::from_dyn(buffer.file())
7150 .and_then(|file| {
7151 let abs_path = file.as_local()?.abs_path(cx);
7152 lsp::Uri::from_file_path(abs_path).ok()
7153 })
7154 .is_none_or(|buffer_uri| {
7155 unchanged_buffers.contains(&buffer_uri)
7156 || match old_diagnostic.source_kind {
7157 DiagnosticSourceKind::Pulled => {
7158 !changed_buffers.contains(&buffer_uri)
7159 }
7160 DiagnosticSourceKind::Other
7161 | DiagnosticSourceKind::Pushed => true,
7162 }
7163 })
7164 },
7165 cx,
7166 )
7167 .log_err();
7168 }
7169 })
7170 })
7171 }
7172
7173 pub fn document_colors(
7174 &mut self,
7175 known_cache_version: Option<usize>,
7176 buffer: Entity<Buffer>,
7177 cx: &mut Context<Self>,
7178 ) -> Option<DocumentColorTask> {
7179 let version_queried_for = buffer.read(cx).version();
7180 let buffer_id = buffer.read(cx).remote_id();
7181
7182 let current_language_servers = self.as_local().map(|local| {
7183 local
7184 .buffers_opened_in_servers
7185 .get(&buffer_id)
7186 .cloned()
7187 .unwrap_or_default()
7188 });
7189
7190 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7191 if let Some(cached_colors) = &lsp_data.document_colors {
7192 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7193 let has_different_servers =
7194 current_language_servers.is_some_and(|current_language_servers| {
7195 current_language_servers
7196 != cached_colors.colors.keys().copied().collect()
7197 });
7198 if !has_different_servers {
7199 let cache_version = cached_colors.cache_version;
7200 if Some(cache_version) == known_cache_version {
7201 return None;
7202 } else {
7203 return Some(
7204 Task::ready(Ok(DocumentColors {
7205 colors: cached_colors
7206 .colors
7207 .values()
7208 .flatten()
7209 .cloned()
7210 .collect(),
7211 cache_version: Some(cache_version),
7212 }))
7213 .shared(),
7214 );
7215 }
7216 }
7217 }
7218 }
7219 }
7220
7221 let color_lsp_data = self
7222 .latest_lsp_data(&buffer, cx)
7223 .document_colors
7224 .get_or_insert_default();
7225 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7226 && !version_queried_for.changed_since(updating_for)
7227 {
7228 return Some(running_update.clone());
7229 }
7230 let buffer_version_queried_for = version_queried_for.clone();
7231 let new_task = cx
7232 .spawn(async move |lsp_store, cx| {
7233 cx.background_executor()
7234 .timer(Duration::from_millis(30))
7235 .await;
7236 let fetched_colors = lsp_store
7237 .update(cx, |lsp_store, cx| {
7238 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7239 })?
7240 .await
7241 .context("fetching document colors")
7242 .map_err(Arc::new);
7243 let fetched_colors = match fetched_colors {
7244 Ok(fetched_colors) => {
7245 if Some(true)
7246 == buffer
7247 .update(cx, |buffer, _| {
7248 buffer.version() != buffer_version_queried_for
7249 })
7250 .ok()
7251 {
7252 return Ok(DocumentColors::default());
7253 }
7254 fetched_colors
7255 }
7256 Err(e) => {
7257 lsp_store
7258 .update(cx, |lsp_store, _| {
7259 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7260 if let Some(document_colors) = &mut lsp_data.document_colors {
7261 document_colors.colors_update = None;
7262 }
7263 }
7264 })
7265 .ok();
7266 return Err(e);
7267 }
7268 };
7269
7270 lsp_store
7271 .update(cx, |lsp_store, cx| {
7272 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7273 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7274
7275 if let Some(fetched_colors) = fetched_colors {
7276 if lsp_data.buffer_version == buffer_version_queried_for {
7277 lsp_colors.colors.extend(fetched_colors);
7278 lsp_colors.cache_version += 1;
7279 } else if !lsp_data
7280 .buffer_version
7281 .changed_since(&buffer_version_queried_for)
7282 {
7283 lsp_data.buffer_version = buffer_version_queried_for;
7284 lsp_colors.colors = fetched_colors;
7285 lsp_colors.cache_version += 1;
7286 }
7287 }
7288 lsp_colors.colors_update = None;
7289 let colors = lsp_colors
7290 .colors
7291 .values()
7292 .flatten()
7293 .cloned()
7294 .collect::<HashSet<_>>();
7295 DocumentColors {
7296 colors,
7297 cache_version: Some(lsp_colors.cache_version),
7298 }
7299 })
7300 .map_err(Arc::new)
7301 })
7302 .shared();
7303 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7304 Some(new_task)
7305 }
7306
7307 fn fetch_document_colors_for_buffer(
7308 &mut self,
7309 buffer: &Entity<Buffer>,
7310 cx: &mut Context<Self>,
7311 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7312 if let Some((client, project_id)) = self.upstream_client() {
7313 let request = GetDocumentColor {};
7314 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7315 return Task::ready(Ok(None));
7316 }
7317
7318 let request_task = client.request_lsp(
7319 project_id,
7320 None,
7321 LSP_REQUEST_TIMEOUT,
7322 cx.background_executor().clone(),
7323 request.to_proto(project_id, buffer.read(cx)),
7324 );
7325 let buffer = buffer.clone();
7326 cx.spawn(async move |lsp_store, cx| {
7327 let Some(lsp_store) = lsp_store.upgrade() else {
7328 return Ok(None);
7329 };
7330 let colors = join_all(
7331 request_task
7332 .await
7333 .log_err()
7334 .flatten()
7335 .map(|response| response.payload)
7336 .unwrap_or_default()
7337 .into_iter()
7338 .map(|color_response| {
7339 let response = request.response_from_proto(
7340 color_response.response,
7341 lsp_store.clone(),
7342 buffer.clone(),
7343 cx.clone(),
7344 );
7345 async move {
7346 (
7347 LanguageServerId::from_proto(color_response.server_id),
7348 response.await.log_err().unwrap_or_default(),
7349 )
7350 }
7351 }),
7352 )
7353 .await
7354 .into_iter()
7355 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7356 acc.entry(server_id)
7357 .or_insert_with(HashSet::default)
7358 .extend(colors);
7359 acc
7360 });
7361 Ok(Some(colors))
7362 })
7363 } else {
7364 let document_colors_task =
7365 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7366 cx.background_spawn(async move {
7367 Ok(Some(
7368 document_colors_task
7369 .await
7370 .into_iter()
7371 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7372 acc.entry(server_id)
7373 .or_insert_with(HashSet::default)
7374 .extend(colors);
7375 acc
7376 })
7377 .into_iter()
7378 .collect(),
7379 ))
7380 })
7381 }
7382 }
7383
7384 pub fn signature_help<T: ToPointUtf16>(
7385 &mut self,
7386 buffer: &Entity<Buffer>,
7387 position: T,
7388 cx: &mut Context<Self>,
7389 ) -> Task<Option<Vec<SignatureHelp>>> {
7390 let position = position.to_point_utf16(buffer.read(cx));
7391
7392 if let Some((client, upstream_project_id)) = self.upstream_client() {
7393 let request = GetSignatureHelp { position };
7394 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7395 return Task::ready(None);
7396 }
7397 let request_task = client.request_lsp(
7398 upstream_project_id,
7399 None,
7400 LSP_REQUEST_TIMEOUT,
7401 cx.background_executor().clone(),
7402 request.to_proto(upstream_project_id, buffer.read(cx)),
7403 );
7404 let buffer = buffer.clone();
7405 cx.spawn(async move |weak_lsp_store, cx| {
7406 let lsp_store = weak_lsp_store.upgrade()?;
7407 let signatures = join_all(
7408 request_task
7409 .await
7410 .log_err()
7411 .flatten()
7412 .map(|response| response.payload)
7413 .unwrap_or_default()
7414 .into_iter()
7415 .map(|response| {
7416 let response = GetSignatureHelp { position }.response_from_proto(
7417 response.response,
7418 lsp_store.clone(),
7419 buffer.clone(),
7420 cx.clone(),
7421 );
7422 async move { response.await.log_err().flatten() }
7423 }),
7424 )
7425 .await
7426 .into_iter()
7427 .flatten()
7428 .collect();
7429 Some(signatures)
7430 })
7431 } else {
7432 let all_actions_task = self.request_multiple_lsp_locally(
7433 buffer,
7434 Some(position),
7435 GetSignatureHelp { position },
7436 cx,
7437 );
7438 cx.background_spawn(async move {
7439 Some(
7440 all_actions_task
7441 .await
7442 .into_iter()
7443 .flat_map(|(_, actions)| actions)
7444 .collect::<Vec<_>>(),
7445 )
7446 })
7447 }
7448 }
7449
7450 pub fn hover(
7451 &mut self,
7452 buffer: &Entity<Buffer>,
7453 position: PointUtf16,
7454 cx: &mut Context<Self>,
7455 ) -> Task<Option<Vec<Hover>>> {
7456 if let Some((client, upstream_project_id)) = self.upstream_client() {
7457 let request = GetHover { position };
7458 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7459 return Task::ready(None);
7460 }
7461 let request_task = client.request_lsp(
7462 upstream_project_id,
7463 None,
7464 LSP_REQUEST_TIMEOUT,
7465 cx.background_executor().clone(),
7466 request.to_proto(upstream_project_id, buffer.read(cx)),
7467 );
7468 let buffer = buffer.clone();
7469 cx.spawn(async move |weak_lsp_store, cx| {
7470 let lsp_store = weak_lsp_store.upgrade()?;
7471 let hovers = join_all(
7472 request_task
7473 .await
7474 .log_err()
7475 .flatten()
7476 .map(|response| response.payload)
7477 .unwrap_or_default()
7478 .into_iter()
7479 .map(|response| {
7480 let response = GetHover { position }.response_from_proto(
7481 response.response,
7482 lsp_store.clone(),
7483 buffer.clone(),
7484 cx.clone(),
7485 );
7486 async move {
7487 response
7488 .await
7489 .log_err()
7490 .flatten()
7491 .and_then(remove_empty_hover_blocks)
7492 }
7493 }),
7494 )
7495 .await
7496 .into_iter()
7497 .flatten()
7498 .collect();
7499 Some(hovers)
7500 })
7501 } else {
7502 let all_actions_task = self.request_multiple_lsp_locally(
7503 buffer,
7504 Some(position),
7505 GetHover { position },
7506 cx,
7507 );
7508 cx.background_spawn(async move {
7509 Some(
7510 all_actions_task
7511 .await
7512 .into_iter()
7513 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7514 .collect::<Vec<Hover>>(),
7515 )
7516 })
7517 }
7518 }
7519
7520 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7521 let language_registry = self.languages.clone();
7522
7523 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7524 let request = upstream_client.request(proto::GetProjectSymbols {
7525 project_id: *project_id,
7526 query: query.to_string(),
7527 });
7528 cx.foreground_executor().spawn(async move {
7529 let response = request.await?;
7530 let mut symbols = Vec::new();
7531 let core_symbols = response
7532 .symbols
7533 .into_iter()
7534 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7535 .collect::<Vec<_>>();
7536 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7537 .await;
7538 Ok(symbols)
7539 })
7540 } else if let Some(local) = self.as_local() {
7541 struct WorkspaceSymbolsResult {
7542 server_id: LanguageServerId,
7543 lsp_adapter: Arc<CachedLspAdapter>,
7544 worktree: WeakEntity<Worktree>,
7545 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7546 }
7547
7548 let mut requests = Vec::new();
7549 let mut requested_servers = BTreeSet::new();
7550 for (seed, state) in local.language_server_ids.iter() {
7551 let Some(worktree_handle) = self
7552 .worktree_store
7553 .read(cx)
7554 .worktree_for_id(seed.worktree_id, cx)
7555 else {
7556 continue;
7557 };
7558 let worktree = worktree_handle.read(cx);
7559 if !worktree.is_visible() {
7560 continue;
7561 }
7562
7563 if !requested_servers.insert(state.id) {
7564 continue;
7565 }
7566
7567 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7568 Some(LanguageServerState::Running {
7569 adapter, server, ..
7570 }) => (adapter.clone(), server),
7571
7572 _ => continue,
7573 };
7574 let supports_workspace_symbol_request =
7575 match server.capabilities().workspace_symbol_provider {
7576 Some(OneOf::Left(supported)) => supported,
7577 Some(OneOf::Right(_)) => true,
7578 None => false,
7579 };
7580 if !supports_workspace_symbol_request {
7581 continue;
7582 }
7583 let worktree_handle = worktree_handle.clone();
7584 let server_id = server.server_id();
7585 requests.push(
7586 server
7587 .request::<lsp::request::WorkspaceSymbolRequest>(
7588 lsp::WorkspaceSymbolParams {
7589 query: query.to_string(),
7590 ..Default::default()
7591 },
7592 )
7593 .map(move |response| {
7594 let lsp_symbols = response.into_response()
7595 .context("workspace symbols request")
7596 .log_err()
7597 .flatten()
7598 .map(|symbol_response| match symbol_response {
7599 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7600 flat_responses.into_iter().map(|lsp_symbol| {
7601 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7602 }).collect::<Vec<_>>()
7603 }
7604 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7605 nested_responses.into_iter().filter_map(|lsp_symbol| {
7606 let location = match lsp_symbol.location {
7607 OneOf::Left(location) => location,
7608 OneOf::Right(_) => {
7609 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7610 return None
7611 }
7612 };
7613 Some((lsp_symbol.name, lsp_symbol.kind, location))
7614 }).collect::<Vec<_>>()
7615 }
7616 }).unwrap_or_default();
7617
7618 WorkspaceSymbolsResult {
7619 server_id,
7620 lsp_adapter,
7621 worktree: worktree_handle.downgrade(),
7622 lsp_symbols,
7623 }
7624 }),
7625 );
7626 }
7627
7628 cx.spawn(async move |this, cx| {
7629 let responses = futures::future::join_all(requests).await;
7630 let this = match this.upgrade() {
7631 Some(this) => this,
7632 None => return Ok(Vec::new()),
7633 };
7634
7635 let mut symbols = Vec::new();
7636 for result in responses {
7637 let core_symbols = this.update(cx, |this, cx| {
7638 result
7639 .lsp_symbols
7640 .into_iter()
7641 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7642 let abs_path = symbol_location.uri.to_file_path().ok()?;
7643 let source_worktree = result.worktree.upgrade()?;
7644 let source_worktree_id = source_worktree.read(cx).id();
7645
7646 let path = if let Some((tree, rel_path)) =
7647 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7648 {
7649 let worktree_id = tree.read(cx).id();
7650 SymbolLocation::InProject(ProjectPath {
7651 worktree_id,
7652 path: rel_path,
7653 })
7654 } else {
7655 SymbolLocation::OutsideProject {
7656 signature: this.symbol_signature(&abs_path),
7657 abs_path: abs_path.into(),
7658 }
7659 };
7660
7661 Some(CoreSymbol {
7662 source_language_server_id: result.server_id,
7663 language_server_name: result.lsp_adapter.name.clone(),
7664 source_worktree_id,
7665 path,
7666 kind: symbol_kind,
7667 name: symbol_name,
7668 range: range_from_lsp(symbol_location.range),
7669 })
7670 })
7671 .collect()
7672 })?;
7673
7674 populate_labels_for_symbols(
7675 core_symbols,
7676 &language_registry,
7677 Some(result.lsp_adapter),
7678 &mut symbols,
7679 )
7680 .await;
7681 }
7682
7683 Ok(symbols)
7684 })
7685 } else {
7686 Task::ready(Err(anyhow!("No upstream client or local language server")))
7687 }
7688 }
7689
7690 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7691 let mut summary = DiagnosticSummary::default();
7692 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7693 summary.error_count += path_summary.error_count;
7694 summary.warning_count += path_summary.warning_count;
7695 }
7696 summary
7697 }
7698
7699 /// Returns the diagnostic summary for a specific project path.
7700 pub fn diagnostic_summary_for_path(
7701 &self,
7702 project_path: &ProjectPath,
7703 _: &App,
7704 ) -> DiagnosticSummary {
7705 if let Some(summaries) = self
7706 .diagnostic_summaries
7707 .get(&project_path.worktree_id)
7708 .and_then(|map| map.get(&project_path.path))
7709 {
7710 let (error_count, warning_count) = summaries.iter().fold(
7711 (0, 0),
7712 |(error_count, warning_count), (_language_server_id, summary)| {
7713 (
7714 error_count + summary.error_count,
7715 warning_count + summary.warning_count,
7716 )
7717 },
7718 );
7719
7720 DiagnosticSummary {
7721 error_count,
7722 warning_count,
7723 }
7724 } else {
7725 DiagnosticSummary::default()
7726 }
7727 }
7728
7729 pub fn diagnostic_summaries<'a>(
7730 &'a self,
7731 include_ignored: bool,
7732 cx: &'a App,
7733 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7734 self.worktree_store
7735 .read(cx)
7736 .visible_worktrees(cx)
7737 .filter_map(|worktree| {
7738 let worktree = worktree.read(cx);
7739 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7740 })
7741 .flat_map(move |(worktree, summaries)| {
7742 let worktree_id = worktree.id();
7743 summaries
7744 .iter()
7745 .filter(move |(path, _)| {
7746 include_ignored
7747 || worktree
7748 .entry_for_path(path.as_ref())
7749 .is_some_and(|entry| !entry.is_ignored)
7750 })
7751 .flat_map(move |(path, summaries)| {
7752 summaries.iter().map(move |(server_id, summary)| {
7753 (
7754 ProjectPath {
7755 worktree_id,
7756 path: path.clone(),
7757 },
7758 *server_id,
7759 *summary,
7760 )
7761 })
7762 })
7763 })
7764 }
7765
7766 pub fn on_buffer_edited(
7767 &mut self,
7768 buffer: Entity<Buffer>,
7769 cx: &mut Context<Self>,
7770 ) -> Option<()> {
7771 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7772 Some(
7773 self.as_local()?
7774 .language_servers_for_buffer(buffer, cx)
7775 .map(|i| i.1.clone())
7776 .collect(),
7777 )
7778 })?;
7779
7780 let buffer = buffer.read(cx);
7781 let file = File::from_dyn(buffer.file())?;
7782 let abs_path = file.as_local()?.abs_path(cx);
7783 let uri = lsp::Uri::from_file_path(&abs_path)
7784 .ok()
7785 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7786 .log_err()?;
7787 let next_snapshot = buffer.text_snapshot();
7788 for language_server in language_servers {
7789 let language_server = language_server.clone();
7790
7791 let buffer_snapshots = self
7792 .as_local_mut()?
7793 .buffer_snapshots
7794 .get_mut(&buffer.remote_id())
7795 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7796 let previous_snapshot = buffer_snapshots.last()?;
7797
7798 let build_incremental_change = || {
7799 buffer
7800 .edits_since::<Dimensions<PointUtf16, usize>>(
7801 previous_snapshot.snapshot.version(),
7802 )
7803 .map(|edit| {
7804 let edit_start = edit.new.start.0;
7805 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7806 let new_text = next_snapshot
7807 .text_for_range(edit.new.start.1..edit.new.end.1)
7808 .collect();
7809 lsp::TextDocumentContentChangeEvent {
7810 range: Some(lsp::Range::new(
7811 point_to_lsp(edit_start),
7812 point_to_lsp(edit_end),
7813 )),
7814 range_length: None,
7815 text: new_text,
7816 }
7817 })
7818 .collect()
7819 };
7820
7821 let document_sync_kind = language_server
7822 .capabilities()
7823 .text_document_sync
7824 .as_ref()
7825 .and_then(|sync| match sync {
7826 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7827 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7828 });
7829
7830 let content_changes: Vec<_> = match document_sync_kind {
7831 Some(lsp::TextDocumentSyncKind::FULL) => {
7832 vec![lsp::TextDocumentContentChangeEvent {
7833 range: None,
7834 range_length: None,
7835 text: next_snapshot.text(),
7836 }]
7837 }
7838 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7839 _ => {
7840 #[cfg(any(test, feature = "test-support"))]
7841 {
7842 build_incremental_change()
7843 }
7844
7845 #[cfg(not(any(test, feature = "test-support")))]
7846 {
7847 continue;
7848 }
7849 }
7850 };
7851
7852 let next_version = previous_snapshot.version + 1;
7853 buffer_snapshots.push(LspBufferSnapshot {
7854 version: next_version,
7855 snapshot: next_snapshot.clone(),
7856 });
7857
7858 language_server
7859 .notify::<lsp::notification::DidChangeTextDocument>(
7860 lsp::DidChangeTextDocumentParams {
7861 text_document: lsp::VersionedTextDocumentIdentifier::new(
7862 uri.clone(),
7863 next_version,
7864 ),
7865 content_changes,
7866 },
7867 )
7868 .ok();
7869 self.pull_workspace_diagnostics(language_server.server_id());
7870 }
7871
7872 None
7873 }
7874
7875 pub fn on_buffer_saved(
7876 &mut self,
7877 buffer: Entity<Buffer>,
7878 cx: &mut Context<Self>,
7879 ) -> Option<()> {
7880 let file = File::from_dyn(buffer.read(cx).file())?;
7881 let worktree_id = file.worktree_id(cx);
7882 let abs_path = file.as_local()?.abs_path(cx);
7883 let text_document = lsp::TextDocumentIdentifier {
7884 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7885 };
7886 let local = self.as_local()?;
7887
7888 for server in local.language_servers_for_worktree(worktree_id) {
7889 if let Some(include_text) = include_text(server.as_ref()) {
7890 let text = if include_text {
7891 Some(buffer.read(cx).text())
7892 } else {
7893 None
7894 };
7895 server
7896 .notify::<lsp::notification::DidSaveTextDocument>(
7897 lsp::DidSaveTextDocumentParams {
7898 text_document: text_document.clone(),
7899 text,
7900 },
7901 )
7902 .ok();
7903 }
7904 }
7905
7906 let language_servers = buffer.update(cx, |buffer, cx| {
7907 local.language_server_ids_for_buffer(buffer, cx)
7908 });
7909 for language_server_id in language_servers {
7910 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7911 }
7912
7913 None
7914 }
7915
7916 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7917 maybe!(async move {
7918 let mut refreshed_servers = HashSet::default();
7919 let servers = lsp_store
7920 .update(cx, |lsp_store, cx| {
7921 let local = lsp_store.as_local()?;
7922
7923 let servers = local
7924 .language_server_ids
7925 .iter()
7926 .filter_map(|(seed, state)| {
7927 let worktree = lsp_store
7928 .worktree_store
7929 .read(cx)
7930 .worktree_for_id(seed.worktree_id, cx);
7931 let delegate: Arc<dyn LspAdapterDelegate> =
7932 worktree.map(|worktree| {
7933 LocalLspAdapterDelegate::new(
7934 local.languages.clone(),
7935 &local.environment,
7936 cx.weak_entity(),
7937 &worktree,
7938 local.http_client.clone(),
7939 local.fs.clone(),
7940 cx,
7941 )
7942 })?;
7943 let server_id = state.id;
7944
7945 let states = local.language_servers.get(&server_id)?;
7946
7947 match states {
7948 LanguageServerState::Starting { .. } => None,
7949 LanguageServerState::Running {
7950 adapter, server, ..
7951 } => {
7952 let adapter = adapter.clone();
7953 let server = server.clone();
7954 refreshed_servers.insert(server.name());
7955 let toolchain = seed.toolchain.clone();
7956 Some(cx.spawn(async move |_, cx| {
7957 let settings =
7958 LocalLspStore::workspace_configuration_for_adapter(
7959 adapter.adapter.clone(),
7960 &delegate,
7961 toolchain,
7962 cx,
7963 )
7964 .await
7965 .ok()?;
7966 server
7967 .notify::<lsp::notification::DidChangeConfiguration>(
7968 lsp::DidChangeConfigurationParams { settings },
7969 )
7970 .ok()?;
7971 Some(())
7972 }))
7973 }
7974 }
7975 })
7976 .collect::<Vec<_>>();
7977
7978 Some(servers)
7979 })
7980 .ok()
7981 .flatten()?;
7982
7983 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7984 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7985 // to stop and unregister its language server wrapper.
7986 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7987 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7988 let _: Vec<Option<()>> = join_all(servers).await;
7989
7990 Some(())
7991 })
7992 .await;
7993 }
7994
7995 fn maintain_workspace_config(
7996 external_refresh_requests: watch::Receiver<()>,
7997 cx: &mut Context<Self>,
7998 ) -> Task<Result<()>> {
7999 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8000 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8001
8002 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8003 *settings_changed_tx.borrow_mut() = ();
8004 });
8005
8006 let mut joint_future =
8007 futures::stream::select(settings_changed_rx, external_refresh_requests);
8008 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8009 // - 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).
8010 // - 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.
8011 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8012 // - 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,
8013 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8014 cx.spawn(async move |this, cx| {
8015 while let Some(()) = joint_future.next().await {
8016 this.update(cx, |this, cx| {
8017 this.refresh_server_tree(cx);
8018 })
8019 .ok();
8020
8021 Self::refresh_workspace_configurations(&this, cx).await;
8022 }
8023
8024 drop(settings_observation);
8025 anyhow::Ok(())
8026 })
8027 }
8028
8029 pub fn language_servers_for_local_buffer<'a>(
8030 &'a self,
8031 buffer: &Buffer,
8032 cx: &mut App,
8033 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8034 let local = self.as_local();
8035 let language_server_ids = local
8036 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8037 .unwrap_or_default();
8038
8039 language_server_ids
8040 .into_iter()
8041 .filter_map(
8042 move |server_id| match local?.language_servers.get(&server_id)? {
8043 LanguageServerState::Running {
8044 adapter, server, ..
8045 } => Some((adapter, server)),
8046 _ => None,
8047 },
8048 )
8049 }
8050
8051 pub fn language_server_for_local_buffer<'a>(
8052 &'a self,
8053 buffer: &'a Buffer,
8054 server_id: LanguageServerId,
8055 cx: &'a mut App,
8056 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8057 self.as_local()?
8058 .language_servers_for_buffer(buffer, cx)
8059 .find(|(_, s)| s.server_id() == server_id)
8060 }
8061
8062 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8063 self.diagnostic_summaries.remove(&id_to_remove);
8064 if let Some(local) = self.as_local_mut() {
8065 let to_remove = local.remove_worktree(id_to_remove, cx);
8066 for server in to_remove {
8067 self.language_server_statuses.remove(&server);
8068 }
8069 }
8070 }
8071
8072 pub fn shared(
8073 &mut self,
8074 project_id: u64,
8075 downstream_client: AnyProtoClient,
8076 _: &mut Context<Self>,
8077 ) {
8078 self.downstream_client = Some((downstream_client.clone(), project_id));
8079
8080 for (server_id, status) in &self.language_server_statuses {
8081 if let Some(server) = self.language_server_for_id(*server_id) {
8082 downstream_client
8083 .send(proto::StartLanguageServer {
8084 project_id,
8085 server: Some(proto::LanguageServer {
8086 id: server_id.to_proto(),
8087 name: status.name.to_string(),
8088 worktree_id: status.worktree.map(|id| id.to_proto()),
8089 }),
8090 capabilities: serde_json::to_string(&server.capabilities())
8091 .expect("serializing server LSP capabilities"),
8092 })
8093 .log_err();
8094 }
8095 }
8096 }
8097
8098 pub fn disconnected_from_host(&mut self) {
8099 self.downstream_client.take();
8100 }
8101
8102 pub fn disconnected_from_ssh_remote(&mut self) {
8103 if let LspStoreMode::Remote(RemoteLspStore {
8104 upstream_client, ..
8105 }) = &mut self.mode
8106 {
8107 upstream_client.take();
8108 }
8109 }
8110
8111 pub(crate) fn set_language_server_statuses_from_proto(
8112 &mut self,
8113 project: WeakEntity<Project>,
8114 language_servers: Vec<proto::LanguageServer>,
8115 server_capabilities: Vec<String>,
8116 cx: &mut Context<Self>,
8117 ) {
8118 let lsp_logs = cx
8119 .try_global::<GlobalLogStore>()
8120 .map(|lsp_store| lsp_store.0.clone());
8121
8122 self.language_server_statuses = language_servers
8123 .into_iter()
8124 .zip(server_capabilities)
8125 .map(|(server, server_capabilities)| {
8126 let server_id = LanguageServerId(server.id as usize);
8127 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8128 self.lsp_server_capabilities
8129 .insert(server_id, server_capabilities);
8130 }
8131
8132 let name = LanguageServerName::from_proto(server.name);
8133 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8134
8135 if let Some(lsp_logs) = &lsp_logs {
8136 lsp_logs.update(cx, |lsp_logs, cx| {
8137 lsp_logs.add_language_server(
8138 // Only remote clients get their language servers set from proto
8139 LanguageServerKind::Remote {
8140 project: project.clone(),
8141 },
8142 server_id,
8143 Some(name.clone()),
8144 worktree,
8145 None,
8146 cx,
8147 );
8148 });
8149 }
8150
8151 (
8152 server_id,
8153 LanguageServerStatus {
8154 name,
8155 pending_work: Default::default(),
8156 has_pending_diagnostic_updates: false,
8157 progress_tokens: Default::default(),
8158 worktree,
8159 binary: None,
8160 configuration: None,
8161 workspace_folders: BTreeSet::new(),
8162 },
8163 )
8164 })
8165 .collect();
8166 }
8167
8168 #[cfg(test)]
8169 pub fn update_diagnostic_entries(
8170 &mut self,
8171 server_id: LanguageServerId,
8172 abs_path: PathBuf,
8173 result_id: Option<String>,
8174 version: Option<i32>,
8175 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8176 cx: &mut Context<Self>,
8177 ) -> anyhow::Result<()> {
8178 self.merge_diagnostic_entries(
8179 vec![DocumentDiagnosticsUpdate {
8180 diagnostics: DocumentDiagnostics {
8181 diagnostics,
8182 document_abs_path: abs_path,
8183 version,
8184 },
8185 result_id,
8186 server_id,
8187 disk_based_sources: Cow::Borrowed(&[]),
8188 }],
8189 |_, _, _| false,
8190 cx,
8191 )?;
8192 Ok(())
8193 }
8194
8195 pub fn merge_diagnostic_entries<'a>(
8196 &mut self,
8197 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8198 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8199 cx: &mut Context<Self>,
8200 ) -> anyhow::Result<()> {
8201 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8202 let mut updated_diagnostics_paths = HashMap::default();
8203 for mut update in diagnostic_updates {
8204 let abs_path = &update.diagnostics.document_abs_path;
8205 let server_id = update.server_id;
8206 let Some((worktree, relative_path)) =
8207 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8208 else {
8209 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8210 return Ok(());
8211 };
8212
8213 let worktree_id = worktree.read(cx).id();
8214 let project_path = ProjectPath {
8215 worktree_id,
8216 path: relative_path,
8217 };
8218
8219 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8220 let snapshot = buffer_handle.read(cx).snapshot();
8221 let buffer = buffer_handle.read(cx);
8222 let reused_diagnostics = buffer
8223 .buffer_diagnostics(Some(server_id))
8224 .iter()
8225 .filter(|v| merge(buffer, &v.diagnostic, cx))
8226 .map(|v| {
8227 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8228 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8229 DiagnosticEntry {
8230 range: start..end,
8231 diagnostic: v.diagnostic.clone(),
8232 }
8233 })
8234 .collect::<Vec<_>>();
8235
8236 self.as_local_mut()
8237 .context("cannot merge diagnostics on a remote LspStore")?
8238 .update_buffer_diagnostics(
8239 &buffer_handle,
8240 server_id,
8241 update.result_id,
8242 update.diagnostics.version,
8243 update.diagnostics.diagnostics.clone(),
8244 reused_diagnostics.clone(),
8245 cx,
8246 )?;
8247
8248 update.diagnostics.diagnostics.extend(reused_diagnostics);
8249 }
8250
8251 let updated = worktree.update(cx, |worktree, cx| {
8252 self.update_worktree_diagnostics(
8253 worktree.id(),
8254 server_id,
8255 project_path.path.clone(),
8256 update.diagnostics.diagnostics,
8257 cx,
8258 )
8259 })?;
8260 match updated {
8261 ControlFlow::Continue(new_summary) => {
8262 if let Some((project_id, new_summary)) = new_summary {
8263 match &mut diagnostics_summary {
8264 Some(diagnostics_summary) => {
8265 diagnostics_summary
8266 .more_summaries
8267 .push(proto::DiagnosticSummary {
8268 path: project_path.path.as_ref().to_proto(),
8269 language_server_id: server_id.0 as u64,
8270 error_count: new_summary.error_count,
8271 warning_count: new_summary.warning_count,
8272 })
8273 }
8274 None => {
8275 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8276 project_id,
8277 worktree_id: worktree_id.to_proto(),
8278 summary: Some(proto::DiagnosticSummary {
8279 path: project_path.path.as_ref().to_proto(),
8280 language_server_id: server_id.0 as u64,
8281 error_count: new_summary.error_count,
8282 warning_count: new_summary.warning_count,
8283 }),
8284 more_summaries: Vec::new(),
8285 })
8286 }
8287 }
8288 }
8289 updated_diagnostics_paths
8290 .entry(server_id)
8291 .or_insert_with(Vec::new)
8292 .push(project_path);
8293 }
8294 ControlFlow::Break(()) => {}
8295 }
8296 }
8297
8298 if let Some((diagnostics_summary, (downstream_client, _))) =
8299 diagnostics_summary.zip(self.downstream_client.as_ref())
8300 {
8301 downstream_client.send(diagnostics_summary).log_err();
8302 }
8303 for (server_id, paths) in updated_diagnostics_paths {
8304 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8305 }
8306 Ok(())
8307 }
8308
8309 fn update_worktree_diagnostics(
8310 &mut self,
8311 worktree_id: WorktreeId,
8312 server_id: LanguageServerId,
8313 path_in_worktree: Arc<RelPath>,
8314 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8315 _: &mut Context<Worktree>,
8316 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8317 let local = match &mut self.mode {
8318 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8319 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8320 };
8321
8322 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8323 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8324 let summaries_by_server_id = summaries_for_tree
8325 .entry(path_in_worktree.clone())
8326 .or_default();
8327
8328 let old_summary = summaries_by_server_id
8329 .remove(&server_id)
8330 .unwrap_or_default();
8331
8332 let new_summary = DiagnosticSummary::new(&diagnostics);
8333 if new_summary.is_empty() {
8334 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8335 {
8336 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8337 diagnostics_by_server_id.remove(ix);
8338 }
8339 if diagnostics_by_server_id.is_empty() {
8340 diagnostics_for_tree.remove(&path_in_worktree);
8341 }
8342 }
8343 } else {
8344 summaries_by_server_id.insert(server_id, new_summary);
8345 let diagnostics_by_server_id = diagnostics_for_tree
8346 .entry(path_in_worktree.clone())
8347 .or_default();
8348 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8349 Ok(ix) => {
8350 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8351 }
8352 Err(ix) => {
8353 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8354 }
8355 }
8356 }
8357
8358 if !old_summary.is_empty() || !new_summary.is_empty() {
8359 if let Some((_, project_id)) = &self.downstream_client {
8360 Ok(ControlFlow::Continue(Some((
8361 *project_id,
8362 proto::DiagnosticSummary {
8363 path: path_in_worktree.to_proto(),
8364 language_server_id: server_id.0 as u64,
8365 error_count: new_summary.error_count as u32,
8366 warning_count: new_summary.warning_count as u32,
8367 },
8368 ))))
8369 } else {
8370 Ok(ControlFlow::Continue(None))
8371 }
8372 } else {
8373 Ok(ControlFlow::Break(()))
8374 }
8375 }
8376
8377 pub fn open_buffer_for_symbol(
8378 &mut self,
8379 symbol: &Symbol,
8380 cx: &mut Context<Self>,
8381 ) -> Task<Result<Entity<Buffer>>> {
8382 if let Some((client, project_id)) = self.upstream_client() {
8383 let request = client.request(proto::OpenBufferForSymbol {
8384 project_id,
8385 symbol: Some(Self::serialize_symbol(symbol)),
8386 });
8387 cx.spawn(async move |this, cx| {
8388 let response = request.await?;
8389 let buffer_id = BufferId::new(response.buffer_id)?;
8390 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8391 .await
8392 })
8393 } else if let Some(local) = self.as_local() {
8394 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8395 seed.worktree_id == symbol.source_worktree_id
8396 && state.id == symbol.source_language_server_id
8397 && symbol.language_server_name == seed.name
8398 });
8399 if !is_valid {
8400 return Task::ready(Err(anyhow!(
8401 "language server for worktree and language not found"
8402 )));
8403 };
8404
8405 let symbol_abs_path = match &symbol.path {
8406 SymbolLocation::InProject(project_path) => self
8407 .worktree_store
8408 .read(cx)
8409 .absolutize(&project_path, cx)
8410 .context("no such worktree"),
8411 SymbolLocation::OutsideProject {
8412 abs_path,
8413 signature: _,
8414 } => Ok(abs_path.to_path_buf()),
8415 };
8416 let symbol_abs_path = match symbol_abs_path {
8417 Ok(abs_path) => abs_path,
8418 Err(err) => return Task::ready(Err(err)),
8419 };
8420 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8421 uri
8422 } else {
8423 return Task::ready(Err(anyhow!("invalid symbol path")));
8424 };
8425
8426 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8427 } else {
8428 Task::ready(Err(anyhow!("no upstream client or local store")))
8429 }
8430 }
8431
8432 pub(crate) fn open_local_buffer_via_lsp(
8433 &mut self,
8434 abs_path: lsp::Uri,
8435 language_server_id: LanguageServerId,
8436 cx: &mut Context<Self>,
8437 ) -> Task<Result<Entity<Buffer>>> {
8438 cx.spawn(async move |lsp_store, cx| {
8439 // Escape percent-encoded string.
8440 let current_scheme = abs_path.scheme().to_owned();
8441 // Uri is immutable, so we can't modify the scheme
8442
8443 let abs_path = abs_path
8444 .to_file_path()
8445 .map_err(|()| anyhow!("can't convert URI to path"))?;
8446 let p = abs_path.clone();
8447 let yarn_worktree = lsp_store
8448 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8449 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8450 cx.spawn(async move |this, cx| {
8451 let t = this
8452 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8453 .ok()?;
8454 t.await
8455 })
8456 }),
8457 None => Task::ready(None),
8458 })?
8459 .await;
8460 let (worktree_root_target, known_relative_path) =
8461 if let Some((zip_root, relative_path)) = yarn_worktree {
8462 (zip_root, Some(relative_path))
8463 } else {
8464 (Arc::<Path>::from(abs_path.as_path()), None)
8465 };
8466 let (worktree, relative_path) = if let Some(result) =
8467 lsp_store.update(cx, |lsp_store, cx| {
8468 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8469 worktree_store.find_worktree(&worktree_root_target, cx)
8470 })
8471 })? {
8472 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8473 (result.0, relative_path)
8474 } else {
8475 let worktree = lsp_store
8476 .update(cx, |lsp_store, cx| {
8477 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8478 worktree_store.create_worktree(&worktree_root_target, false, cx)
8479 })
8480 })?
8481 .await?;
8482 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8483 lsp_store
8484 .update(cx, |lsp_store, cx| {
8485 if let Some(local) = lsp_store.as_local_mut() {
8486 local.register_language_server_for_invisible_worktree(
8487 &worktree,
8488 language_server_id,
8489 cx,
8490 )
8491 }
8492 })
8493 .ok();
8494 }
8495 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8496 let relative_path = if let Some(known_path) = known_relative_path {
8497 known_path
8498 } else {
8499 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8500 .into_arc()
8501 };
8502 (worktree, relative_path)
8503 };
8504 let project_path = ProjectPath {
8505 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8506 path: relative_path,
8507 };
8508 lsp_store
8509 .update(cx, |lsp_store, cx| {
8510 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8511 buffer_store.open_buffer(project_path, cx)
8512 })
8513 })?
8514 .await
8515 })
8516 }
8517
8518 fn request_multiple_lsp_locally<P, R>(
8519 &mut self,
8520 buffer: &Entity<Buffer>,
8521 position: Option<P>,
8522 request: R,
8523 cx: &mut Context<Self>,
8524 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8525 where
8526 P: ToOffset,
8527 R: LspCommand + Clone,
8528 <R::LspRequest as lsp::request::Request>::Result: Send,
8529 <R::LspRequest as lsp::request::Request>::Params: Send,
8530 {
8531 let Some(local) = self.as_local() else {
8532 return Task::ready(Vec::new());
8533 };
8534
8535 let snapshot = buffer.read(cx).snapshot();
8536 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8537
8538 let server_ids = buffer.update(cx, |buffer, cx| {
8539 local
8540 .language_servers_for_buffer(buffer, cx)
8541 .filter(|(adapter, _)| {
8542 scope
8543 .as_ref()
8544 .map(|scope| scope.language_allowed(&adapter.name))
8545 .unwrap_or(true)
8546 })
8547 .map(|(_, server)| server.server_id())
8548 .filter(|server_id| {
8549 self.as_local().is_none_or(|local| {
8550 local
8551 .buffers_opened_in_servers
8552 .get(&snapshot.remote_id())
8553 .is_some_and(|servers| servers.contains(server_id))
8554 })
8555 })
8556 .collect::<Vec<_>>()
8557 });
8558
8559 let mut response_results = server_ids
8560 .into_iter()
8561 .map(|server_id| {
8562 let task = self.request_lsp(
8563 buffer.clone(),
8564 LanguageServerToQuery::Other(server_id),
8565 request.clone(),
8566 cx,
8567 );
8568 async move { (server_id, task.await) }
8569 })
8570 .collect::<FuturesUnordered<_>>();
8571
8572 cx.background_spawn(async move {
8573 let mut responses = Vec::with_capacity(response_results.len());
8574 while let Some((server_id, response_result)) = response_results.next().await {
8575 match response_result {
8576 Ok(response) => responses.push((server_id, response)),
8577 // rust-analyzer likes to error with this when its still loading up
8578 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8579 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8580 }
8581 }
8582 responses
8583 })
8584 }
8585
8586 async fn handle_lsp_get_completions(
8587 this: Entity<Self>,
8588 envelope: TypedEnvelope<proto::GetCompletions>,
8589 mut cx: AsyncApp,
8590 ) -> Result<proto::GetCompletionsResponse> {
8591 let sender_id = envelope.original_sender_id().unwrap_or_default();
8592
8593 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8594 let buffer_handle = this.update(&mut cx, |this, cx| {
8595 this.buffer_store.read(cx).get_existing(buffer_id)
8596 })??;
8597 let request = GetCompletions::from_proto(
8598 envelope.payload,
8599 this.clone(),
8600 buffer_handle.clone(),
8601 cx.clone(),
8602 )
8603 .await?;
8604
8605 let server_to_query = match request.server_id {
8606 Some(server_id) => LanguageServerToQuery::Other(server_id),
8607 None => LanguageServerToQuery::FirstCapable,
8608 };
8609
8610 let response = this
8611 .update(&mut cx, |this, cx| {
8612 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8613 })?
8614 .await?;
8615 this.update(&mut cx, |this, cx| {
8616 Ok(GetCompletions::response_to_proto(
8617 response,
8618 this,
8619 sender_id,
8620 &buffer_handle.read(cx).version(),
8621 cx,
8622 ))
8623 })?
8624 }
8625
8626 async fn handle_lsp_command<T: LspCommand>(
8627 this: Entity<Self>,
8628 envelope: TypedEnvelope<T::ProtoRequest>,
8629 mut cx: AsyncApp,
8630 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8631 where
8632 <T::LspRequest as lsp::request::Request>::Params: Send,
8633 <T::LspRequest as lsp::request::Request>::Result: Send,
8634 {
8635 let sender_id = envelope.original_sender_id().unwrap_or_default();
8636 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8637 let buffer_handle = this.update(&mut cx, |this, cx| {
8638 this.buffer_store.read(cx).get_existing(buffer_id)
8639 })??;
8640 let request = T::from_proto(
8641 envelope.payload,
8642 this.clone(),
8643 buffer_handle.clone(),
8644 cx.clone(),
8645 )
8646 .await?;
8647 let response = this
8648 .update(&mut cx, |this, cx| {
8649 this.request_lsp(
8650 buffer_handle.clone(),
8651 LanguageServerToQuery::FirstCapable,
8652 request,
8653 cx,
8654 )
8655 })?
8656 .await?;
8657 this.update(&mut cx, |this, cx| {
8658 Ok(T::response_to_proto(
8659 response,
8660 this,
8661 sender_id,
8662 &buffer_handle.read(cx).version(),
8663 cx,
8664 ))
8665 })?
8666 }
8667
8668 async fn handle_lsp_query(
8669 lsp_store: Entity<Self>,
8670 envelope: TypedEnvelope<proto::LspQuery>,
8671 mut cx: AsyncApp,
8672 ) -> Result<proto::Ack> {
8673 use proto::lsp_query::Request;
8674 let sender_id = envelope.original_sender_id().unwrap_or_default();
8675 let lsp_query = envelope.payload;
8676 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8677 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8678 match lsp_query.request.context("invalid LSP query request")? {
8679 Request::GetReferences(get_references) => {
8680 let position = get_references.position.clone().and_then(deserialize_anchor);
8681 Self::query_lsp_locally::<GetReferences>(
8682 lsp_store,
8683 server_id,
8684 sender_id,
8685 lsp_request_id,
8686 get_references,
8687 position,
8688 &mut cx,
8689 )
8690 .await?;
8691 }
8692 Request::GetDocumentColor(get_document_color) => {
8693 Self::query_lsp_locally::<GetDocumentColor>(
8694 lsp_store,
8695 server_id,
8696 sender_id,
8697 lsp_request_id,
8698 get_document_color,
8699 None,
8700 &mut cx,
8701 )
8702 .await?;
8703 }
8704 Request::GetHover(get_hover) => {
8705 let position = get_hover.position.clone().and_then(deserialize_anchor);
8706 Self::query_lsp_locally::<GetHover>(
8707 lsp_store,
8708 server_id,
8709 sender_id,
8710 lsp_request_id,
8711 get_hover,
8712 position,
8713 &mut cx,
8714 )
8715 .await?;
8716 }
8717 Request::GetCodeActions(get_code_actions) => {
8718 Self::query_lsp_locally::<GetCodeActions>(
8719 lsp_store,
8720 server_id,
8721 sender_id,
8722 lsp_request_id,
8723 get_code_actions,
8724 None,
8725 &mut cx,
8726 )
8727 .await?;
8728 }
8729 Request::GetSignatureHelp(get_signature_help) => {
8730 let position = get_signature_help
8731 .position
8732 .clone()
8733 .and_then(deserialize_anchor);
8734 Self::query_lsp_locally::<GetSignatureHelp>(
8735 lsp_store,
8736 server_id,
8737 sender_id,
8738 lsp_request_id,
8739 get_signature_help,
8740 position,
8741 &mut cx,
8742 )
8743 .await?;
8744 }
8745 Request::GetCodeLens(get_code_lens) => {
8746 Self::query_lsp_locally::<GetCodeLens>(
8747 lsp_store,
8748 server_id,
8749 sender_id,
8750 lsp_request_id,
8751 get_code_lens,
8752 None,
8753 &mut cx,
8754 )
8755 .await?;
8756 }
8757 Request::GetDefinition(get_definition) => {
8758 let position = get_definition.position.clone().and_then(deserialize_anchor);
8759 Self::query_lsp_locally::<GetDefinitions>(
8760 lsp_store,
8761 server_id,
8762 sender_id,
8763 lsp_request_id,
8764 get_definition,
8765 position,
8766 &mut cx,
8767 )
8768 .await?;
8769 }
8770 Request::GetDeclaration(get_declaration) => {
8771 let position = get_declaration
8772 .position
8773 .clone()
8774 .and_then(deserialize_anchor);
8775 Self::query_lsp_locally::<GetDeclarations>(
8776 lsp_store,
8777 server_id,
8778 sender_id,
8779 lsp_request_id,
8780 get_declaration,
8781 position,
8782 &mut cx,
8783 )
8784 .await?;
8785 }
8786 Request::GetTypeDefinition(get_type_definition) => {
8787 let position = get_type_definition
8788 .position
8789 .clone()
8790 .and_then(deserialize_anchor);
8791 Self::query_lsp_locally::<GetTypeDefinitions>(
8792 lsp_store,
8793 server_id,
8794 sender_id,
8795 lsp_request_id,
8796 get_type_definition,
8797 position,
8798 &mut cx,
8799 )
8800 .await?;
8801 }
8802 Request::GetImplementation(get_implementation) => {
8803 let position = get_implementation
8804 .position
8805 .clone()
8806 .and_then(deserialize_anchor);
8807 Self::query_lsp_locally::<GetImplementations>(
8808 lsp_store,
8809 server_id,
8810 sender_id,
8811 lsp_request_id,
8812 get_implementation,
8813 position,
8814 &mut cx,
8815 )
8816 .await?;
8817 }
8818 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8819 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8820 let version = deserialize_version(get_document_diagnostics.buffer_version());
8821 let buffer = lsp_store.update(&mut cx, |this, cx| {
8822 this.buffer_store.read(cx).get_existing(buffer_id)
8823 })??;
8824 buffer
8825 .update(&mut cx, |buffer, _| {
8826 buffer.wait_for_version(version.clone())
8827 })?
8828 .await?;
8829 lsp_store.update(&mut cx, |lsp_store, cx| {
8830 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8831 let key = LspKey {
8832 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8833 server_queried: server_id,
8834 };
8835 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8836 ) {
8837 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8838 lsp_requests.clear();
8839 };
8840 }
8841
8842 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8843 existing_queries.insert(
8844 lsp_request_id,
8845 cx.spawn(async move |lsp_store, cx| {
8846 let diagnostics_pull = lsp_store
8847 .update(cx, |lsp_store, cx| {
8848 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8849 })
8850 .ok();
8851 if let Some(diagnostics_pull) = diagnostics_pull {
8852 match diagnostics_pull.await {
8853 Ok(()) => {}
8854 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8855 };
8856 }
8857 }),
8858 );
8859 })?;
8860 }
8861 Request::InlayHints(inlay_hints) => {
8862 let query_start = inlay_hints
8863 .start
8864 .clone()
8865 .and_then(deserialize_anchor)
8866 .context("invalid inlay hints range start")?;
8867 let query_end = inlay_hints
8868 .end
8869 .clone()
8870 .and_then(deserialize_anchor)
8871 .context("invalid inlay hints range end")?;
8872 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8873 &lsp_store,
8874 server_id,
8875 lsp_request_id,
8876 &inlay_hints,
8877 query_start..query_end,
8878 &mut cx,
8879 )
8880 .await
8881 .context("preparing inlay hints request")?;
8882 Self::query_lsp_locally::<InlayHints>(
8883 lsp_store,
8884 server_id,
8885 sender_id,
8886 lsp_request_id,
8887 inlay_hints,
8888 None,
8889 &mut cx,
8890 )
8891 .await
8892 .context("querying for inlay hints")?
8893 }
8894 }
8895 Ok(proto::Ack {})
8896 }
8897
8898 async fn handle_lsp_query_response(
8899 lsp_store: Entity<Self>,
8900 envelope: TypedEnvelope<proto::LspQueryResponse>,
8901 cx: AsyncApp,
8902 ) -> Result<()> {
8903 lsp_store.read_with(&cx, |lsp_store, _| {
8904 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8905 upstream_client.handle_lsp_response(envelope.clone());
8906 }
8907 })?;
8908 Ok(())
8909 }
8910
8911 async fn handle_apply_code_action(
8912 this: Entity<Self>,
8913 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8914 mut cx: AsyncApp,
8915 ) -> Result<proto::ApplyCodeActionResponse> {
8916 let sender_id = envelope.original_sender_id().unwrap_or_default();
8917 let action =
8918 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8919 let apply_code_action = this.update(&mut cx, |this, cx| {
8920 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8921 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8922 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8923 })??;
8924
8925 let project_transaction = apply_code_action.await?;
8926 let project_transaction = this.update(&mut cx, |this, cx| {
8927 this.buffer_store.update(cx, |buffer_store, cx| {
8928 buffer_store.serialize_project_transaction_for_peer(
8929 project_transaction,
8930 sender_id,
8931 cx,
8932 )
8933 })
8934 })?;
8935 Ok(proto::ApplyCodeActionResponse {
8936 transaction: Some(project_transaction),
8937 })
8938 }
8939
8940 async fn handle_register_buffer_with_language_servers(
8941 this: Entity<Self>,
8942 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8943 mut cx: AsyncApp,
8944 ) -> Result<proto::Ack> {
8945 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8946 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8947 this.update(&mut cx, |this, cx| {
8948 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8949 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8950 project_id: upstream_project_id,
8951 buffer_id: buffer_id.to_proto(),
8952 only_servers: envelope.payload.only_servers,
8953 });
8954 }
8955
8956 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8957 anyhow::bail!("buffer is not open");
8958 };
8959
8960 let handle = this.register_buffer_with_language_servers(
8961 &buffer,
8962 envelope
8963 .payload
8964 .only_servers
8965 .into_iter()
8966 .filter_map(|selector| {
8967 Some(match selector.selector? {
8968 proto::language_server_selector::Selector::ServerId(server_id) => {
8969 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8970 }
8971 proto::language_server_selector::Selector::Name(name) => {
8972 LanguageServerSelector::Name(LanguageServerName(
8973 SharedString::from(name),
8974 ))
8975 }
8976 })
8977 })
8978 .collect(),
8979 false,
8980 cx,
8981 );
8982 this.buffer_store().update(cx, |buffer_store, _| {
8983 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8984 });
8985
8986 Ok(())
8987 })??;
8988 Ok(proto::Ack {})
8989 }
8990
8991 async fn handle_rename_project_entry(
8992 this: Entity<Self>,
8993 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8994 mut cx: AsyncApp,
8995 ) -> Result<proto::ProjectEntryResponse> {
8996 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8997 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8998 let new_path =
8999 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9000
9001 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9002 .update(&mut cx, |this, cx| {
9003 let (worktree, entry) = this
9004 .worktree_store
9005 .read(cx)
9006 .worktree_and_entry_for_id(entry_id, cx)?;
9007 let new_worktree = this
9008 .worktree_store
9009 .read(cx)
9010 .worktree_for_id(new_worktree_id, cx)?;
9011 Some((
9012 this.worktree_store.clone(),
9013 worktree,
9014 new_worktree,
9015 entry.clone(),
9016 ))
9017 })?
9018 .context("worktree not found")?;
9019 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9020 (worktree.absolutize(&old_entry.path), worktree.id())
9021 })?;
9022 let new_abs_path =
9023 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9024
9025 let _transaction = Self::will_rename_entry(
9026 this.downgrade(),
9027 old_worktree_id,
9028 &old_abs_path,
9029 &new_abs_path,
9030 old_entry.is_dir(),
9031 cx.clone(),
9032 )
9033 .await;
9034 let response = WorktreeStore::handle_rename_project_entry(
9035 worktree_store,
9036 envelope.payload,
9037 cx.clone(),
9038 )
9039 .await;
9040 this.read_with(&cx, |this, _| {
9041 this.did_rename_entry(
9042 old_worktree_id,
9043 &old_abs_path,
9044 &new_abs_path,
9045 old_entry.is_dir(),
9046 );
9047 })
9048 .ok();
9049 response
9050 }
9051
9052 async fn handle_update_diagnostic_summary(
9053 this: Entity<Self>,
9054 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9055 mut cx: AsyncApp,
9056 ) -> Result<()> {
9057 this.update(&mut cx, |lsp_store, cx| {
9058 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9059 let mut updated_diagnostics_paths = HashMap::default();
9060 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9061 for message_summary in envelope
9062 .payload
9063 .summary
9064 .into_iter()
9065 .chain(envelope.payload.more_summaries)
9066 {
9067 let project_path = ProjectPath {
9068 worktree_id,
9069 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9070 };
9071 let path = project_path.path.clone();
9072 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9073 let summary = DiagnosticSummary {
9074 error_count: message_summary.error_count as usize,
9075 warning_count: message_summary.warning_count as usize,
9076 };
9077
9078 if summary.is_empty() {
9079 if let Some(worktree_summaries) =
9080 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9081 && let Some(summaries) = worktree_summaries.get_mut(&path)
9082 {
9083 summaries.remove(&server_id);
9084 if summaries.is_empty() {
9085 worktree_summaries.remove(&path);
9086 }
9087 }
9088 } else {
9089 lsp_store
9090 .diagnostic_summaries
9091 .entry(worktree_id)
9092 .or_default()
9093 .entry(path)
9094 .or_default()
9095 .insert(server_id, summary);
9096 }
9097
9098 if let Some((_, project_id)) = &lsp_store.downstream_client {
9099 match &mut diagnostics_summary {
9100 Some(diagnostics_summary) => {
9101 diagnostics_summary
9102 .more_summaries
9103 .push(proto::DiagnosticSummary {
9104 path: project_path.path.as_ref().to_proto(),
9105 language_server_id: server_id.0 as u64,
9106 error_count: summary.error_count as u32,
9107 warning_count: summary.warning_count as u32,
9108 })
9109 }
9110 None => {
9111 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9112 project_id: *project_id,
9113 worktree_id: worktree_id.to_proto(),
9114 summary: Some(proto::DiagnosticSummary {
9115 path: project_path.path.as_ref().to_proto(),
9116 language_server_id: server_id.0 as u64,
9117 error_count: summary.error_count as u32,
9118 warning_count: summary.warning_count as u32,
9119 }),
9120 more_summaries: Vec::new(),
9121 })
9122 }
9123 }
9124 }
9125 updated_diagnostics_paths
9126 .entry(server_id)
9127 .or_insert_with(Vec::new)
9128 .push(project_path);
9129 }
9130
9131 if let Some((diagnostics_summary, (downstream_client, _))) =
9132 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9133 {
9134 downstream_client.send(diagnostics_summary).log_err();
9135 }
9136 for (server_id, paths) in updated_diagnostics_paths {
9137 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9138 }
9139 Ok(())
9140 })?
9141 }
9142
9143 async fn handle_start_language_server(
9144 lsp_store: Entity<Self>,
9145 envelope: TypedEnvelope<proto::StartLanguageServer>,
9146 mut cx: AsyncApp,
9147 ) -> Result<()> {
9148 let server = envelope.payload.server.context("invalid server")?;
9149 let server_capabilities =
9150 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9151 .with_context(|| {
9152 format!(
9153 "incorrect server capabilities {}",
9154 envelope.payload.capabilities
9155 )
9156 })?;
9157 lsp_store.update(&mut cx, |lsp_store, cx| {
9158 let server_id = LanguageServerId(server.id as usize);
9159 let server_name = LanguageServerName::from_proto(server.name.clone());
9160 lsp_store
9161 .lsp_server_capabilities
9162 .insert(server_id, server_capabilities);
9163 lsp_store.language_server_statuses.insert(
9164 server_id,
9165 LanguageServerStatus {
9166 name: server_name.clone(),
9167 pending_work: Default::default(),
9168 has_pending_diagnostic_updates: false,
9169 progress_tokens: Default::default(),
9170 worktree: server.worktree_id.map(WorktreeId::from_proto),
9171 binary: None,
9172 configuration: None,
9173 workspace_folders: BTreeSet::new(),
9174 },
9175 );
9176 cx.emit(LspStoreEvent::LanguageServerAdded(
9177 server_id,
9178 server_name,
9179 server.worktree_id.map(WorktreeId::from_proto),
9180 ));
9181 cx.notify();
9182 })?;
9183 Ok(())
9184 }
9185
9186 async fn handle_update_language_server(
9187 lsp_store: Entity<Self>,
9188 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9189 mut cx: AsyncApp,
9190 ) -> Result<()> {
9191 lsp_store.update(&mut cx, |lsp_store, cx| {
9192 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9193
9194 match envelope.payload.variant.context("invalid variant")? {
9195 proto::update_language_server::Variant::WorkStart(payload) => {
9196 lsp_store.on_lsp_work_start(
9197 language_server_id,
9198 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9199 .context("invalid progress token value")?,
9200 LanguageServerProgress {
9201 title: payload.title,
9202 is_disk_based_diagnostics_progress: false,
9203 is_cancellable: payload.is_cancellable.unwrap_or(false),
9204 message: payload.message,
9205 percentage: payload.percentage.map(|p| p as usize),
9206 last_update_at: cx.background_executor().now(),
9207 },
9208 cx,
9209 );
9210 }
9211 proto::update_language_server::Variant::WorkProgress(payload) => {
9212 lsp_store.on_lsp_work_progress(
9213 language_server_id,
9214 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9215 .context("invalid progress token value")?,
9216 LanguageServerProgress {
9217 title: None,
9218 is_disk_based_diagnostics_progress: false,
9219 is_cancellable: payload.is_cancellable.unwrap_or(false),
9220 message: payload.message,
9221 percentage: payload.percentage.map(|p| p as usize),
9222 last_update_at: cx.background_executor().now(),
9223 },
9224 cx,
9225 );
9226 }
9227
9228 proto::update_language_server::Variant::WorkEnd(payload) => {
9229 lsp_store.on_lsp_work_end(
9230 language_server_id,
9231 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9232 .context("invalid progress token value")?,
9233 cx,
9234 );
9235 }
9236
9237 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9238 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9239 }
9240
9241 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9242 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9243 }
9244
9245 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9246 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9247 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9248 cx.emit(LspStoreEvent::LanguageServerUpdate {
9249 language_server_id,
9250 name: envelope
9251 .payload
9252 .server_name
9253 .map(SharedString::new)
9254 .map(LanguageServerName),
9255 message: non_lsp,
9256 });
9257 }
9258 }
9259
9260 Ok(())
9261 })?
9262 }
9263
9264 async fn handle_language_server_log(
9265 this: Entity<Self>,
9266 envelope: TypedEnvelope<proto::LanguageServerLog>,
9267 mut cx: AsyncApp,
9268 ) -> Result<()> {
9269 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9270 let log_type = envelope
9271 .payload
9272 .log_type
9273 .map(LanguageServerLogType::from_proto)
9274 .context("invalid language server log type")?;
9275
9276 let message = envelope.payload.message;
9277
9278 this.update(&mut cx, |_, cx| {
9279 cx.emit(LspStoreEvent::LanguageServerLog(
9280 language_server_id,
9281 log_type,
9282 message,
9283 ));
9284 })
9285 }
9286
9287 async fn handle_lsp_ext_cancel_flycheck(
9288 lsp_store: Entity<Self>,
9289 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9290 cx: AsyncApp,
9291 ) -> Result<proto::Ack> {
9292 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9293 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9294 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9295 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9296 } else {
9297 None
9298 }
9299 })?;
9300 if let Some(task) = task {
9301 task.context("handling lsp ext cancel flycheck")?;
9302 }
9303
9304 Ok(proto::Ack {})
9305 }
9306
9307 async fn handle_lsp_ext_run_flycheck(
9308 lsp_store: Entity<Self>,
9309 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9310 mut cx: AsyncApp,
9311 ) -> Result<proto::Ack> {
9312 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9313 lsp_store.update(&mut cx, |lsp_store, cx| {
9314 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9315 let text_document = if envelope.payload.current_file_only {
9316 let buffer_id = envelope
9317 .payload
9318 .buffer_id
9319 .map(|id| BufferId::new(id))
9320 .transpose()?;
9321 buffer_id
9322 .and_then(|buffer_id| {
9323 lsp_store
9324 .buffer_store()
9325 .read(cx)
9326 .get(buffer_id)
9327 .and_then(|buffer| {
9328 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9329 })
9330 .map(|path| make_text_document_identifier(&path))
9331 })
9332 .transpose()?
9333 } else {
9334 None
9335 };
9336 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9337 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9338 )?;
9339 }
9340 anyhow::Ok(())
9341 })??;
9342
9343 Ok(proto::Ack {})
9344 }
9345
9346 async fn handle_lsp_ext_clear_flycheck(
9347 lsp_store: Entity<Self>,
9348 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9349 cx: AsyncApp,
9350 ) -> Result<proto::Ack> {
9351 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9352 lsp_store
9353 .read_with(&cx, |lsp_store, _| {
9354 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9355 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9356 } else {
9357 None
9358 }
9359 })
9360 .context("handling lsp ext clear flycheck")?;
9361
9362 Ok(proto::Ack {})
9363 }
9364
9365 pub fn disk_based_diagnostics_started(
9366 &mut self,
9367 language_server_id: LanguageServerId,
9368 cx: &mut Context<Self>,
9369 ) {
9370 if let Some(language_server_status) =
9371 self.language_server_statuses.get_mut(&language_server_id)
9372 {
9373 language_server_status.has_pending_diagnostic_updates = true;
9374 }
9375
9376 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9377 cx.emit(LspStoreEvent::LanguageServerUpdate {
9378 language_server_id,
9379 name: self
9380 .language_server_adapter_for_id(language_server_id)
9381 .map(|adapter| adapter.name()),
9382 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9383 Default::default(),
9384 ),
9385 })
9386 }
9387
9388 pub fn disk_based_diagnostics_finished(
9389 &mut self,
9390 language_server_id: LanguageServerId,
9391 cx: &mut Context<Self>,
9392 ) {
9393 if let Some(language_server_status) =
9394 self.language_server_statuses.get_mut(&language_server_id)
9395 {
9396 language_server_status.has_pending_diagnostic_updates = false;
9397 }
9398
9399 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9400 cx.emit(LspStoreEvent::LanguageServerUpdate {
9401 language_server_id,
9402 name: self
9403 .language_server_adapter_for_id(language_server_id)
9404 .map(|adapter| adapter.name()),
9405 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9406 Default::default(),
9407 ),
9408 })
9409 }
9410
9411 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9412 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9413 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9414 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9415 // the language server might take some time to publish diagnostics.
9416 fn simulate_disk_based_diagnostics_events_if_needed(
9417 &mut self,
9418 language_server_id: LanguageServerId,
9419 cx: &mut Context<Self>,
9420 ) {
9421 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9422
9423 let Some(LanguageServerState::Running {
9424 simulate_disk_based_diagnostics_completion,
9425 adapter,
9426 ..
9427 }) = self
9428 .as_local_mut()
9429 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9430 else {
9431 return;
9432 };
9433
9434 if adapter.disk_based_diagnostics_progress_token.is_some() {
9435 return;
9436 }
9437
9438 let prev_task =
9439 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9440 cx.background_executor()
9441 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9442 .await;
9443
9444 this.update(cx, |this, cx| {
9445 this.disk_based_diagnostics_finished(language_server_id, cx);
9446
9447 if let Some(LanguageServerState::Running {
9448 simulate_disk_based_diagnostics_completion,
9449 ..
9450 }) = this.as_local_mut().and_then(|local_store| {
9451 local_store.language_servers.get_mut(&language_server_id)
9452 }) {
9453 *simulate_disk_based_diagnostics_completion = None;
9454 }
9455 })
9456 .ok();
9457 }));
9458
9459 if prev_task.is_none() {
9460 self.disk_based_diagnostics_started(language_server_id, cx);
9461 }
9462 }
9463
9464 pub fn language_server_statuses(
9465 &self,
9466 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9467 self.language_server_statuses
9468 .iter()
9469 .map(|(key, value)| (*key, value))
9470 }
9471
9472 pub(super) fn did_rename_entry(
9473 &self,
9474 worktree_id: WorktreeId,
9475 old_path: &Path,
9476 new_path: &Path,
9477 is_dir: bool,
9478 ) {
9479 maybe!({
9480 let local_store = self.as_local()?;
9481
9482 let old_uri = lsp::Uri::from_file_path(old_path)
9483 .ok()
9484 .map(|uri| uri.to_string())?;
9485 let new_uri = lsp::Uri::from_file_path(new_path)
9486 .ok()
9487 .map(|uri| uri.to_string())?;
9488
9489 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9490 let Some(filter) = local_store
9491 .language_server_paths_watched_for_rename
9492 .get(&language_server.server_id())
9493 else {
9494 continue;
9495 };
9496
9497 if filter.should_send_did_rename(&old_uri, is_dir) {
9498 language_server
9499 .notify::<DidRenameFiles>(RenameFilesParams {
9500 files: vec![FileRename {
9501 old_uri: old_uri.clone(),
9502 new_uri: new_uri.clone(),
9503 }],
9504 })
9505 .ok();
9506 }
9507 }
9508 Some(())
9509 });
9510 }
9511
9512 pub(super) fn will_rename_entry(
9513 this: WeakEntity<Self>,
9514 worktree_id: WorktreeId,
9515 old_path: &Path,
9516 new_path: &Path,
9517 is_dir: bool,
9518 cx: AsyncApp,
9519 ) -> Task<ProjectTransaction> {
9520 let old_uri = lsp::Uri::from_file_path(old_path)
9521 .ok()
9522 .map(|uri| uri.to_string());
9523 let new_uri = lsp::Uri::from_file_path(new_path)
9524 .ok()
9525 .map(|uri| uri.to_string());
9526 cx.spawn(async move |cx| {
9527 let mut tasks = vec![];
9528 this.update(cx, |this, cx| {
9529 let local_store = this.as_local()?;
9530 let old_uri = old_uri?;
9531 let new_uri = new_uri?;
9532 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9533 let Some(filter) = local_store
9534 .language_server_paths_watched_for_rename
9535 .get(&language_server.server_id())
9536 else {
9537 continue;
9538 };
9539
9540 if filter.should_send_will_rename(&old_uri, is_dir) {
9541 let apply_edit = cx.spawn({
9542 let old_uri = old_uri.clone();
9543 let new_uri = new_uri.clone();
9544 let language_server = language_server.clone();
9545 async move |this, cx| {
9546 let edit = language_server
9547 .request::<WillRenameFiles>(RenameFilesParams {
9548 files: vec![FileRename { old_uri, new_uri }],
9549 })
9550 .await
9551 .into_response()
9552 .context("will rename files")
9553 .log_err()
9554 .flatten()?;
9555
9556 let transaction = LocalLspStore::deserialize_workspace_edit(
9557 this.upgrade()?,
9558 edit,
9559 false,
9560 language_server.clone(),
9561 cx,
9562 )
9563 .await
9564 .ok()?;
9565 Some(transaction)
9566 }
9567 });
9568 tasks.push(apply_edit);
9569 }
9570 }
9571 Some(())
9572 })
9573 .ok()
9574 .flatten();
9575 let mut merged_transaction = ProjectTransaction::default();
9576 for task in tasks {
9577 // Await on tasks sequentially so that the order of application of edits is deterministic
9578 // (at least with regards to the order of registration of language servers)
9579 if let Some(transaction) = task.await {
9580 for (buffer, buffer_transaction) in transaction.0 {
9581 merged_transaction.0.insert(buffer, buffer_transaction);
9582 }
9583 }
9584 }
9585 merged_transaction
9586 })
9587 }
9588
9589 fn lsp_notify_abs_paths_changed(
9590 &mut self,
9591 server_id: LanguageServerId,
9592 changes: Vec<PathEvent>,
9593 ) {
9594 maybe!({
9595 let server = self.language_server_for_id(server_id)?;
9596 let changes = changes
9597 .into_iter()
9598 .filter_map(|event| {
9599 let typ = match event.kind? {
9600 PathEventKind::Created => lsp::FileChangeType::CREATED,
9601 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9602 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9603 };
9604 Some(lsp::FileEvent {
9605 uri: file_path_to_lsp_url(&event.path).log_err()?,
9606 typ,
9607 })
9608 })
9609 .collect::<Vec<_>>();
9610 if !changes.is_empty() {
9611 server
9612 .notify::<lsp::notification::DidChangeWatchedFiles>(
9613 lsp::DidChangeWatchedFilesParams { changes },
9614 )
9615 .ok();
9616 }
9617 Some(())
9618 });
9619 }
9620
9621 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9622 self.as_local()?.language_server_for_id(id)
9623 }
9624
9625 fn on_lsp_progress(
9626 &mut self,
9627 progress_params: lsp::ProgressParams,
9628 language_server_id: LanguageServerId,
9629 disk_based_diagnostics_progress_token: Option<String>,
9630 cx: &mut Context<Self>,
9631 ) {
9632 match progress_params.value {
9633 lsp::ProgressParamsValue::WorkDone(progress) => {
9634 self.handle_work_done_progress(
9635 progress,
9636 language_server_id,
9637 disk_based_diagnostics_progress_token,
9638 ProgressToken::from_lsp(progress_params.token),
9639 cx,
9640 );
9641 }
9642 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9643 let identifier = match progress_params.token {
9644 lsp::NumberOrString::Number(_) => None,
9645 lsp::NumberOrString::String(token) => token
9646 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9647 .map(|(_, id)| id.to_owned()),
9648 };
9649 if let Some(LanguageServerState::Running {
9650 workspace_diagnostics_refresh_tasks,
9651 ..
9652 }) = self
9653 .as_local_mut()
9654 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9655 && let Some(workspace_diagnostics) =
9656 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9657 {
9658 workspace_diagnostics.progress_tx.try_send(()).ok();
9659 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9660 }
9661 }
9662 }
9663 }
9664
9665 fn handle_work_done_progress(
9666 &mut self,
9667 progress: lsp::WorkDoneProgress,
9668 language_server_id: LanguageServerId,
9669 disk_based_diagnostics_progress_token: Option<String>,
9670 token: ProgressToken,
9671 cx: &mut Context<Self>,
9672 ) {
9673 let language_server_status =
9674 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9675 status
9676 } else {
9677 return;
9678 };
9679
9680 if !language_server_status.progress_tokens.contains(&token) {
9681 return;
9682 }
9683
9684 let is_disk_based_diagnostics_progress =
9685 if let (Some(disk_based_token), ProgressToken::String(token)) =
9686 (&disk_based_diagnostics_progress_token, &token)
9687 {
9688 token.starts_with(disk_based_token)
9689 } else {
9690 false
9691 };
9692
9693 match progress {
9694 lsp::WorkDoneProgress::Begin(report) => {
9695 if is_disk_based_diagnostics_progress {
9696 self.disk_based_diagnostics_started(language_server_id, cx);
9697 }
9698 self.on_lsp_work_start(
9699 language_server_id,
9700 token.clone(),
9701 LanguageServerProgress {
9702 title: Some(report.title),
9703 is_disk_based_diagnostics_progress,
9704 is_cancellable: report.cancellable.unwrap_or(false),
9705 message: report.message.clone(),
9706 percentage: report.percentage.map(|p| p as usize),
9707 last_update_at: cx.background_executor().now(),
9708 },
9709 cx,
9710 );
9711 }
9712 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9713 language_server_id,
9714 token,
9715 LanguageServerProgress {
9716 title: None,
9717 is_disk_based_diagnostics_progress,
9718 is_cancellable: report.cancellable.unwrap_or(false),
9719 message: report.message,
9720 percentage: report.percentage.map(|p| p as usize),
9721 last_update_at: cx.background_executor().now(),
9722 },
9723 cx,
9724 ),
9725 lsp::WorkDoneProgress::End(_) => {
9726 language_server_status.progress_tokens.remove(&token);
9727 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9728 if is_disk_based_diagnostics_progress {
9729 self.disk_based_diagnostics_finished(language_server_id, cx);
9730 }
9731 }
9732 }
9733 }
9734
9735 fn on_lsp_work_start(
9736 &mut self,
9737 language_server_id: LanguageServerId,
9738 token: ProgressToken,
9739 progress: LanguageServerProgress,
9740 cx: &mut Context<Self>,
9741 ) {
9742 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9743 status.pending_work.insert(token.clone(), progress.clone());
9744 cx.notify();
9745 }
9746 cx.emit(LspStoreEvent::LanguageServerUpdate {
9747 language_server_id,
9748 name: self
9749 .language_server_adapter_for_id(language_server_id)
9750 .map(|adapter| adapter.name()),
9751 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9752 token: Some(token.to_proto()),
9753 title: progress.title,
9754 message: progress.message,
9755 percentage: progress.percentage.map(|p| p as u32),
9756 is_cancellable: Some(progress.is_cancellable),
9757 }),
9758 })
9759 }
9760
9761 fn on_lsp_work_progress(
9762 &mut self,
9763 language_server_id: LanguageServerId,
9764 token: ProgressToken,
9765 progress: LanguageServerProgress,
9766 cx: &mut Context<Self>,
9767 ) {
9768 let mut did_update = false;
9769 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9770 match status.pending_work.entry(token.clone()) {
9771 btree_map::Entry::Vacant(entry) => {
9772 entry.insert(progress.clone());
9773 did_update = true;
9774 }
9775 btree_map::Entry::Occupied(mut entry) => {
9776 let entry = entry.get_mut();
9777 if (progress.last_update_at - entry.last_update_at)
9778 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9779 {
9780 entry.last_update_at = progress.last_update_at;
9781 if progress.message.is_some() {
9782 entry.message = progress.message.clone();
9783 }
9784 if progress.percentage.is_some() {
9785 entry.percentage = progress.percentage;
9786 }
9787 if progress.is_cancellable != entry.is_cancellable {
9788 entry.is_cancellable = progress.is_cancellable;
9789 }
9790 did_update = true;
9791 }
9792 }
9793 }
9794 }
9795
9796 if did_update {
9797 cx.emit(LspStoreEvent::LanguageServerUpdate {
9798 language_server_id,
9799 name: self
9800 .language_server_adapter_for_id(language_server_id)
9801 .map(|adapter| adapter.name()),
9802 message: proto::update_language_server::Variant::WorkProgress(
9803 proto::LspWorkProgress {
9804 token: Some(token.to_proto()),
9805 message: progress.message,
9806 percentage: progress.percentage.map(|p| p as u32),
9807 is_cancellable: Some(progress.is_cancellable),
9808 },
9809 ),
9810 })
9811 }
9812 }
9813
9814 fn on_lsp_work_end(
9815 &mut self,
9816 language_server_id: LanguageServerId,
9817 token: ProgressToken,
9818 cx: &mut Context<Self>,
9819 ) {
9820 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9821 if let Some(work) = status.pending_work.remove(&token)
9822 && !work.is_disk_based_diagnostics_progress
9823 {
9824 cx.emit(LspStoreEvent::RefreshInlayHints {
9825 server_id: language_server_id,
9826 request_id: None,
9827 });
9828 }
9829 cx.notify();
9830 }
9831
9832 cx.emit(LspStoreEvent::LanguageServerUpdate {
9833 language_server_id,
9834 name: self
9835 .language_server_adapter_for_id(language_server_id)
9836 .map(|adapter| adapter.name()),
9837 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9838 token: Some(token.to_proto()),
9839 }),
9840 })
9841 }
9842
9843 pub async fn handle_resolve_completion_documentation(
9844 this: Entity<Self>,
9845 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9846 mut cx: AsyncApp,
9847 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9848 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9849
9850 let completion = this
9851 .read_with(&cx, |this, cx| {
9852 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9853 let server = this
9854 .language_server_for_id(id)
9855 .with_context(|| format!("No language server {id}"))?;
9856
9857 anyhow::Ok(cx.background_spawn(async move {
9858 let can_resolve = server
9859 .capabilities()
9860 .completion_provider
9861 .as_ref()
9862 .and_then(|options| options.resolve_provider)
9863 .unwrap_or(false);
9864 if can_resolve {
9865 server
9866 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9867 .await
9868 .into_response()
9869 .context("resolve completion item")
9870 } else {
9871 anyhow::Ok(lsp_completion)
9872 }
9873 }))
9874 })??
9875 .await?;
9876
9877 let mut documentation_is_markdown = false;
9878 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9879 let documentation = match completion.documentation {
9880 Some(lsp::Documentation::String(text)) => text,
9881
9882 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9883 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9884 value
9885 }
9886
9887 _ => String::new(),
9888 };
9889
9890 // If we have a new buffer_id, that means we're talking to a new client
9891 // and want to check for new text_edits in the completion too.
9892 let mut old_replace_start = None;
9893 let mut old_replace_end = None;
9894 let mut old_insert_start = None;
9895 let mut old_insert_end = None;
9896 let mut new_text = String::default();
9897 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9898 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9899 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9900 anyhow::Ok(buffer.read(cx).snapshot())
9901 })??;
9902
9903 if let Some(text_edit) = completion.text_edit.as_ref() {
9904 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9905
9906 if let Some(mut edit) = edit {
9907 LineEnding::normalize(&mut edit.new_text);
9908
9909 new_text = edit.new_text;
9910 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9911 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9912 if let Some(insert_range) = edit.insert_range {
9913 old_insert_start = Some(serialize_anchor(&insert_range.start));
9914 old_insert_end = Some(serialize_anchor(&insert_range.end));
9915 }
9916 }
9917 }
9918 }
9919
9920 Ok(proto::ResolveCompletionDocumentationResponse {
9921 documentation,
9922 documentation_is_markdown,
9923 old_replace_start,
9924 old_replace_end,
9925 new_text,
9926 lsp_completion,
9927 old_insert_start,
9928 old_insert_end,
9929 })
9930 }
9931
9932 async fn handle_on_type_formatting(
9933 this: Entity<Self>,
9934 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9935 mut cx: AsyncApp,
9936 ) -> Result<proto::OnTypeFormattingResponse> {
9937 let on_type_formatting = this.update(&mut cx, |this, cx| {
9938 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9939 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9940 let position = envelope
9941 .payload
9942 .position
9943 .and_then(deserialize_anchor)
9944 .context("invalid position")?;
9945 anyhow::Ok(this.apply_on_type_formatting(
9946 buffer,
9947 position,
9948 envelope.payload.trigger.clone(),
9949 cx,
9950 ))
9951 })??;
9952
9953 let transaction = on_type_formatting
9954 .await?
9955 .as_ref()
9956 .map(language::proto::serialize_transaction);
9957 Ok(proto::OnTypeFormattingResponse { transaction })
9958 }
9959
9960 async fn handle_refresh_inlay_hints(
9961 lsp_store: Entity<Self>,
9962 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9963 mut cx: AsyncApp,
9964 ) -> Result<proto::Ack> {
9965 lsp_store.update(&mut cx, |_, cx| {
9966 cx.emit(LspStoreEvent::RefreshInlayHints {
9967 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9968 request_id: envelope.payload.request_id.map(|id| id as usize),
9969 });
9970 })?;
9971 Ok(proto::Ack {})
9972 }
9973
9974 async fn handle_pull_workspace_diagnostics(
9975 lsp_store: Entity<Self>,
9976 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9977 mut cx: AsyncApp,
9978 ) -> Result<proto::Ack> {
9979 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9980 lsp_store.update(&mut cx, |lsp_store, _| {
9981 lsp_store.pull_workspace_diagnostics(server_id);
9982 })?;
9983 Ok(proto::Ack {})
9984 }
9985
9986 async fn handle_get_color_presentation(
9987 lsp_store: Entity<Self>,
9988 envelope: TypedEnvelope<proto::GetColorPresentation>,
9989 mut cx: AsyncApp,
9990 ) -> Result<proto::GetColorPresentationResponse> {
9991 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9992 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9993 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9994 })??;
9995
9996 let color = envelope
9997 .payload
9998 .color
9999 .context("invalid color resolve request")?;
10000 let start = color
10001 .lsp_range_start
10002 .context("invalid color resolve request")?;
10003 let end = color
10004 .lsp_range_end
10005 .context("invalid color resolve request")?;
10006
10007 let color = DocumentColor {
10008 lsp_range: lsp::Range {
10009 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10010 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10011 },
10012 color: lsp::Color {
10013 red: color.red,
10014 green: color.green,
10015 blue: color.blue,
10016 alpha: color.alpha,
10017 },
10018 resolved: false,
10019 color_presentations: Vec::new(),
10020 };
10021 let resolved_color = lsp_store
10022 .update(&mut cx, |lsp_store, cx| {
10023 lsp_store.resolve_color_presentation(
10024 color,
10025 buffer.clone(),
10026 LanguageServerId(envelope.payload.server_id as usize),
10027 cx,
10028 )
10029 })?
10030 .await
10031 .context("resolving color presentation")?;
10032
10033 Ok(proto::GetColorPresentationResponse {
10034 presentations: resolved_color
10035 .color_presentations
10036 .into_iter()
10037 .map(|presentation| proto::ColorPresentation {
10038 label: presentation.label.to_string(),
10039 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10040 additional_text_edits: presentation
10041 .additional_text_edits
10042 .into_iter()
10043 .map(serialize_lsp_edit)
10044 .collect(),
10045 })
10046 .collect(),
10047 })
10048 }
10049
10050 async fn handle_resolve_inlay_hint(
10051 lsp_store: Entity<Self>,
10052 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10053 mut cx: AsyncApp,
10054 ) -> Result<proto::ResolveInlayHintResponse> {
10055 let proto_hint = envelope
10056 .payload
10057 .hint
10058 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10059 let hint = InlayHints::proto_to_project_hint(proto_hint)
10060 .context("resolved proto inlay hint conversion")?;
10061 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10062 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10063 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10064 })??;
10065 let response_hint = lsp_store
10066 .update(&mut cx, |lsp_store, cx| {
10067 lsp_store.resolve_inlay_hint(
10068 hint,
10069 buffer,
10070 LanguageServerId(envelope.payload.language_server_id as usize),
10071 cx,
10072 )
10073 })?
10074 .await
10075 .context("inlay hints fetch")?;
10076 Ok(proto::ResolveInlayHintResponse {
10077 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10078 })
10079 }
10080
10081 async fn handle_refresh_code_lens(
10082 this: Entity<Self>,
10083 _: TypedEnvelope<proto::RefreshCodeLens>,
10084 mut cx: AsyncApp,
10085 ) -> Result<proto::Ack> {
10086 this.update(&mut cx, |_, cx| {
10087 cx.emit(LspStoreEvent::RefreshCodeLens);
10088 })?;
10089 Ok(proto::Ack {})
10090 }
10091
10092 async fn handle_open_buffer_for_symbol(
10093 this: Entity<Self>,
10094 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10095 mut cx: AsyncApp,
10096 ) -> Result<proto::OpenBufferForSymbolResponse> {
10097 let peer_id = envelope.original_sender_id().unwrap_or_default();
10098 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10099 let symbol = Self::deserialize_symbol(symbol)?;
10100 this.read_with(&cx, |this, _| {
10101 if let SymbolLocation::OutsideProject {
10102 abs_path,
10103 signature,
10104 } = &symbol.path
10105 {
10106 let new_signature = this.symbol_signature(&abs_path);
10107 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10108 }
10109 Ok(())
10110 })??;
10111 let buffer = this
10112 .update(&mut cx, |this, cx| {
10113 this.open_buffer_for_symbol(
10114 &Symbol {
10115 language_server_name: symbol.language_server_name,
10116 source_worktree_id: symbol.source_worktree_id,
10117 source_language_server_id: symbol.source_language_server_id,
10118 path: symbol.path,
10119 name: symbol.name,
10120 kind: symbol.kind,
10121 range: symbol.range,
10122 label: CodeLabel::default(),
10123 },
10124 cx,
10125 )
10126 })?
10127 .await?;
10128
10129 this.update(&mut cx, |this, cx| {
10130 let is_private = buffer
10131 .read(cx)
10132 .file()
10133 .map(|f| f.is_private())
10134 .unwrap_or_default();
10135 if is_private {
10136 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10137 } else {
10138 this.buffer_store
10139 .update(cx, |buffer_store, cx| {
10140 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10141 })
10142 .detach_and_log_err(cx);
10143 let buffer_id = buffer.read(cx).remote_id().to_proto();
10144 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10145 }
10146 })?
10147 }
10148
10149 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10150 let mut hasher = Sha256::new();
10151 hasher.update(abs_path.to_string_lossy().as_bytes());
10152 hasher.update(self.nonce.to_be_bytes());
10153 hasher.finalize().as_slice().try_into().unwrap()
10154 }
10155
10156 pub async fn handle_get_project_symbols(
10157 this: Entity<Self>,
10158 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10159 mut cx: AsyncApp,
10160 ) -> Result<proto::GetProjectSymbolsResponse> {
10161 let symbols = this
10162 .update(&mut cx, |this, cx| {
10163 this.symbols(&envelope.payload.query, cx)
10164 })?
10165 .await?;
10166
10167 Ok(proto::GetProjectSymbolsResponse {
10168 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10169 })
10170 }
10171
10172 pub async fn handle_restart_language_servers(
10173 this: Entity<Self>,
10174 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10175 mut cx: AsyncApp,
10176 ) -> Result<proto::Ack> {
10177 this.update(&mut cx, |lsp_store, cx| {
10178 let buffers =
10179 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10180 lsp_store.restart_language_servers_for_buffers(
10181 buffers,
10182 envelope
10183 .payload
10184 .only_servers
10185 .into_iter()
10186 .filter_map(|selector| {
10187 Some(match selector.selector? {
10188 proto::language_server_selector::Selector::ServerId(server_id) => {
10189 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10190 }
10191 proto::language_server_selector::Selector::Name(name) => {
10192 LanguageServerSelector::Name(LanguageServerName(
10193 SharedString::from(name),
10194 ))
10195 }
10196 })
10197 })
10198 .collect(),
10199 cx,
10200 );
10201 })?;
10202
10203 Ok(proto::Ack {})
10204 }
10205
10206 pub async fn handle_stop_language_servers(
10207 lsp_store: Entity<Self>,
10208 envelope: TypedEnvelope<proto::StopLanguageServers>,
10209 mut cx: AsyncApp,
10210 ) -> Result<proto::Ack> {
10211 lsp_store.update(&mut cx, |lsp_store, cx| {
10212 if envelope.payload.all
10213 && envelope.payload.also_servers.is_empty()
10214 && envelope.payload.buffer_ids.is_empty()
10215 {
10216 lsp_store.stop_all_language_servers(cx);
10217 } else {
10218 let buffers =
10219 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10220 lsp_store
10221 .stop_language_servers_for_buffers(
10222 buffers,
10223 envelope
10224 .payload
10225 .also_servers
10226 .into_iter()
10227 .filter_map(|selector| {
10228 Some(match selector.selector? {
10229 proto::language_server_selector::Selector::ServerId(
10230 server_id,
10231 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10232 server_id,
10233 )),
10234 proto::language_server_selector::Selector::Name(name) => {
10235 LanguageServerSelector::Name(LanguageServerName(
10236 SharedString::from(name),
10237 ))
10238 }
10239 })
10240 })
10241 .collect(),
10242 cx,
10243 )
10244 .detach_and_log_err(cx);
10245 }
10246 })?;
10247
10248 Ok(proto::Ack {})
10249 }
10250
10251 pub async fn handle_cancel_language_server_work(
10252 lsp_store: Entity<Self>,
10253 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10254 mut cx: AsyncApp,
10255 ) -> Result<proto::Ack> {
10256 lsp_store.update(&mut cx, |lsp_store, cx| {
10257 if let Some(work) = envelope.payload.work {
10258 match work {
10259 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10260 let buffers =
10261 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10262 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10263 }
10264 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10265 let server_id = LanguageServerId::from_proto(work.language_server_id);
10266 let token = work
10267 .token
10268 .map(|token| {
10269 ProgressToken::from_proto(token)
10270 .context("invalid work progress token")
10271 })
10272 .transpose()?;
10273 lsp_store.cancel_language_server_work(server_id, token, cx);
10274 }
10275 }
10276 }
10277 anyhow::Ok(())
10278 })??;
10279
10280 Ok(proto::Ack {})
10281 }
10282
10283 fn buffer_ids_to_buffers(
10284 &mut self,
10285 buffer_ids: impl Iterator<Item = u64>,
10286 cx: &mut Context<Self>,
10287 ) -> Vec<Entity<Buffer>> {
10288 buffer_ids
10289 .into_iter()
10290 .flat_map(|buffer_id| {
10291 self.buffer_store
10292 .read(cx)
10293 .get(BufferId::new(buffer_id).log_err()?)
10294 })
10295 .collect::<Vec<_>>()
10296 }
10297
10298 async fn handle_apply_additional_edits_for_completion(
10299 this: Entity<Self>,
10300 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10301 mut cx: AsyncApp,
10302 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10303 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10304 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10305 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10306 let completion = Self::deserialize_completion(
10307 envelope.payload.completion.context("invalid completion")?,
10308 )?;
10309 anyhow::Ok((buffer, completion))
10310 })??;
10311
10312 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10313 this.apply_additional_edits_for_completion(
10314 buffer,
10315 Rc::new(RefCell::new(Box::new([Completion {
10316 replace_range: completion.replace_range,
10317 new_text: completion.new_text,
10318 source: completion.source,
10319 documentation: None,
10320 label: CodeLabel::default(),
10321 match_start: None,
10322 snippet_deduplication_key: None,
10323 insert_text_mode: None,
10324 icon_path: None,
10325 confirm: None,
10326 }]))),
10327 0,
10328 false,
10329 cx,
10330 )
10331 })?;
10332
10333 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10334 transaction: apply_additional_edits
10335 .await?
10336 .as_ref()
10337 .map(language::proto::serialize_transaction),
10338 })
10339 }
10340
10341 pub fn last_formatting_failure(&self) -> Option<&str> {
10342 self.last_formatting_failure.as_deref()
10343 }
10344
10345 pub fn reset_last_formatting_failure(&mut self) {
10346 self.last_formatting_failure = None;
10347 }
10348
10349 pub fn environment_for_buffer(
10350 &self,
10351 buffer: &Entity<Buffer>,
10352 cx: &mut Context<Self>,
10353 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10354 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10355 environment.update(cx, |env, cx| {
10356 env.buffer_environment(buffer, &self.worktree_store, cx)
10357 })
10358 } else {
10359 Task::ready(None).shared()
10360 }
10361 }
10362
10363 pub fn format(
10364 &mut self,
10365 buffers: HashSet<Entity<Buffer>>,
10366 target: LspFormatTarget,
10367 push_to_history: bool,
10368 trigger: FormatTrigger,
10369 cx: &mut Context<Self>,
10370 ) -> Task<anyhow::Result<ProjectTransaction>> {
10371 let logger = zlog::scoped!("format");
10372 if self.as_local().is_some() {
10373 zlog::trace!(logger => "Formatting locally");
10374 let logger = zlog::scoped!(logger => "local");
10375 let buffers = buffers
10376 .into_iter()
10377 .map(|buffer_handle| {
10378 let buffer = buffer_handle.read(cx);
10379 let buffer_abs_path = File::from_dyn(buffer.file())
10380 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10381
10382 (buffer_handle, buffer_abs_path, buffer.remote_id())
10383 })
10384 .collect::<Vec<_>>();
10385
10386 cx.spawn(async move |lsp_store, cx| {
10387 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10388
10389 for (handle, abs_path, id) in buffers {
10390 let env = lsp_store
10391 .update(cx, |lsp_store, cx| {
10392 lsp_store.environment_for_buffer(&handle, cx)
10393 })?
10394 .await;
10395
10396 let ranges = match &target {
10397 LspFormatTarget::Buffers => None,
10398 LspFormatTarget::Ranges(ranges) => {
10399 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10400 }
10401 };
10402
10403 formattable_buffers.push(FormattableBuffer {
10404 handle,
10405 abs_path,
10406 env,
10407 ranges,
10408 });
10409 }
10410 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10411
10412 let format_timer = zlog::time!(logger => "Formatting buffers");
10413 let result = LocalLspStore::format_locally(
10414 lsp_store.clone(),
10415 formattable_buffers,
10416 push_to_history,
10417 trigger,
10418 logger,
10419 cx,
10420 )
10421 .await;
10422 format_timer.end();
10423
10424 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10425
10426 lsp_store.update(cx, |lsp_store, _| {
10427 lsp_store.update_last_formatting_failure(&result);
10428 })?;
10429
10430 result
10431 })
10432 } else if let Some((client, project_id)) = self.upstream_client() {
10433 zlog::trace!(logger => "Formatting remotely");
10434 let logger = zlog::scoped!(logger => "remote");
10435 // Don't support formatting ranges via remote
10436 match target {
10437 LspFormatTarget::Buffers => {}
10438 LspFormatTarget::Ranges(_) => {
10439 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10440 return Task::ready(Ok(ProjectTransaction::default()));
10441 }
10442 }
10443
10444 let buffer_store = self.buffer_store();
10445 cx.spawn(async move |lsp_store, cx| {
10446 zlog::trace!(logger => "Sending remote format request");
10447 let request_timer = zlog::time!(logger => "remote format request");
10448 let result = client
10449 .request(proto::FormatBuffers {
10450 project_id,
10451 trigger: trigger as i32,
10452 buffer_ids: buffers
10453 .iter()
10454 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10455 .collect::<Result<_>>()?,
10456 })
10457 .await
10458 .and_then(|result| result.transaction.context("missing transaction"));
10459 request_timer.end();
10460
10461 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10462
10463 lsp_store.update(cx, |lsp_store, _| {
10464 lsp_store.update_last_formatting_failure(&result);
10465 })?;
10466
10467 let transaction_response = result?;
10468 let _timer = zlog::time!(logger => "deserializing project transaction");
10469 buffer_store
10470 .update(cx, |buffer_store, cx| {
10471 buffer_store.deserialize_project_transaction(
10472 transaction_response,
10473 push_to_history,
10474 cx,
10475 )
10476 })?
10477 .await
10478 })
10479 } else {
10480 zlog::trace!(logger => "Not formatting");
10481 Task::ready(Ok(ProjectTransaction::default()))
10482 }
10483 }
10484
10485 async fn handle_format_buffers(
10486 this: Entity<Self>,
10487 envelope: TypedEnvelope<proto::FormatBuffers>,
10488 mut cx: AsyncApp,
10489 ) -> Result<proto::FormatBuffersResponse> {
10490 let sender_id = envelope.original_sender_id().unwrap_or_default();
10491 let format = this.update(&mut cx, |this, cx| {
10492 let mut buffers = HashSet::default();
10493 for buffer_id in &envelope.payload.buffer_ids {
10494 let buffer_id = BufferId::new(*buffer_id)?;
10495 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10496 }
10497 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10498 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10499 })??;
10500
10501 let project_transaction = format.await?;
10502 let project_transaction = this.update(&mut cx, |this, cx| {
10503 this.buffer_store.update(cx, |buffer_store, cx| {
10504 buffer_store.serialize_project_transaction_for_peer(
10505 project_transaction,
10506 sender_id,
10507 cx,
10508 )
10509 })
10510 })?;
10511 Ok(proto::FormatBuffersResponse {
10512 transaction: Some(project_transaction),
10513 })
10514 }
10515
10516 async fn handle_apply_code_action_kind(
10517 this: Entity<Self>,
10518 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10519 mut cx: AsyncApp,
10520 ) -> Result<proto::ApplyCodeActionKindResponse> {
10521 let sender_id = envelope.original_sender_id().unwrap_or_default();
10522 let format = this.update(&mut cx, |this, cx| {
10523 let mut buffers = HashSet::default();
10524 for buffer_id in &envelope.payload.buffer_ids {
10525 let buffer_id = BufferId::new(*buffer_id)?;
10526 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10527 }
10528 let kind = match envelope.payload.kind.as_str() {
10529 "" => CodeActionKind::EMPTY,
10530 "quickfix" => CodeActionKind::QUICKFIX,
10531 "refactor" => CodeActionKind::REFACTOR,
10532 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10533 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10534 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10535 "source" => CodeActionKind::SOURCE,
10536 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10537 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10538 _ => anyhow::bail!(
10539 "Invalid code action kind {}",
10540 envelope.payload.kind.as_str()
10541 ),
10542 };
10543 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10544 })??;
10545
10546 let project_transaction = format.await?;
10547 let project_transaction = this.update(&mut cx, |this, cx| {
10548 this.buffer_store.update(cx, |buffer_store, cx| {
10549 buffer_store.serialize_project_transaction_for_peer(
10550 project_transaction,
10551 sender_id,
10552 cx,
10553 )
10554 })
10555 })?;
10556 Ok(proto::ApplyCodeActionKindResponse {
10557 transaction: Some(project_transaction),
10558 })
10559 }
10560
10561 async fn shutdown_language_server(
10562 server_state: Option<LanguageServerState>,
10563 name: LanguageServerName,
10564 cx: &mut AsyncApp,
10565 ) {
10566 let server = match server_state {
10567 Some(LanguageServerState::Starting { startup, .. }) => {
10568 let mut timer = cx
10569 .background_executor()
10570 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10571 .fuse();
10572
10573 select! {
10574 server = startup.fuse() => server,
10575 () = timer => {
10576 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10577 None
10578 },
10579 }
10580 }
10581
10582 Some(LanguageServerState::Running { server, .. }) => Some(server),
10583
10584 None => None,
10585 };
10586
10587 if let Some(server) = server
10588 && let Some(shutdown) = server.shutdown()
10589 {
10590 shutdown.await;
10591 }
10592 }
10593
10594 // Returns a list of all of the worktrees which no longer have a language server and the root path
10595 // for the stopped server
10596 fn stop_local_language_server(
10597 &mut self,
10598 server_id: LanguageServerId,
10599 cx: &mut Context<Self>,
10600 ) -> Task<()> {
10601 let local = match &mut self.mode {
10602 LspStoreMode::Local(local) => local,
10603 _ => {
10604 return Task::ready(());
10605 }
10606 };
10607
10608 // Remove this server ID from all entries in the given worktree.
10609 local
10610 .language_server_ids
10611 .retain(|_, state| state.id != server_id);
10612 self.buffer_store.update(cx, |buffer_store, cx| {
10613 for buffer in buffer_store.buffers() {
10614 buffer.update(cx, |buffer, cx| {
10615 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10616 buffer.set_completion_triggers(server_id, Default::default(), cx);
10617 });
10618 }
10619 });
10620
10621 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10622 summaries.retain(|path, summaries_by_server_id| {
10623 if summaries_by_server_id.remove(&server_id).is_some() {
10624 if let Some((client, project_id)) = self.downstream_client.clone() {
10625 client
10626 .send(proto::UpdateDiagnosticSummary {
10627 project_id,
10628 worktree_id: worktree_id.to_proto(),
10629 summary: Some(proto::DiagnosticSummary {
10630 path: path.as_ref().to_proto(),
10631 language_server_id: server_id.0 as u64,
10632 error_count: 0,
10633 warning_count: 0,
10634 }),
10635 more_summaries: Vec::new(),
10636 })
10637 .log_err();
10638 }
10639 !summaries_by_server_id.is_empty()
10640 } else {
10641 true
10642 }
10643 });
10644 }
10645
10646 let local = self.as_local_mut().unwrap();
10647 for diagnostics in local.diagnostics.values_mut() {
10648 diagnostics.retain(|_, diagnostics_by_server_id| {
10649 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10650 diagnostics_by_server_id.remove(ix);
10651 !diagnostics_by_server_id.is_empty()
10652 } else {
10653 true
10654 }
10655 });
10656 }
10657 local.language_server_watched_paths.remove(&server_id);
10658
10659 let server_state = local.language_servers.remove(&server_id);
10660 self.cleanup_lsp_data(server_id);
10661 let name = self
10662 .language_server_statuses
10663 .remove(&server_id)
10664 .map(|status| status.name)
10665 .or_else(|| {
10666 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10667 Some(adapter.name())
10668 } else {
10669 None
10670 }
10671 });
10672
10673 if let Some(name) = name {
10674 log::info!("stopping language server {name}");
10675 self.languages
10676 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10677 cx.notify();
10678
10679 return cx.spawn(async move |lsp_store, cx| {
10680 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10681 lsp_store
10682 .update(cx, |lsp_store, cx| {
10683 lsp_store
10684 .languages
10685 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10686 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10687 cx.notify();
10688 })
10689 .ok();
10690 });
10691 }
10692
10693 if server_state.is_some() {
10694 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10695 }
10696 Task::ready(())
10697 }
10698
10699 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10700 if let Some((client, project_id)) = self.upstream_client() {
10701 let request = client.request(proto::StopLanguageServers {
10702 project_id,
10703 buffer_ids: Vec::new(),
10704 also_servers: Vec::new(),
10705 all: true,
10706 });
10707 cx.background_spawn(request).detach_and_log_err(cx);
10708 } else {
10709 let Some(local) = self.as_local_mut() else {
10710 return;
10711 };
10712 let language_servers_to_stop = local
10713 .language_server_ids
10714 .values()
10715 .map(|state| state.id)
10716 .collect();
10717 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10718 let tasks = language_servers_to_stop
10719 .into_iter()
10720 .map(|server| self.stop_local_language_server(server, cx))
10721 .collect::<Vec<_>>();
10722 cx.background_spawn(async move {
10723 futures::future::join_all(tasks).await;
10724 })
10725 .detach();
10726 }
10727 }
10728
10729 pub fn restart_language_servers_for_buffers(
10730 &mut self,
10731 buffers: Vec<Entity<Buffer>>,
10732 only_restart_servers: HashSet<LanguageServerSelector>,
10733 cx: &mut Context<Self>,
10734 ) {
10735 if let Some((client, project_id)) = self.upstream_client() {
10736 let request = client.request(proto::RestartLanguageServers {
10737 project_id,
10738 buffer_ids: buffers
10739 .into_iter()
10740 .map(|b| b.read(cx).remote_id().to_proto())
10741 .collect(),
10742 only_servers: only_restart_servers
10743 .into_iter()
10744 .map(|selector| {
10745 let selector = match selector {
10746 LanguageServerSelector::Id(language_server_id) => {
10747 proto::language_server_selector::Selector::ServerId(
10748 language_server_id.to_proto(),
10749 )
10750 }
10751 LanguageServerSelector::Name(language_server_name) => {
10752 proto::language_server_selector::Selector::Name(
10753 language_server_name.to_string(),
10754 )
10755 }
10756 };
10757 proto::LanguageServerSelector {
10758 selector: Some(selector),
10759 }
10760 })
10761 .collect(),
10762 all: false,
10763 });
10764 cx.background_spawn(request).detach_and_log_err(cx);
10765 } else {
10766 let stop_task = if only_restart_servers.is_empty() {
10767 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10768 } else {
10769 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10770 };
10771 cx.spawn(async move |lsp_store, cx| {
10772 stop_task.await;
10773 lsp_store
10774 .update(cx, |lsp_store, cx| {
10775 for buffer in buffers {
10776 lsp_store.register_buffer_with_language_servers(
10777 &buffer,
10778 only_restart_servers.clone(),
10779 true,
10780 cx,
10781 );
10782 }
10783 })
10784 .ok()
10785 })
10786 .detach();
10787 }
10788 }
10789
10790 pub fn stop_language_servers_for_buffers(
10791 &mut self,
10792 buffers: Vec<Entity<Buffer>>,
10793 also_stop_servers: HashSet<LanguageServerSelector>,
10794 cx: &mut Context<Self>,
10795 ) -> Task<Result<()>> {
10796 if let Some((client, project_id)) = self.upstream_client() {
10797 let request = client.request(proto::StopLanguageServers {
10798 project_id,
10799 buffer_ids: buffers
10800 .into_iter()
10801 .map(|b| b.read(cx).remote_id().to_proto())
10802 .collect(),
10803 also_servers: also_stop_servers
10804 .into_iter()
10805 .map(|selector| {
10806 let selector = match selector {
10807 LanguageServerSelector::Id(language_server_id) => {
10808 proto::language_server_selector::Selector::ServerId(
10809 language_server_id.to_proto(),
10810 )
10811 }
10812 LanguageServerSelector::Name(language_server_name) => {
10813 proto::language_server_selector::Selector::Name(
10814 language_server_name.to_string(),
10815 )
10816 }
10817 };
10818 proto::LanguageServerSelector {
10819 selector: Some(selector),
10820 }
10821 })
10822 .collect(),
10823 all: false,
10824 });
10825 cx.background_spawn(async move {
10826 let _ = request.await?;
10827 Ok(())
10828 })
10829 } else {
10830 let task =
10831 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10832 cx.background_spawn(async move {
10833 task.await;
10834 Ok(())
10835 })
10836 }
10837 }
10838
10839 fn stop_local_language_servers_for_buffers(
10840 &mut self,
10841 buffers: &[Entity<Buffer>],
10842 also_stop_servers: HashSet<LanguageServerSelector>,
10843 cx: &mut Context<Self>,
10844 ) -> Task<()> {
10845 let Some(local) = self.as_local_mut() else {
10846 return Task::ready(());
10847 };
10848 let mut language_server_names_to_stop = BTreeSet::default();
10849 let mut language_servers_to_stop = also_stop_servers
10850 .into_iter()
10851 .flat_map(|selector| match selector {
10852 LanguageServerSelector::Id(id) => Some(id),
10853 LanguageServerSelector::Name(name) => {
10854 language_server_names_to_stop.insert(name);
10855 None
10856 }
10857 })
10858 .collect::<BTreeSet<_>>();
10859
10860 let mut covered_worktrees = HashSet::default();
10861 for buffer in buffers {
10862 buffer.update(cx, |buffer, cx| {
10863 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10864 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10865 && covered_worktrees.insert(worktree_id)
10866 {
10867 language_server_names_to_stop.retain(|name| {
10868 let old_ids_count = language_servers_to_stop.len();
10869 let all_language_servers_with_this_name = local
10870 .language_server_ids
10871 .iter()
10872 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10873 language_servers_to_stop.extend(all_language_servers_with_this_name);
10874 old_ids_count == language_servers_to_stop.len()
10875 });
10876 }
10877 });
10878 }
10879 for name in language_server_names_to_stop {
10880 language_servers_to_stop.extend(
10881 local
10882 .language_server_ids
10883 .iter()
10884 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10885 );
10886 }
10887
10888 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10889 let tasks = language_servers_to_stop
10890 .into_iter()
10891 .map(|server| self.stop_local_language_server(server, cx))
10892 .collect::<Vec<_>>();
10893
10894 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10895 }
10896
10897 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10898 let (worktree, relative_path) =
10899 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10900
10901 let project_path = ProjectPath {
10902 worktree_id: worktree.read(cx).id(),
10903 path: relative_path,
10904 };
10905
10906 Some(
10907 self.buffer_store()
10908 .read(cx)
10909 .get_by_path(&project_path)?
10910 .read(cx),
10911 )
10912 }
10913
10914 #[cfg(any(test, feature = "test-support"))]
10915 pub fn update_diagnostics(
10916 &mut self,
10917 server_id: LanguageServerId,
10918 diagnostics: lsp::PublishDiagnosticsParams,
10919 result_id: Option<String>,
10920 source_kind: DiagnosticSourceKind,
10921 disk_based_sources: &[String],
10922 cx: &mut Context<Self>,
10923 ) -> Result<()> {
10924 self.merge_lsp_diagnostics(
10925 source_kind,
10926 vec![DocumentDiagnosticsUpdate {
10927 diagnostics,
10928 result_id,
10929 server_id,
10930 disk_based_sources: Cow::Borrowed(disk_based_sources),
10931 }],
10932 |_, _, _| false,
10933 cx,
10934 )
10935 }
10936
10937 pub fn merge_lsp_diagnostics(
10938 &mut self,
10939 source_kind: DiagnosticSourceKind,
10940 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10941 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10942 cx: &mut Context<Self>,
10943 ) -> Result<()> {
10944 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10945 let updates = lsp_diagnostics
10946 .into_iter()
10947 .filter_map(|update| {
10948 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10949 Some(DocumentDiagnosticsUpdate {
10950 diagnostics: self.lsp_to_document_diagnostics(
10951 abs_path,
10952 source_kind,
10953 update.server_id,
10954 update.diagnostics,
10955 &update.disk_based_sources,
10956 ),
10957 result_id: update.result_id,
10958 server_id: update.server_id,
10959 disk_based_sources: update.disk_based_sources,
10960 })
10961 })
10962 .collect();
10963 self.merge_diagnostic_entries(updates, merge, cx)?;
10964 Ok(())
10965 }
10966
10967 fn lsp_to_document_diagnostics(
10968 &mut self,
10969 document_abs_path: PathBuf,
10970 source_kind: DiagnosticSourceKind,
10971 server_id: LanguageServerId,
10972 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10973 disk_based_sources: &[String],
10974 ) -> DocumentDiagnostics {
10975 let mut diagnostics = Vec::default();
10976 let mut primary_diagnostic_group_ids = HashMap::default();
10977 let mut sources_by_group_id = HashMap::default();
10978 let mut supporting_diagnostics = HashMap::default();
10979
10980 let adapter = self.language_server_adapter_for_id(server_id);
10981
10982 // Ensure that primary diagnostics are always the most severe
10983 lsp_diagnostics
10984 .diagnostics
10985 .sort_by_key(|item| item.severity);
10986
10987 for diagnostic in &lsp_diagnostics.diagnostics {
10988 let source = diagnostic.source.as_ref();
10989 let range = range_from_lsp(diagnostic.range);
10990 let is_supporting = diagnostic
10991 .related_information
10992 .as_ref()
10993 .is_some_and(|infos| {
10994 infos.iter().any(|info| {
10995 primary_diagnostic_group_ids.contains_key(&(
10996 source,
10997 diagnostic.code.clone(),
10998 range_from_lsp(info.location.range),
10999 ))
11000 })
11001 });
11002
11003 let is_unnecessary = diagnostic
11004 .tags
11005 .as_ref()
11006 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11007
11008 let underline = self
11009 .language_server_adapter_for_id(server_id)
11010 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11011
11012 if is_supporting {
11013 supporting_diagnostics.insert(
11014 (source, diagnostic.code.clone(), range),
11015 (diagnostic.severity, is_unnecessary),
11016 );
11017 } else {
11018 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11019 let is_disk_based =
11020 source.is_some_and(|source| disk_based_sources.contains(source));
11021
11022 sources_by_group_id.insert(group_id, source);
11023 primary_diagnostic_group_ids
11024 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11025
11026 diagnostics.push(DiagnosticEntry {
11027 range,
11028 diagnostic: Diagnostic {
11029 source: diagnostic.source.clone(),
11030 source_kind,
11031 code: diagnostic.code.clone(),
11032 code_description: diagnostic
11033 .code_description
11034 .as_ref()
11035 .and_then(|d| d.href.clone()),
11036 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11037 markdown: adapter.as_ref().and_then(|adapter| {
11038 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11039 }),
11040 message: diagnostic.message.trim().to_string(),
11041 group_id,
11042 is_primary: true,
11043 is_disk_based,
11044 is_unnecessary,
11045 underline,
11046 data: diagnostic.data.clone(),
11047 },
11048 });
11049 if let Some(infos) = &diagnostic.related_information {
11050 for info in infos {
11051 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11052 let range = range_from_lsp(info.location.range);
11053 diagnostics.push(DiagnosticEntry {
11054 range,
11055 diagnostic: Diagnostic {
11056 source: diagnostic.source.clone(),
11057 source_kind,
11058 code: diagnostic.code.clone(),
11059 code_description: diagnostic
11060 .code_description
11061 .as_ref()
11062 .and_then(|d| d.href.clone()),
11063 severity: DiagnosticSeverity::INFORMATION,
11064 markdown: adapter.as_ref().and_then(|adapter| {
11065 adapter.diagnostic_message_to_markdown(&info.message)
11066 }),
11067 message: info.message.trim().to_string(),
11068 group_id,
11069 is_primary: false,
11070 is_disk_based,
11071 is_unnecessary: false,
11072 underline,
11073 data: diagnostic.data.clone(),
11074 },
11075 });
11076 }
11077 }
11078 }
11079 }
11080 }
11081
11082 for entry in &mut diagnostics {
11083 let diagnostic = &mut entry.diagnostic;
11084 if !diagnostic.is_primary {
11085 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11086 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11087 source,
11088 diagnostic.code.clone(),
11089 entry.range.clone(),
11090 )) {
11091 if let Some(severity) = severity {
11092 diagnostic.severity = severity;
11093 }
11094 diagnostic.is_unnecessary = is_unnecessary;
11095 }
11096 }
11097 }
11098
11099 DocumentDiagnostics {
11100 diagnostics,
11101 document_abs_path,
11102 version: lsp_diagnostics.version,
11103 }
11104 }
11105
11106 fn insert_newly_running_language_server(
11107 &mut self,
11108 adapter: Arc<CachedLspAdapter>,
11109 language_server: Arc<LanguageServer>,
11110 server_id: LanguageServerId,
11111 key: LanguageServerSeed,
11112 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11113 cx: &mut Context<Self>,
11114 ) {
11115 let Some(local) = self.as_local_mut() else {
11116 return;
11117 };
11118 // If the language server for this key doesn't match the server id, don't store the
11119 // server. Which will cause it to be dropped, killing the process
11120 if local
11121 .language_server_ids
11122 .get(&key)
11123 .map(|state| state.id != server_id)
11124 .unwrap_or(false)
11125 {
11126 return;
11127 }
11128
11129 // Update language_servers collection with Running variant of LanguageServerState
11130 // indicating that the server is up and running and ready
11131 let workspace_folders = workspace_folders.lock().clone();
11132 language_server.set_workspace_folders(workspace_folders);
11133
11134 let workspace_diagnostics_refresh_tasks = language_server
11135 .capabilities()
11136 .diagnostic_provider
11137 .and_then(|provider| {
11138 local
11139 .language_server_dynamic_registrations
11140 .entry(server_id)
11141 .or_default()
11142 .diagnostics
11143 .entry(None)
11144 .or_insert(provider.clone());
11145 let workspace_refresher =
11146 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11147
11148 Some((None, workspace_refresher))
11149 })
11150 .into_iter()
11151 .collect();
11152 local.language_servers.insert(
11153 server_id,
11154 LanguageServerState::Running {
11155 workspace_diagnostics_refresh_tasks,
11156 adapter: adapter.clone(),
11157 server: language_server.clone(),
11158 simulate_disk_based_diagnostics_completion: None,
11159 },
11160 );
11161 local
11162 .languages
11163 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11164 if let Some(file_ops_caps) = language_server
11165 .capabilities()
11166 .workspace
11167 .as_ref()
11168 .and_then(|ws| ws.file_operations.as_ref())
11169 {
11170 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11171 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11172 if did_rename_caps.or(will_rename_caps).is_some() {
11173 let watcher = RenamePathsWatchedForServer::default()
11174 .with_did_rename_patterns(did_rename_caps)
11175 .with_will_rename_patterns(will_rename_caps);
11176 local
11177 .language_server_paths_watched_for_rename
11178 .insert(server_id, watcher);
11179 }
11180 }
11181
11182 self.language_server_statuses.insert(
11183 server_id,
11184 LanguageServerStatus {
11185 name: language_server.name(),
11186 pending_work: Default::default(),
11187 has_pending_diagnostic_updates: false,
11188 progress_tokens: Default::default(),
11189 worktree: Some(key.worktree_id),
11190 binary: Some(LanguageServerBinaryInfo {
11191 path: language_server.binary().path.to_string_lossy().into_owned(),
11192 arguments: language_server
11193 .binary()
11194 .arguments
11195 .iter()
11196 .map(|arg| arg.to_string_lossy().into_owned())
11197 .collect(),
11198 env: language_server.binary().env.clone(),
11199 }),
11200 configuration: Some(language_server.configuration().clone()),
11201 workspace_folders: language_server.workspace_folders(),
11202 },
11203 );
11204
11205 cx.emit(LspStoreEvent::LanguageServerAdded(
11206 server_id,
11207 language_server.name(),
11208 Some(key.worktree_id),
11209 ));
11210
11211 let server_capabilities = language_server.capabilities();
11212 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11213 downstream_client
11214 .send(proto::StartLanguageServer {
11215 project_id: *project_id,
11216 server: Some(proto::LanguageServer {
11217 id: server_id.to_proto(),
11218 name: language_server.name().to_string(),
11219 worktree_id: Some(key.worktree_id.to_proto()),
11220 }),
11221 capabilities: serde_json::to_string(&server_capabilities)
11222 .expect("serializing server LSP capabilities"),
11223 })
11224 .log_err();
11225 }
11226 self.lsp_server_capabilities
11227 .insert(server_id, server_capabilities);
11228
11229 // Tell the language server about every open buffer in the worktree that matches the language.
11230 // Also check for buffers in worktrees that reused this server
11231 let mut worktrees_using_server = vec![key.worktree_id];
11232 if let Some(local) = self.as_local() {
11233 // Find all worktrees that have this server in their language server tree
11234 for (worktree_id, servers) in &local.lsp_tree.instances {
11235 if *worktree_id != key.worktree_id {
11236 for server_map in servers.roots.values() {
11237 if server_map
11238 .values()
11239 .any(|(node, _)| node.id() == Some(server_id))
11240 {
11241 worktrees_using_server.push(*worktree_id);
11242 }
11243 }
11244 }
11245 }
11246 }
11247
11248 let mut buffer_paths_registered = Vec::new();
11249 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11250 let mut lsp_adapters = HashMap::default();
11251 for buffer_handle in buffer_store.buffers() {
11252 let buffer = buffer_handle.read(cx);
11253 let file = match File::from_dyn(buffer.file()) {
11254 Some(file) => file,
11255 None => continue,
11256 };
11257 let language = match buffer.language() {
11258 Some(language) => language,
11259 None => continue,
11260 };
11261
11262 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11263 || !lsp_adapters
11264 .entry(language.name())
11265 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11266 .iter()
11267 .any(|a| a.name == key.name)
11268 {
11269 continue;
11270 }
11271 // didOpen
11272 let file = match file.as_local() {
11273 Some(file) => file,
11274 None => continue,
11275 };
11276
11277 let local = self.as_local_mut().unwrap();
11278
11279 let buffer_id = buffer.remote_id();
11280 if local.registered_buffers.contains_key(&buffer_id) {
11281 let versions = local
11282 .buffer_snapshots
11283 .entry(buffer_id)
11284 .or_default()
11285 .entry(server_id)
11286 .and_modify(|_| {
11287 assert!(
11288 false,
11289 "There should not be an existing snapshot for a newly inserted buffer"
11290 )
11291 })
11292 .or_insert_with(|| {
11293 vec![LspBufferSnapshot {
11294 version: 0,
11295 snapshot: buffer.text_snapshot(),
11296 }]
11297 });
11298
11299 let snapshot = versions.last().unwrap();
11300 let version = snapshot.version;
11301 let initial_snapshot = &snapshot.snapshot;
11302 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11303 language_server.register_buffer(
11304 uri,
11305 adapter.language_id(&language.name()),
11306 version,
11307 initial_snapshot.text(),
11308 );
11309 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11310 local
11311 .buffers_opened_in_servers
11312 .entry(buffer_id)
11313 .or_default()
11314 .insert(server_id);
11315 }
11316 buffer_handle.update(cx, |buffer, cx| {
11317 buffer.set_completion_triggers(
11318 server_id,
11319 language_server
11320 .capabilities()
11321 .completion_provider
11322 .as_ref()
11323 .and_then(|provider| {
11324 provider
11325 .trigger_characters
11326 .as_ref()
11327 .map(|characters| characters.iter().cloned().collect())
11328 })
11329 .unwrap_or_default(),
11330 cx,
11331 )
11332 });
11333 }
11334 });
11335
11336 for (buffer_id, abs_path) in buffer_paths_registered {
11337 cx.emit(LspStoreEvent::LanguageServerUpdate {
11338 language_server_id: server_id,
11339 name: Some(adapter.name()),
11340 message: proto::update_language_server::Variant::RegisteredForBuffer(
11341 proto::RegisteredForBuffer {
11342 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11343 buffer_id: buffer_id.to_proto(),
11344 },
11345 ),
11346 });
11347 }
11348
11349 cx.notify();
11350 }
11351
11352 pub fn language_servers_running_disk_based_diagnostics(
11353 &self,
11354 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11355 self.language_server_statuses
11356 .iter()
11357 .filter_map(|(id, status)| {
11358 if status.has_pending_diagnostic_updates {
11359 Some(*id)
11360 } else {
11361 None
11362 }
11363 })
11364 }
11365
11366 pub(crate) fn cancel_language_server_work_for_buffers(
11367 &mut self,
11368 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11369 cx: &mut Context<Self>,
11370 ) {
11371 if let Some((client, project_id)) = self.upstream_client() {
11372 let request = client.request(proto::CancelLanguageServerWork {
11373 project_id,
11374 work: Some(proto::cancel_language_server_work::Work::Buffers(
11375 proto::cancel_language_server_work::Buffers {
11376 buffer_ids: buffers
11377 .into_iter()
11378 .map(|b| b.read(cx).remote_id().to_proto())
11379 .collect(),
11380 },
11381 )),
11382 });
11383 cx.background_spawn(request).detach_and_log_err(cx);
11384 } else if let Some(local) = self.as_local() {
11385 let servers = buffers
11386 .into_iter()
11387 .flat_map(|buffer| {
11388 buffer.update(cx, |buffer, cx| {
11389 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11390 })
11391 })
11392 .collect::<HashSet<_>>();
11393 for server_id in servers {
11394 self.cancel_language_server_work(server_id, None, cx);
11395 }
11396 }
11397 }
11398
11399 pub(crate) fn cancel_language_server_work(
11400 &mut self,
11401 server_id: LanguageServerId,
11402 token_to_cancel: Option<ProgressToken>,
11403 cx: &mut Context<Self>,
11404 ) {
11405 if let Some(local) = self.as_local() {
11406 let status = self.language_server_statuses.get(&server_id);
11407 let server = local.language_servers.get(&server_id);
11408 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11409 {
11410 for (token, progress) in &status.pending_work {
11411 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11412 && token != token_to_cancel
11413 {
11414 continue;
11415 }
11416 if progress.is_cancellable {
11417 server
11418 .notify::<lsp::notification::WorkDoneProgressCancel>(
11419 WorkDoneProgressCancelParams {
11420 token: token.to_lsp(),
11421 },
11422 )
11423 .ok();
11424 }
11425 }
11426 }
11427 } else if let Some((client, project_id)) = self.upstream_client() {
11428 let request = client.request(proto::CancelLanguageServerWork {
11429 project_id,
11430 work: Some(
11431 proto::cancel_language_server_work::Work::LanguageServerWork(
11432 proto::cancel_language_server_work::LanguageServerWork {
11433 language_server_id: server_id.to_proto(),
11434 token: token_to_cancel.map(|token| token.to_proto()),
11435 },
11436 ),
11437 ),
11438 });
11439 cx.background_spawn(request).detach_and_log_err(cx);
11440 }
11441 }
11442
11443 fn register_supplementary_language_server(
11444 &mut self,
11445 id: LanguageServerId,
11446 name: LanguageServerName,
11447 server: Arc<LanguageServer>,
11448 cx: &mut Context<Self>,
11449 ) {
11450 if let Some(local) = self.as_local_mut() {
11451 local
11452 .supplementary_language_servers
11453 .insert(id, (name.clone(), server));
11454 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11455 }
11456 }
11457
11458 fn unregister_supplementary_language_server(
11459 &mut self,
11460 id: LanguageServerId,
11461 cx: &mut Context<Self>,
11462 ) {
11463 if let Some(local) = self.as_local_mut() {
11464 local.supplementary_language_servers.remove(&id);
11465 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11466 }
11467 }
11468
11469 pub(crate) fn supplementary_language_servers(
11470 &self,
11471 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11472 self.as_local().into_iter().flat_map(|local| {
11473 local
11474 .supplementary_language_servers
11475 .iter()
11476 .map(|(id, (name, _))| (*id, name.clone()))
11477 })
11478 }
11479
11480 pub fn language_server_adapter_for_id(
11481 &self,
11482 id: LanguageServerId,
11483 ) -> Option<Arc<CachedLspAdapter>> {
11484 self.as_local()
11485 .and_then(|local| local.language_servers.get(&id))
11486 .and_then(|language_server_state| match language_server_state {
11487 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11488 _ => None,
11489 })
11490 }
11491
11492 pub(super) fn update_local_worktree_language_servers(
11493 &mut self,
11494 worktree_handle: &Entity<Worktree>,
11495 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11496 cx: &mut Context<Self>,
11497 ) {
11498 if changes.is_empty() {
11499 return;
11500 }
11501
11502 let Some(local) = self.as_local() else { return };
11503
11504 local.prettier_store.update(cx, |prettier_store, cx| {
11505 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11506 });
11507
11508 let worktree_id = worktree_handle.read(cx).id();
11509 let mut language_server_ids = local
11510 .language_server_ids
11511 .iter()
11512 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11513 .collect::<Vec<_>>();
11514 language_server_ids.sort();
11515 language_server_ids.dedup();
11516
11517 // let abs_path = worktree_handle.read(cx).abs_path();
11518 for server_id in &language_server_ids {
11519 if let Some(LanguageServerState::Running { server, .. }) =
11520 local.language_servers.get(server_id)
11521 && let Some(watched_paths) = local
11522 .language_server_watched_paths
11523 .get(server_id)
11524 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11525 {
11526 let params = lsp::DidChangeWatchedFilesParams {
11527 changes: changes
11528 .iter()
11529 .filter_map(|(path, _, change)| {
11530 if !watched_paths.is_match(path.as_std_path()) {
11531 return None;
11532 }
11533 let typ = match change {
11534 PathChange::Loaded => return None,
11535 PathChange::Added => lsp::FileChangeType::CREATED,
11536 PathChange::Removed => lsp::FileChangeType::DELETED,
11537 PathChange::Updated => lsp::FileChangeType::CHANGED,
11538 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11539 };
11540 let uri = lsp::Uri::from_file_path(
11541 worktree_handle.read(cx).absolutize(&path),
11542 )
11543 .ok()?;
11544 Some(lsp::FileEvent { uri, typ })
11545 })
11546 .collect(),
11547 };
11548 if !params.changes.is_empty() {
11549 server
11550 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11551 .ok();
11552 }
11553 }
11554 }
11555 for (path, _, _) in changes {
11556 if let Some(file_name) = path.file_name()
11557 && local.watched_manifest_filenames.contains(file_name)
11558 {
11559 self.request_workspace_config_refresh();
11560 break;
11561 }
11562 }
11563 }
11564
11565 pub fn wait_for_remote_buffer(
11566 &mut self,
11567 id: BufferId,
11568 cx: &mut Context<Self>,
11569 ) -> Task<Result<Entity<Buffer>>> {
11570 self.buffer_store.update(cx, |buffer_store, cx| {
11571 buffer_store.wait_for_remote_buffer(id, cx)
11572 })
11573 }
11574
11575 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11576 let mut result = proto::Symbol {
11577 language_server_name: symbol.language_server_name.0.to_string(),
11578 source_worktree_id: symbol.source_worktree_id.to_proto(),
11579 language_server_id: symbol.source_language_server_id.to_proto(),
11580 name: symbol.name.clone(),
11581 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11582 start: Some(proto::PointUtf16 {
11583 row: symbol.range.start.0.row,
11584 column: symbol.range.start.0.column,
11585 }),
11586 end: Some(proto::PointUtf16 {
11587 row: symbol.range.end.0.row,
11588 column: symbol.range.end.0.column,
11589 }),
11590 worktree_id: Default::default(),
11591 path: Default::default(),
11592 signature: Default::default(),
11593 };
11594 match &symbol.path {
11595 SymbolLocation::InProject(path) => {
11596 result.worktree_id = path.worktree_id.to_proto();
11597 result.path = path.path.to_proto();
11598 }
11599 SymbolLocation::OutsideProject {
11600 abs_path,
11601 signature,
11602 } => {
11603 result.path = abs_path.to_string_lossy().into_owned();
11604 result.signature = signature.to_vec();
11605 }
11606 }
11607 result
11608 }
11609
11610 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11611 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11612 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11613 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11614
11615 let path = if serialized_symbol.signature.is_empty() {
11616 SymbolLocation::InProject(ProjectPath {
11617 worktree_id,
11618 path: RelPath::from_proto(&serialized_symbol.path)
11619 .context("invalid symbol path")?,
11620 })
11621 } else {
11622 SymbolLocation::OutsideProject {
11623 abs_path: Path::new(&serialized_symbol.path).into(),
11624 signature: serialized_symbol
11625 .signature
11626 .try_into()
11627 .map_err(|_| anyhow!("invalid signature"))?,
11628 }
11629 };
11630
11631 let start = serialized_symbol.start.context("invalid start")?;
11632 let end = serialized_symbol.end.context("invalid end")?;
11633 Ok(CoreSymbol {
11634 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11635 source_worktree_id,
11636 source_language_server_id: LanguageServerId::from_proto(
11637 serialized_symbol.language_server_id,
11638 ),
11639 path,
11640 name: serialized_symbol.name,
11641 range: Unclipped(PointUtf16::new(start.row, start.column))
11642 ..Unclipped(PointUtf16::new(end.row, end.column)),
11643 kind,
11644 })
11645 }
11646
11647 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11648 let mut serialized_completion = proto::Completion {
11649 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11650 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11651 new_text: completion.new_text.clone(),
11652 ..proto::Completion::default()
11653 };
11654 match &completion.source {
11655 CompletionSource::Lsp {
11656 insert_range,
11657 server_id,
11658 lsp_completion,
11659 lsp_defaults,
11660 resolved,
11661 } => {
11662 let (old_insert_start, old_insert_end) = insert_range
11663 .as_ref()
11664 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11665 .unzip();
11666
11667 serialized_completion.old_insert_start = old_insert_start;
11668 serialized_completion.old_insert_end = old_insert_end;
11669 serialized_completion.source = proto::completion::Source::Lsp as i32;
11670 serialized_completion.server_id = server_id.0 as u64;
11671 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11672 serialized_completion.lsp_defaults = lsp_defaults
11673 .as_deref()
11674 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11675 serialized_completion.resolved = *resolved;
11676 }
11677 CompletionSource::BufferWord {
11678 word_range,
11679 resolved,
11680 } => {
11681 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11682 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11683 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11684 serialized_completion.resolved = *resolved;
11685 }
11686 CompletionSource::Custom => {
11687 serialized_completion.source = proto::completion::Source::Custom as i32;
11688 serialized_completion.resolved = true;
11689 }
11690 CompletionSource::Dap { sort_text } => {
11691 serialized_completion.source = proto::completion::Source::Dap as i32;
11692 serialized_completion.sort_text = Some(sort_text.clone());
11693 }
11694 }
11695
11696 serialized_completion
11697 }
11698
11699 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11700 let old_replace_start = completion
11701 .old_replace_start
11702 .and_then(deserialize_anchor)
11703 .context("invalid old start")?;
11704 let old_replace_end = completion
11705 .old_replace_end
11706 .and_then(deserialize_anchor)
11707 .context("invalid old end")?;
11708 let insert_range = {
11709 match completion.old_insert_start.zip(completion.old_insert_end) {
11710 Some((start, end)) => {
11711 let start = deserialize_anchor(start).context("invalid insert old start")?;
11712 let end = deserialize_anchor(end).context("invalid insert old end")?;
11713 Some(start..end)
11714 }
11715 None => None,
11716 }
11717 };
11718 Ok(CoreCompletion {
11719 replace_range: old_replace_start..old_replace_end,
11720 new_text: completion.new_text,
11721 source: match proto::completion::Source::from_i32(completion.source) {
11722 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11723 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11724 insert_range,
11725 server_id: LanguageServerId::from_proto(completion.server_id),
11726 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11727 lsp_defaults: completion
11728 .lsp_defaults
11729 .as_deref()
11730 .map(serde_json::from_slice)
11731 .transpose()?,
11732 resolved: completion.resolved,
11733 },
11734 Some(proto::completion::Source::BufferWord) => {
11735 let word_range = completion
11736 .buffer_word_start
11737 .and_then(deserialize_anchor)
11738 .context("invalid buffer word start")?
11739 ..completion
11740 .buffer_word_end
11741 .and_then(deserialize_anchor)
11742 .context("invalid buffer word end")?;
11743 CompletionSource::BufferWord {
11744 word_range,
11745 resolved: completion.resolved,
11746 }
11747 }
11748 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11749 sort_text: completion
11750 .sort_text
11751 .context("expected sort text to exist")?,
11752 },
11753 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11754 },
11755 })
11756 }
11757
11758 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11759 let (kind, lsp_action) = match &action.lsp_action {
11760 LspAction::Action(code_action) => (
11761 proto::code_action::Kind::Action as i32,
11762 serde_json::to_vec(code_action).unwrap(),
11763 ),
11764 LspAction::Command(command) => (
11765 proto::code_action::Kind::Command as i32,
11766 serde_json::to_vec(command).unwrap(),
11767 ),
11768 LspAction::CodeLens(code_lens) => (
11769 proto::code_action::Kind::CodeLens as i32,
11770 serde_json::to_vec(code_lens).unwrap(),
11771 ),
11772 };
11773
11774 proto::CodeAction {
11775 server_id: action.server_id.0 as u64,
11776 start: Some(serialize_anchor(&action.range.start)),
11777 end: Some(serialize_anchor(&action.range.end)),
11778 lsp_action,
11779 kind,
11780 resolved: action.resolved,
11781 }
11782 }
11783
11784 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11785 let start = action
11786 .start
11787 .and_then(deserialize_anchor)
11788 .context("invalid start")?;
11789 let end = action
11790 .end
11791 .and_then(deserialize_anchor)
11792 .context("invalid end")?;
11793 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11794 Some(proto::code_action::Kind::Action) => {
11795 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11796 }
11797 Some(proto::code_action::Kind::Command) => {
11798 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11799 }
11800 Some(proto::code_action::Kind::CodeLens) => {
11801 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11802 }
11803 None => anyhow::bail!("Unknown action kind {}", action.kind),
11804 };
11805 Ok(CodeAction {
11806 server_id: LanguageServerId(action.server_id as usize),
11807 range: start..end,
11808 resolved: action.resolved,
11809 lsp_action,
11810 })
11811 }
11812
11813 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11814 match &formatting_result {
11815 Ok(_) => self.last_formatting_failure = None,
11816 Err(error) => {
11817 let error_string = format!("{error:#}");
11818 log::error!("Formatting failed: {error_string}");
11819 self.last_formatting_failure
11820 .replace(error_string.lines().join(" "));
11821 }
11822 }
11823 }
11824
11825 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11826 self.lsp_server_capabilities.remove(&for_server);
11827 for lsp_data in self.lsp_data.values_mut() {
11828 lsp_data.remove_server_data(for_server);
11829 }
11830 if let Some(local) = self.as_local_mut() {
11831 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11832 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11833 buffer_servers.remove(&for_server);
11834 }
11835 }
11836 }
11837
11838 pub fn result_id(
11839 &self,
11840 server_id: LanguageServerId,
11841 buffer_id: BufferId,
11842 cx: &App,
11843 ) -> Option<String> {
11844 let abs_path = self
11845 .buffer_store
11846 .read(cx)
11847 .get(buffer_id)
11848 .and_then(|b| File::from_dyn(b.read(cx).file()))
11849 .map(|f| f.abs_path(cx))?;
11850 self.as_local()?
11851 .buffer_pull_diagnostics_result_ids
11852 .get(&server_id)?
11853 .get(&abs_path)?
11854 .clone()
11855 }
11856
11857 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11858 let Some(local) = self.as_local() else {
11859 return HashMap::default();
11860 };
11861 local
11862 .buffer_pull_diagnostics_result_ids
11863 .get(&server_id)
11864 .into_iter()
11865 .flatten()
11866 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11867 .collect()
11868 }
11869
11870 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11871 if let Some(LanguageServerState::Running {
11872 workspace_diagnostics_refresh_tasks,
11873 ..
11874 }) = self
11875 .as_local_mut()
11876 .and_then(|local| local.language_servers.get_mut(&server_id))
11877 {
11878 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11879 diagnostics.refresh_tx.try_send(()).ok();
11880 }
11881 }
11882 }
11883
11884 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11885 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11886 return;
11887 };
11888 let Some(local) = self.as_local_mut() else {
11889 return;
11890 };
11891
11892 for server_id in buffer.update(cx, |buffer, cx| {
11893 local.language_server_ids_for_buffer(buffer, cx)
11894 }) {
11895 if let Some(LanguageServerState::Running {
11896 workspace_diagnostics_refresh_tasks,
11897 ..
11898 }) = local.language_servers.get_mut(&server_id)
11899 {
11900 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11901 diagnostics.refresh_tx.try_send(()).ok();
11902 }
11903 }
11904 }
11905 }
11906
11907 fn apply_workspace_diagnostic_report(
11908 &mut self,
11909 server_id: LanguageServerId,
11910 report: lsp::WorkspaceDiagnosticReportResult,
11911 cx: &mut Context<Self>,
11912 ) {
11913 let workspace_diagnostics =
11914 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11915 let mut unchanged_buffers = HashSet::default();
11916 let mut changed_buffers = HashSet::default();
11917 let workspace_diagnostics_updates = workspace_diagnostics
11918 .into_iter()
11919 .filter_map(
11920 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11921 LspPullDiagnostics::Response {
11922 server_id,
11923 uri,
11924 diagnostics,
11925 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11926 LspPullDiagnostics::Default => None,
11927 },
11928 )
11929 .fold(
11930 HashMap::default(),
11931 |mut acc, (server_id, uri, diagnostics, version)| {
11932 let (result_id, diagnostics) = match diagnostics {
11933 PulledDiagnostics::Unchanged { result_id } => {
11934 unchanged_buffers.insert(uri.clone());
11935 (Some(result_id), Vec::new())
11936 }
11937 PulledDiagnostics::Changed {
11938 result_id,
11939 diagnostics,
11940 } => {
11941 changed_buffers.insert(uri.clone());
11942 (result_id, diagnostics)
11943 }
11944 };
11945 let disk_based_sources = Cow::Owned(
11946 self.language_server_adapter_for_id(server_id)
11947 .as_ref()
11948 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11949 .unwrap_or(&[])
11950 .to_vec(),
11951 );
11952 acc.entry(server_id)
11953 .or_insert_with(Vec::new)
11954 .push(DocumentDiagnosticsUpdate {
11955 server_id,
11956 diagnostics: lsp::PublishDiagnosticsParams {
11957 uri,
11958 diagnostics,
11959 version,
11960 },
11961 result_id,
11962 disk_based_sources,
11963 });
11964 acc
11965 },
11966 );
11967
11968 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11969 self.merge_lsp_diagnostics(
11970 DiagnosticSourceKind::Pulled,
11971 diagnostic_updates,
11972 |buffer, old_diagnostic, cx| {
11973 File::from_dyn(buffer.file())
11974 .and_then(|file| {
11975 let abs_path = file.as_local()?.abs_path(cx);
11976 lsp::Uri::from_file_path(abs_path).ok()
11977 })
11978 .is_none_or(|buffer_uri| {
11979 unchanged_buffers.contains(&buffer_uri)
11980 || match old_diagnostic.source_kind {
11981 DiagnosticSourceKind::Pulled => {
11982 !changed_buffers.contains(&buffer_uri)
11983 }
11984 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11985 true
11986 }
11987 }
11988 })
11989 },
11990 cx,
11991 )
11992 .log_err();
11993 }
11994 }
11995
11996 fn register_server_capabilities(
11997 &mut self,
11998 server_id: LanguageServerId,
11999 params: lsp::RegistrationParams,
12000 cx: &mut Context<Self>,
12001 ) -> anyhow::Result<()> {
12002 let server = self
12003 .language_server_for_id(server_id)
12004 .with_context(|| format!("no server {server_id} found"))?;
12005 for reg in params.registrations {
12006 match reg.method.as_str() {
12007 "workspace/didChangeWatchedFiles" => {
12008 if let Some(options) = reg.register_options {
12009 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12010 let caps = serde_json::from_value(options)?;
12011 local_lsp_store
12012 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12013 true
12014 } else {
12015 false
12016 };
12017 if notify {
12018 notify_server_capabilities_updated(&server, cx);
12019 }
12020 }
12021 }
12022 "workspace/didChangeConfiguration" => {
12023 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12024 }
12025 "workspace/didChangeWorkspaceFolders" => {
12026 // In this case register options is an empty object, we can ignore it
12027 let caps = lsp::WorkspaceFoldersServerCapabilities {
12028 supported: Some(true),
12029 change_notifications: Some(OneOf::Right(reg.id)),
12030 };
12031 server.update_capabilities(|capabilities| {
12032 capabilities
12033 .workspace
12034 .get_or_insert_default()
12035 .workspace_folders = Some(caps);
12036 });
12037 notify_server_capabilities_updated(&server, cx);
12038 }
12039 "workspace/symbol" => {
12040 let options = parse_register_capabilities(reg)?;
12041 server.update_capabilities(|capabilities| {
12042 capabilities.workspace_symbol_provider = Some(options);
12043 });
12044 notify_server_capabilities_updated(&server, cx);
12045 }
12046 "workspace/fileOperations" => {
12047 if let Some(options) = reg.register_options {
12048 let caps = serde_json::from_value(options)?;
12049 server.update_capabilities(|capabilities| {
12050 capabilities
12051 .workspace
12052 .get_or_insert_default()
12053 .file_operations = Some(caps);
12054 });
12055 notify_server_capabilities_updated(&server, cx);
12056 }
12057 }
12058 "workspace/executeCommand" => {
12059 if let Some(options) = reg.register_options {
12060 let options = serde_json::from_value(options)?;
12061 server.update_capabilities(|capabilities| {
12062 capabilities.execute_command_provider = Some(options);
12063 });
12064 notify_server_capabilities_updated(&server, cx);
12065 }
12066 }
12067 "textDocument/rangeFormatting" => {
12068 let options = parse_register_capabilities(reg)?;
12069 server.update_capabilities(|capabilities| {
12070 capabilities.document_range_formatting_provider = Some(options);
12071 });
12072 notify_server_capabilities_updated(&server, cx);
12073 }
12074 "textDocument/onTypeFormatting" => {
12075 if let Some(options) = reg
12076 .register_options
12077 .map(serde_json::from_value)
12078 .transpose()?
12079 {
12080 server.update_capabilities(|capabilities| {
12081 capabilities.document_on_type_formatting_provider = Some(options);
12082 });
12083 notify_server_capabilities_updated(&server, cx);
12084 }
12085 }
12086 "textDocument/formatting" => {
12087 let options = parse_register_capabilities(reg)?;
12088 server.update_capabilities(|capabilities| {
12089 capabilities.document_formatting_provider = Some(options);
12090 });
12091 notify_server_capabilities_updated(&server, cx);
12092 }
12093 "textDocument/rename" => {
12094 let options = parse_register_capabilities(reg)?;
12095 server.update_capabilities(|capabilities| {
12096 capabilities.rename_provider = Some(options);
12097 });
12098 notify_server_capabilities_updated(&server, cx);
12099 }
12100 "textDocument/inlayHint" => {
12101 let options = parse_register_capabilities(reg)?;
12102 server.update_capabilities(|capabilities| {
12103 capabilities.inlay_hint_provider = Some(options);
12104 });
12105 notify_server_capabilities_updated(&server, cx);
12106 }
12107 "textDocument/documentSymbol" => {
12108 let options = parse_register_capabilities(reg)?;
12109 server.update_capabilities(|capabilities| {
12110 capabilities.document_symbol_provider = Some(options);
12111 });
12112 notify_server_capabilities_updated(&server, cx);
12113 }
12114 "textDocument/codeAction" => {
12115 let options = parse_register_capabilities(reg)?;
12116 let provider = match options {
12117 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12118 OneOf::Right(caps) => caps,
12119 };
12120 server.update_capabilities(|capabilities| {
12121 capabilities.code_action_provider = Some(provider);
12122 });
12123 notify_server_capabilities_updated(&server, cx);
12124 }
12125 "textDocument/definition" => {
12126 let options = parse_register_capabilities(reg)?;
12127 server.update_capabilities(|capabilities| {
12128 capabilities.definition_provider = Some(options);
12129 });
12130 notify_server_capabilities_updated(&server, cx);
12131 }
12132 "textDocument/completion" => {
12133 if let Some(caps) = reg
12134 .register_options
12135 .map(serde_json::from_value::<CompletionOptions>)
12136 .transpose()?
12137 {
12138 server.update_capabilities(|capabilities| {
12139 capabilities.completion_provider = Some(caps.clone());
12140 });
12141
12142 if let Some(local) = self.as_local() {
12143 let mut buffers_with_language_server = Vec::new();
12144 for handle in self.buffer_store.read(cx).buffers() {
12145 let buffer_id = handle.read(cx).remote_id();
12146 if local
12147 .buffers_opened_in_servers
12148 .get(&buffer_id)
12149 .filter(|s| s.contains(&server_id))
12150 .is_some()
12151 {
12152 buffers_with_language_server.push(handle);
12153 }
12154 }
12155 let triggers = caps
12156 .trigger_characters
12157 .unwrap_or_default()
12158 .into_iter()
12159 .collect::<BTreeSet<_>>();
12160 for handle in buffers_with_language_server {
12161 let triggers = triggers.clone();
12162 let _ = handle.update(cx, move |buffer, cx| {
12163 buffer.set_completion_triggers(server_id, triggers, cx);
12164 });
12165 }
12166 }
12167 notify_server_capabilities_updated(&server, cx);
12168 }
12169 }
12170 "textDocument/hover" => {
12171 let options = parse_register_capabilities(reg)?;
12172 let provider = match options {
12173 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12174 OneOf::Right(caps) => caps,
12175 };
12176 server.update_capabilities(|capabilities| {
12177 capabilities.hover_provider = Some(provider);
12178 });
12179 notify_server_capabilities_updated(&server, cx);
12180 }
12181 "textDocument/signatureHelp" => {
12182 if let Some(caps) = reg
12183 .register_options
12184 .map(serde_json::from_value)
12185 .transpose()?
12186 {
12187 server.update_capabilities(|capabilities| {
12188 capabilities.signature_help_provider = Some(caps);
12189 });
12190 notify_server_capabilities_updated(&server, cx);
12191 }
12192 }
12193 "textDocument/didChange" => {
12194 if let Some(sync_kind) = reg
12195 .register_options
12196 .and_then(|opts| opts.get("syncKind").cloned())
12197 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12198 .transpose()?
12199 {
12200 server.update_capabilities(|capabilities| {
12201 let mut sync_options =
12202 Self::take_text_document_sync_options(capabilities);
12203 sync_options.change = Some(sync_kind);
12204 capabilities.text_document_sync =
12205 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12206 });
12207 notify_server_capabilities_updated(&server, cx);
12208 }
12209 }
12210 "textDocument/didSave" => {
12211 if let Some(include_text) = reg
12212 .register_options
12213 .map(|opts| {
12214 let transpose = opts
12215 .get("includeText")
12216 .cloned()
12217 .map(serde_json::from_value::<Option<bool>>)
12218 .transpose();
12219 match transpose {
12220 Ok(value) => Ok(value.flatten()),
12221 Err(e) => Err(e),
12222 }
12223 })
12224 .transpose()?
12225 {
12226 server.update_capabilities(|capabilities| {
12227 let mut sync_options =
12228 Self::take_text_document_sync_options(capabilities);
12229 sync_options.save =
12230 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12231 include_text,
12232 }));
12233 capabilities.text_document_sync =
12234 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12235 });
12236 notify_server_capabilities_updated(&server, cx);
12237 }
12238 }
12239 "textDocument/codeLens" => {
12240 if let Some(caps) = reg
12241 .register_options
12242 .map(serde_json::from_value)
12243 .transpose()?
12244 {
12245 server.update_capabilities(|capabilities| {
12246 capabilities.code_lens_provider = Some(caps);
12247 });
12248 notify_server_capabilities_updated(&server, cx);
12249 }
12250 }
12251 "textDocument/diagnostic" => {
12252 if let Some(caps) = reg
12253 .register_options
12254 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12255 .transpose()?
12256 {
12257 let local = self
12258 .as_local_mut()
12259 .context("Expected LSP Store to be local")?;
12260 let state = local
12261 .language_servers
12262 .get_mut(&server_id)
12263 .context("Could not obtain Language Servers state")?;
12264 local
12265 .language_server_dynamic_registrations
12266 .entry(server_id)
12267 .or_default()
12268 .diagnostics
12269 .insert(Some(reg.id.clone()), caps.clone());
12270
12271 if let LanguageServerState::Running {
12272 workspace_diagnostics_refresh_tasks,
12273 ..
12274 } = state
12275 && let Some(task) = lsp_workspace_diagnostics_refresh(
12276 Some(reg.id.clone()),
12277 caps.clone(),
12278 server.clone(),
12279 cx,
12280 )
12281 {
12282 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12283 }
12284
12285 let mut did_update_caps = false;
12286 server.update_capabilities(|capabilities| {
12287 if capabilities.diagnostic_provider.as_ref().is_none_or(
12288 |current_caps| {
12289 let supports_workspace_diagnostics =
12290 |capabilities: &DiagnosticServerCapabilities| {
12291 match capabilities {
12292 DiagnosticServerCapabilities::Options(
12293 diagnostic_options,
12294 ) => diagnostic_options.workspace_diagnostics,
12295 DiagnosticServerCapabilities::RegistrationOptions(
12296 diagnostic_registration_options,
12297 ) => {
12298 diagnostic_registration_options
12299 .diagnostic_options
12300 .workspace_diagnostics
12301 }
12302 }
12303 };
12304 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12305 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12306 // as it'll think that they're not supported.
12307 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12308 !supports_workspace_diagnostics(current_caps)
12309 & supports_workspace_diagnostics(&caps)
12310 },
12311 ) {
12312 did_update_caps = true;
12313 capabilities.diagnostic_provider = Some(caps);
12314 }
12315 });
12316 if did_update_caps {
12317 notify_server_capabilities_updated(&server, cx);
12318 }
12319 }
12320 }
12321 "textDocument/documentColor" => {
12322 let options = parse_register_capabilities(reg)?;
12323 let provider = match options {
12324 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12325 OneOf::Right(caps) => caps,
12326 };
12327 server.update_capabilities(|capabilities| {
12328 capabilities.color_provider = Some(provider);
12329 });
12330 notify_server_capabilities_updated(&server, cx);
12331 }
12332 _ => log::warn!("unhandled capability registration: {reg:?}"),
12333 }
12334 }
12335
12336 Ok(())
12337 }
12338
12339 fn unregister_server_capabilities(
12340 &mut self,
12341 server_id: LanguageServerId,
12342 params: lsp::UnregistrationParams,
12343 cx: &mut Context<Self>,
12344 ) -> anyhow::Result<()> {
12345 let server = self
12346 .language_server_for_id(server_id)
12347 .with_context(|| format!("no server {server_id} found"))?;
12348 for unreg in params.unregisterations.iter() {
12349 match unreg.method.as_str() {
12350 "workspace/didChangeWatchedFiles" => {
12351 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12352 local_lsp_store
12353 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12354 true
12355 } else {
12356 false
12357 };
12358 if notify {
12359 notify_server_capabilities_updated(&server, cx);
12360 }
12361 }
12362 "workspace/didChangeConfiguration" => {
12363 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12364 }
12365 "workspace/didChangeWorkspaceFolders" => {
12366 server.update_capabilities(|capabilities| {
12367 capabilities
12368 .workspace
12369 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12370 workspace_folders: None,
12371 file_operations: None,
12372 })
12373 .workspace_folders = None;
12374 });
12375 notify_server_capabilities_updated(&server, cx);
12376 }
12377 "workspace/symbol" => {
12378 server.update_capabilities(|capabilities| {
12379 capabilities.workspace_symbol_provider = None
12380 });
12381 notify_server_capabilities_updated(&server, cx);
12382 }
12383 "workspace/fileOperations" => {
12384 server.update_capabilities(|capabilities| {
12385 capabilities
12386 .workspace
12387 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12388 workspace_folders: None,
12389 file_operations: None,
12390 })
12391 .file_operations = None;
12392 });
12393 notify_server_capabilities_updated(&server, cx);
12394 }
12395 "workspace/executeCommand" => {
12396 server.update_capabilities(|capabilities| {
12397 capabilities.execute_command_provider = None;
12398 });
12399 notify_server_capabilities_updated(&server, cx);
12400 }
12401 "textDocument/rangeFormatting" => {
12402 server.update_capabilities(|capabilities| {
12403 capabilities.document_range_formatting_provider = None
12404 });
12405 notify_server_capabilities_updated(&server, cx);
12406 }
12407 "textDocument/onTypeFormatting" => {
12408 server.update_capabilities(|capabilities| {
12409 capabilities.document_on_type_formatting_provider = None;
12410 });
12411 notify_server_capabilities_updated(&server, cx);
12412 }
12413 "textDocument/formatting" => {
12414 server.update_capabilities(|capabilities| {
12415 capabilities.document_formatting_provider = None;
12416 });
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 "textDocument/rename" => {
12420 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12421 notify_server_capabilities_updated(&server, cx);
12422 }
12423 "textDocument/codeAction" => {
12424 server.update_capabilities(|capabilities| {
12425 capabilities.code_action_provider = None;
12426 });
12427 notify_server_capabilities_updated(&server, cx);
12428 }
12429 "textDocument/definition" => {
12430 server.update_capabilities(|capabilities| {
12431 capabilities.definition_provider = None;
12432 });
12433 notify_server_capabilities_updated(&server, cx);
12434 }
12435 "textDocument/completion" => {
12436 server.update_capabilities(|capabilities| {
12437 capabilities.completion_provider = None;
12438 });
12439 notify_server_capabilities_updated(&server, cx);
12440 }
12441 "textDocument/hover" => {
12442 server.update_capabilities(|capabilities| {
12443 capabilities.hover_provider = None;
12444 });
12445 notify_server_capabilities_updated(&server, cx);
12446 }
12447 "textDocument/signatureHelp" => {
12448 server.update_capabilities(|capabilities| {
12449 capabilities.signature_help_provider = None;
12450 });
12451 notify_server_capabilities_updated(&server, cx);
12452 }
12453 "textDocument/didChange" => {
12454 server.update_capabilities(|capabilities| {
12455 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12456 sync_options.change = None;
12457 capabilities.text_document_sync =
12458 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12459 });
12460 notify_server_capabilities_updated(&server, cx);
12461 }
12462 "textDocument/didSave" => {
12463 server.update_capabilities(|capabilities| {
12464 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12465 sync_options.save = None;
12466 capabilities.text_document_sync =
12467 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12468 });
12469 notify_server_capabilities_updated(&server, cx);
12470 }
12471 "textDocument/codeLens" => {
12472 server.update_capabilities(|capabilities| {
12473 capabilities.code_lens_provider = None;
12474 });
12475 notify_server_capabilities_updated(&server, cx);
12476 }
12477 "textDocument/diagnostic" => {
12478 let local = self
12479 .as_local_mut()
12480 .context("Expected LSP Store to be local")?;
12481
12482 let state = local
12483 .language_servers
12484 .get_mut(&server_id)
12485 .context("Could not obtain Language Servers state")?;
12486 let options = local
12487 .language_server_dynamic_registrations
12488 .get_mut(&server_id)
12489 .with_context(|| {
12490 format!("Expected dynamic registration to exist for server {server_id}")
12491 })?.diagnostics
12492 .remove(&Some(unreg.id.clone()))
12493 .with_context(|| format!(
12494 "Attempted to unregister non-existent diagnostic registration with ID {}",
12495 unreg.id)
12496 )?;
12497
12498 let mut has_any_diagnostic_providers_still = true;
12499 if let Some(identifier) = diagnostic_identifier(&options)
12500 && let LanguageServerState::Running {
12501 workspace_diagnostics_refresh_tasks,
12502 ..
12503 } = state
12504 {
12505 workspace_diagnostics_refresh_tasks.remove(&identifier);
12506 has_any_diagnostic_providers_still =
12507 !workspace_diagnostics_refresh_tasks.is_empty();
12508 }
12509
12510 if !has_any_diagnostic_providers_still {
12511 server.update_capabilities(|capabilities| {
12512 debug_assert!(capabilities.diagnostic_provider.is_some());
12513 capabilities.diagnostic_provider = None;
12514 });
12515 }
12516
12517 notify_server_capabilities_updated(&server, cx);
12518 }
12519 "textDocument/documentColor" => {
12520 server.update_capabilities(|capabilities| {
12521 capabilities.color_provider = None;
12522 });
12523 notify_server_capabilities_updated(&server, cx);
12524 }
12525 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12526 }
12527 }
12528
12529 Ok(())
12530 }
12531
12532 async fn deduplicate_range_based_lsp_requests<T>(
12533 lsp_store: &Entity<Self>,
12534 server_id: Option<LanguageServerId>,
12535 lsp_request_id: LspRequestId,
12536 proto_request: &T::ProtoRequest,
12537 range: Range<Anchor>,
12538 cx: &mut AsyncApp,
12539 ) -> Result<()>
12540 where
12541 T: LspCommand,
12542 T::ProtoRequest: proto::LspRequestMessage,
12543 {
12544 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12545 let version = deserialize_version(proto_request.buffer_version());
12546 let buffer = lsp_store.update(cx, |this, cx| {
12547 this.buffer_store.read(cx).get_existing(buffer_id)
12548 })??;
12549 buffer
12550 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12551 .await?;
12552 lsp_store.update(cx, |lsp_store, cx| {
12553 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12554 let chunks_queried_for = lsp_data
12555 .inlay_hints
12556 .applicable_chunks(&[range])
12557 .collect::<Vec<_>>();
12558 match chunks_queried_for.as_slice() {
12559 &[chunk] => {
12560 let key = LspKey {
12561 request_type: TypeId::of::<T>(),
12562 server_queried: server_id,
12563 };
12564 let previous_request = lsp_data
12565 .chunk_lsp_requests
12566 .entry(key)
12567 .or_default()
12568 .insert(chunk, lsp_request_id);
12569 if let Some((previous_request, running_requests)) =
12570 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12571 {
12572 running_requests.remove(&previous_request);
12573 }
12574 }
12575 _ambiguous_chunks => {
12576 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12577 // there, a buffer version-based check will be performed and outdated requests discarded.
12578 }
12579 }
12580 anyhow::Ok(())
12581 })??;
12582
12583 Ok(())
12584 }
12585
12586 async fn query_lsp_locally<T>(
12587 lsp_store: Entity<Self>,
12588 for_server_id: Option<LanguageServerId>,
12589 sender_id: proto::PeerId,
12590 lsp_request_id: LspRequestId,
12591 proto_request: T::ProtoRequest,
12592 position: Option<Anchor>,
12593 cx: &mut AsyncApp,
12594 ) -> Result<()>
12595 where
12596 T: LspCommand + Clone,
12597 T::ProtoRequest: proto::LspRequestMessage,
12598 <T::ProtoRequest as proto::RequestMessage>::Response:
12599 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12600 {
12601 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12602 let version = deserialize_version(proto_request.buffer_version());
12603 let buffer = lsp_store.update(cx, |this, cx| {
12604 this.buffer_store.read(cx).get_existing(buffer_id)
12605 })??;
12606 buffer
12607 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12608 .await?;
12609 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12610 let request =
12611 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12612 let key = LspKey {
12613 request_type: TypeId::of::<T>(),
12614 server_queried: for_server_id,
12615 };
12616 lsp_store.update(cx, |lsp_store, cx| {
12617 let request_task = match for_server_id {
12618 Some(server_id) => {
12619 let server_task = lsp_store.request_lsp(
12620 buffer.clone(),
12621 LanguageServerToQuery::Other(server_id),
12622 request.clone(),
12623 cx,
12624 );
12625 cx.background_spawn(async move {
12626 let mut responses = Vec::new();
12627 match server_task.await {
12628 Ok(response) => responses.push((server_id, response)),
12629 // rust-analyzer likes to error with this when its still loading up
12630 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12631 Err(e) => log::error!(
12632 "Error handling response for request {request:?}: {e:#}"
12633 ),
12634 }
12635 responses
12636 })
12637 }
12638 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12639 };
12640 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12641 if T::ProtoRequest::stop_previous_requests() {
12642 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12643 lsp_requests.clear();
12644 }
12645 }
12646 lsp_data.lsp_requests.entry(key).or_default().insert(
12647 lsp_request_id,
12648 cx.spawn(async move |lsp_store, cx| {
12649 let response = request_task.await;
12650 lsp_store
12651 .update(cx, |lsp_store, cx| {
12652 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12653 {
12654 let response = response
12655 .into_iter()
12656 .map(|(server_id, response)| {
12657 (
12658 server_id.to_proto(),
12659 T::response_to_proto(
12660 response,
12661 lsp_store,
12662 sender_id,
12663 &buffer_version,
12664 cx,
12665 )
12666 .into(),
12667 )
12668 })
12669 .collect::<HashMap<_, _>>();
12670 match client.send_lsp_response::<T::ProtoRequest>(
12671 project_id,
12672 lsp_request_id,
12673 response,
12674 ) {
12675 Ok(()) => {}
12676 Err(e) => {
12677 log::error!("Failed to send LSP response: {e:#}",)
12678 }
12679 }
12680 }
12681 })
12682 .ok();
12683 }),
12684 );
12685 })?;
12686 Ok(())
12687 }
12688
12689 fn take_text_document_sync_options(
12690 capabilities: &mut lsp::ServerCapabilities,
12691 ) -> lsp::TextDocumentSyncOptions {
12692 match capabilities.text_document_sync.take() {
12693 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12694 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12695 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12696 sync_options.change = Some(sync_kind);
12697 sync_options
12698 }
12699 None => lsp::TextDocumentSyncOptions::default(),
12700 }
12701 }
12702
12703 #[cfg(any(test, feature = "test-support"))]
12704 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12705 Some(
12706 self.lsp_data
12707 .get_mut(&buffer_id)?
12708 .code_lens
12709 .take()?
12710 .update
12711 .take()?
12712 .1,
12713 )
12714 }
12715
12716 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12717 self.downstream_client.clone()
12718 }
12719
12720 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12721 self.worktree_store.clone()
12722 }
12723
12724 /// Gets what's stored in the LSP data for the given buffer.
12725 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12726 self.lsp_data.get_mut(&buffer_id)
12727 }
12728
12729 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12730 /// new [`BufferLspData`] will be created to replace the previous state.
12731 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12732 let (buffer_id, buffer_version) =
12733 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12734 let lsp_data = self
12735 .lsp_data
12736 .entry(buffer_id)
12737 .or_insert_with(|| BufferLspData::new(buffer, cx));
12738 if buffer_version.changed_since(&lsp_data.buffer_version) {
12739 *lsp_data = BufferLspData::new(buffer, cx);
12740 }
12741 lsp_data
12742 }
12743}
12744
12745// Registration with registerOptions as null, should fallback to true.
12746// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12747fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12748 reg: lsp::Registration,
12749) -> Result<OneOf<bool, T>> {
12750 Ok(match reg.register_options {
12751 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12752 None => OneOf::Left(true),
12753 })
12754}
12755
12756fn subscribe_to_binary_statuses(
12757 languages: &Arc<LanguageRegistry>,
12758 cx: &mut Context<'_, LspStore>,
12759) -> Task<()> {
12760 let mut server_statuses = languages.language_server_binary_statuses();
12761 cx.spawn(async move |lsp_store, cx| {
12762 while let Some((server_name, binary_status)) = server_statuses.next().await {
12763 if lsp_store
12764 .update(cx, |_, cx| {
12765 let mut message = None;
12766 let binary_status = match binary_status {
12767 BinaryStatus::None => proto::ServerBinaryStatus::None,
12768 BinaryStatus::CheckingForUpdate => {
12769 proto::ServerBinaryStatus::CheckingForUpdate
12770 }
12771 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12772 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12773 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12774 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12775 BinaryStatus::Failed { error } => {
12776 message = Some(error);
12777 proto::ServerBinaryStatus::Failed
12778 }
12779 };
12780 cx.emit(LspStoreEvent::LanguageServerUpdate {
12781 // Binary updates are about the binary that might not have any language server id at that point.
12782 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12783 language_server_id: LanguageServerId(0),
12784 name: Some(server_name),
12785 message: proto::update_language_server::Variant::StatusUpdate(
12786 proto::StatusUpdate {
12787 message,
12788 status: Some(proto::status_update::Status::Binary(
12789 binary_status as i32,
12790 )),
12791 },
12792 ),
12793 });
12794 })
12795 .is_err()
12796 {
12797 break;
12798 }
12799 }
12800 })
12801}
12802
12803fn lsp_workspace_diagnostics_refresh(
12804 registration_id: Option<String>,
12805 options: DiagnosticServerCapabilities,
12806 server: Arc<LanguageServer>,
12807 cx: &mut Context<'_, LspStore>,
12808) -> Option<WorkspaceRefreshTask> {
12809 let identifier = diagnostic_identifier(&options)?;
12810
12811 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12812 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12813 refresh_tx.try_send(()).ok();
12814
12815 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12816 let mut attempts = 0;
12817 let max_attempts = 50;
12818 let mut requests = 0;
12819
12820 loop {
12821 let Some(()) = refresh_rx.recv().await else {
12822 return;
12823 };
12824
12825 'request: loop {
12826 requests += 1;
12827 if attempts > max_attempts {
12828 log::error!(
12829 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12830 );
12831 return;
12832 }
12833 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12834 cx.background_executor()
12835 .timer(Duration::from_millis(backoff_millis))
12836 .await;
12837 attempts += 1;
12838
12839 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12840 lsp_store
12841 .all_result_ids(server.server_id())
12842 .into_iter()
12843 .filter_map(|(abs_path, result_id)| {
12844 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12845 Some(lsp::PreviousResultId {
12846 uri,
12847 value: result_id,
12848 })
12849 })
12850 .collect()
12851 }) else {
12852 return;
12853 };
12854
12855 let token = if let Some(identifier) = ®istration_id {
12856 format!(
12857 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12858 server.server_id(),
12859 )
12860 } else {
12861 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12862 };
12863
12864 progress_rx.try_recv().ok();
12865 let timer =
12866 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12867 let progress = pin!(progress_rx.recv().fuse());
12868 let response_result = server
12869 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12870 lsp::WorkspaceDiagnosticParams {
12871 previous_result_ids,
12872 identifier: identifier.clone(),
12873 work_done_progress_params: Default::default(),
12874 partial_result_params: lsp::PartialResultParams {
12875 partial_result_token: Some(lsp::ProgressToken::String(token)),
12876 },
12877 },
12878 select(timer, progress).then(|either| match either {
12879 Either::Left((message, ..)) => ready(message).left_future(),
12880 Either::Right(..) => pending::<String>().right_future(),
12881 }),
12882 )
12883 .await;
12884
12885 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12886 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12887 match response_result {
12888 ConnectionResult::Timeout => {
12889 log::error!("Timeout during workspace diagnostics pull");
12890 continue 'request;
12891 }
12892 ConnectionResult::ConnectionReset => {
12893 log::error!("Server closed a workspace diagnostics pull request");
12894 continue 'request;
12895 }
12896 ConnectionResult::Result(Err(e)) => {
12897 log::error!("Error during workspace diagnostics pull: {e:#}");
12898 break 'request;
12899 }
12900 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12901 attempts = 0;
12902 if lsp_store
12903 .update(cx, |lsp_store, cx| {
12904 lsp_store.apply_workspace_diagnostic_report(
12905 server.server_id(),
12906 pulled_diagnostics,
12907 cx,
12908 )
12909 })
12910 .is_err()
12911 {
12912 return;
12913 }
12914 break 'request;
12915 }
12916 }
12917 }
12918 }
12919 });
12920
12921 Some(WorkspaceRefreshTask {
12922 refresh_tx,
12923 progress_tx,
12924 task: workspace_query_language_server,
12925 })
12926}
12927
12928fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12929 match &options {
12930 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12931 if !diagnostic_options.workspace_diagnostics {
12932 return None;
12933 }
12934 Some(diagnostic_options.identifier.clone())
12935 }
12936 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12937 let diagnostic_options = ®istration_options.diagnostic_options;
12938 if !diagnostic_options.workspace_diagnostics {
12939 return None;
12940 }
12941 Some(diagnostic_options.identifier.clone())
12942 }
12943 }
12944}
12945
12946fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12947 let CompletionSource::BufferWord {
12948 word_range,
12949 resolved,
12950 } = &mut completion.source
12951 else {
12952 return;
12953 };
12954 if *resolved {
12955 return;
12956 }
12957
12958 if completion.new_text
12959 != snapshot
12960 .text_for_range(word_range.clone())
12961 .collect::<String>()
12962 {
12963 return;
12964 }
12965
12966 let mut offset = 0;
12967 for chunk in snapshot.chunks(word_range.clone(), true) {
12968 let end_offset = offset + chunk.text.len();
12969 if let Some(highlight_id) = chunk.syntax_highlight_id {
12970 completion
12971 .label
12972 .runs
12973 .push((offset..end_offset, highlight_id));
12974 }
12975 offset = end_offset;
12976 }
12977 *resolved = true;
12978}
12979
12980impl EventEmitter<LspStoreEvent> for LspStore {}
12981
12982fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12983 hover
12984 .contents
12985 .retain(|hover_block| !hover_block.text.trim().is_empty());
12986 if hover.contents.is_empty() {
12987 None
12988 } else {
12989 Some(hover)
12990 }
12991}
12992
12993async fn populate_labels_for_completions(
12994 new_completions: Vec<CoreCompletion>,
12995 language: Option<Arc<Language>>,
12996 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12997) -> Vec<Completion> {
12998 let lsp_completions = new_completions
12999 .iter()
13000 .filter_map(|new_completion| {
13001 new_completion
13002 .source
13003 .lsp_completion(true)
13004 .map(|lsp_completion| lsp_completion.into_owned())
13005 })
13006 .collect::<Vec<_>>();
13007
13008 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13009 lsp_adapter
13010 .labels_for_completions(&lsp_completions, language)
13011 .await
13012 .log_err()
13013 .unwrap_or_default()
13014 } else {
13015 Vec::new()
13016 }
13017 .into_iter()
13018 .fuse();
13019
13020 let mut completions = Vec::new();
13021 for completion in new_completions {
13022 match completion.source.lsp_completion(true) {
13023 Some(lsp_completion) => {
13024 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13025
13026 let mut label = labels.next().flatten().unwrap_or_else(|| {
13027 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13028 });
13029 ensure_uniform_list_compatible_label(&mut label);
13030 completions.push(Completion {
13031 label,
13032 documentation,
13033 replace_range: completion.replace_range,
13034 new_text: completion.new_text,
13035 insert_text_mode: lsp_completion.insert_text_mode,
13036 source: completion.source,
13037 icon_path: None,
13038 confirm: None,
13039 match_start: None,
13040 snippet_deduplication_key: None,
13041 });
13042 }
13043 None => {
13044 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13045 ensure_uniform_list_compatible_label(&mut label);
13046 completions.push(Completion {
13047 label,
13048 documentation: None,
13049 replace_range: completion.replace_range,
13050 new_text: completion.new_text,
13051 source: completion.source,
13052 insert_text_mode: None,
13053 icon_path: None,
13054 confirm: None,
13055 match_start: None,
13056 snippet_deduplication_key: None,
13057 });
13058 }
13059 }
13060 }
13061 completions
13062}
13063
13064#[derive(Debug)]
13065pub enum LanguageServerToQuery {
13066 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13067 FirstCapable,
13068 /// Query a specific language server.
13069 Other(LanguageServerId),
13070}
13071
13072#[derive(Default)]
13073struct RenamePathsWatchedForServer {
13074 did_rename: Vec<RenameActionPredicate>,
13075 will_rename: Vec<RenameActionPredicate>,
13076}
13077
13078impl RenamePathsWatchedForServer {
13079 fn with_did_rename_patterns(
13080 mut self,
13081 did_rename: Option<&FileOperationRegistrationOptions>,
13082 ) -> Self {
13083 if let Some(did_rename) = did_rename {
13084 self.did_rename = did_rename
13085 .filters
13086 .iter()
13087 .filter_map(|filter| filter.try_into().log_err())
13088 .collect();
13089 }
13090 self
13091 }
13092 fn with_will_rename_patterns(
13093 mut self,
13094 will_rename: Option<&FileOperationRegistrationOptions>,
13095 ) -> Self {
13096 if let Some(will_rename) = will_rename {
13097 self.will_rename = will_rename
13098 .filters
13099 .iter()
13100 .filter_map(|filter| filter.try_into().log_err())
13101 .collect();
13102 }
13103 self
13104 }
13105
13106 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13107 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13108 }
13109 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13110 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13111 }
13112}
13113
13114impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13115 type Error = globset::Error;
13116 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13117 Ok(Self {
13118 kind: ops.pattern.matches.clone(),
13119 glob: GlobBuilder::new(&ops.pattern.glob)
13120 .case_insensitive(
13121 ops.pattern
13122 .options
13123 .as_ref()
13124 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13125 )
13126 .build()?
13127 .compile_matcher(),
13128 })
13129 }
13130}
13131struct RenameActionPredicate {
13132 glob: GlobMatcher,
13133 kind: Option<FileOperationPatternKind>,
13134}
13135
13136impl RenameActionPredicate {
13137 // Returns true if language server should be notified
13138 fn eval(&self, path: &str, is_dir: bool) -> bool {
13139 self.kind.as_ref().is_none_or(|kind| {
13140 let expected_kind = if is_dir {
13141 FileOperationPatternKind::Folder
13142 } else {
13143 FileOperationPatternKind::File
13144 };
13145 kind == &expected_kind
13146 }) && self.glob.is_match(path)
13147 }
13148}
13149
13150#[derive(Default)]
13151struct LanguageServerWatchedPaths {
13152 worktree_paths: HashMap<WorktreeId, GlobSet>,
13153 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13154}
13155
13156#[derive(Default)]
13157struct LanguageServerWatchedPathsBuilder {
13158 worktree_paths: HashMap<WorktreeId, GlobSet>,
13159 abs_paths: HashMap<Arc<Path>, GlobSet>,
13160}
13161
13162impl LanguageServerWatchedPathsBuilder {
13163 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13164 self.worktree_paths.insert(worktree_id, glob_set);
13165 }
13166 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13167 self.abs_paths.insert(path, glob_set);
13168 }
13169 fn build(
13170 self,
13171 fs: Arc<dyn Fs>,
13172 language_server_id: LanguageServerId,
13173 cx: &mut Context<LspStore>,
13174 ) -> LanguageServerWatchedPaths {
13175 let lsp_store = cx.weak_entity();
13176
13177 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13178 let abs_paths = self
13179 .abs_paths
13180 .into_iter()
13181 .map(|(abs_path, globset)| {
13182 let task = cx.spawn({
13183 let abs_path = abs_path.clone();
13184 let fs = fs.clone();
13185
13186 let lsp_store = lsp_store.clone();
13187 async move |_, cx| {
13188 maybe!(async move {
13189 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13190 while let Some(update) = push_updates.0.next().await {
13191 let action = lsp_store
13192 .update(cx, |this, _| {
13193 let Some(local) = this.as_local() else {
13194 return ControlFlow::Break(());
13195 };
13196 let Some(watcher) = local
13197 .language_server_watched_paths
13198 .get(&language_server_id)
13199 else {
13200 return ControlFlow::Break(());
13201 };
13202 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13203 "Watched abs path is not registered with a watcher",
13204 );
13205 let matching_entries = update
13206 .into_iter()
13207 .filter(|event| globs.is_match(&event.path))
13208 .collect::<Vec<_>>();
13209 this.lsp_notify_abs_paths_changed(
13210 language_server_id,
13211 matching_entries,
13212 );
13213 ControlFlow::Continue(())
13214 })
13215 .ok()?;
13216
13217 if action.is_break() {
13218 break;
13219 }
13220 }
13221 Some(())
13222 })
13223 .await;
13224 }
13225 });
13226 (abs_path, (globset, task))
13227 })
13228 .collect();
13229 LanguageServerWatchedPaths {
13230 worktree_paths: self.worktree_paths,
13231 abs_paths,
13232 }
13233 }
13234}
13235
13236struct LspBufferSnapshot {
13237 version: i32,
13238 snapshot: TextBufferSnapshot,
13239}
13240
13241/// A prompt requested by LSP server.
13242#[derive(Clone, Debug)]
13243pub struct LanguageServerPromptRequest {
13244 pub level: PromptLevel,
13245 pub message: String,
13246 pub actions: Vec<MessageActionItem>,
13247 pub lsp_name: String,
13248 pub(crate) response_channel: Sender<MessageActionItem>,
13249}
13250
13251impl LanguageServerPromptRequest {
13252 pub async fn respond(self, index: usize) -> Option<()> {
13253 if let Some(response) = self.actions.into_iter().nth(index) {
13254 self.response_channel.send(response).await.ok()
13255 } else {
13256 None
13257 }
13258 }
13259}
13260impl PartialEq for LanguageServerPromptRequest {
13261 fn eq(&self, other: &Self) -> bool {
13262 self.message == other.message && self.actions == other.actions
13263 }
13264}
13265
13266#[derive(Clone, Debug, PartialEq)]
13267pub enum LanguageServerLogType {
13268 Log(MessageType),
13269 Trace { verbose_info: Option<String> },
13270 Rpc { received: bool },
13271}
13272
13273impl LanguageServerLogType {
13274 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13275 match self {
13276 Self::Log(log_type) => {
13277 use proto::log_message::LogLevel;
13278 let level = match *log_type {
13279 MessageType::ERROR => LogLevel::Error,
13280 MessageType::WARNING => LogLevel::Warning,
13281 MessageType::INFO => LogLevel::Info,
13282 MessageType::LOG => LogLevel::Log,
13283 other => {
13284 log::warn!("Unknown lsp log message type: {other:?}");
13285 LogLevel::Log
13286 }
13287 };
13288 proto::language_server_log::LogType::Log(proto::LogMessage {
13289 level: level as i32,
13290 })
13291 }
13292 Self::Trace { verbose_info } => {
13293 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13294 verbose_info: verbose_info.to_owned(),
13295 })
13296 }
13297 Self::Rpc { received } => {
13298 let kind = if *received {
13299 proto::rpc_message::Kind::Received
13300 } else {
13301 proto::rpc_message::Kind::Sent
13302 };
13303 let kind = kind as i32;
13304 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13305 }
13306 }
13307 }
13308
13309 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13310 use proto::log_message::LogLevel;
13311 use proto::rpc_message;
13312 match log_type {
13313 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13314 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13315 LogLevel::Error => MessageType::ERROR,
13316 LogLevel::Warning => MessageType::WARNING,
13317 LogLevel::Info => MessageType::INFO,
13318 LogLevel::Log => MessageType::LOG,
13319 },
13320 ),
13321 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13322 verbose_info: trace_message.verbose_info,
13323 },
13324 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13325 received: match rpc_message::Kind::from_i32(message.kind)
13326 .unwrap_or(rpc_message::Kind::Received)
13327 {
13328 rpc_message::Kind::Received => true,
13329 rpc_message::Kind::Sent => false,
13330 },
13331 },
13332 }
13333 }
13334}
13335
13336pub struct WorkspaceRefreshTask {
13337 refresh_tx: mpsc::Sender<()>,
13338 progress_tx: mpsc::Sender<()>,
13339 #[allow(dead_code)]
13340 task: Task<()>,
13341}
13342
13343pub enum LanguageServerState {
13344 Starting {
13345 startup: Task<Option<Arc<LanguageServer>>>,
13346 /// List of language servers that will be added to the workspace once it's initialization completes.
13347 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13348 },
13349
13350 Running {
13351 adapter: Arc<CachedLspAdapter>,
13352 server: Arc<LanguageServer>,
13353 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13354 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13355 },
13356}
13357
13358impl LanguageServerState {
13359 fn add_workspace_folder(&self, uri: Uri) {
13360 match self {
13361 LanguageServerState::Starting {
13362 pending_workspace_folders,
13363 ..
13364 } => {
13365 pending_workspace_folders.lock().insert(uri);
13366 }
13367 LanguageServerState::Running { server, .. } => {
13368 server.add_workspace_folder(uri);
13369 }
13370 }
13371 }
13372 fn _remove_workspace_folder(&self, uri: Uri) {
13373 match self {
13374 LanguageServerState::Starting {
13375 pending_workspace_folders,
13376 ..
13377 } => {
13378 pending_workspace_folders.lock().remove(&uri);
13379 }
13380 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13381 }
13382 }
13383}
13384
13385impl std::fmt::Debug for LanguageServerState {
13386 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13387 match self {
13388 LanguageServerState::Starting { .. } => {
13389 f.debug_struct("LanguageServerState::Starting").finish()
13390 }
13391 LanguageServerState::Running { .. } => {
13392 f.debug_struct("LanguageServerState::Running").finish()
13393 }
13394 }
13395 }
13396}
13397
13398#[derive(Clone, Debug, Serialize)]
13399pub struct LanguageServerProgress {
13400 pub is_disk_based_diagnostics_progress: bool,
13401 pub is_cancellable: bool,
13402 pub title: Option<String>,
13403 pub message: Option<String>,
13404 pub percentage: Option<usize>,
13405 #[serde(skip_serializing)]
13406 pub last_update_at: Instant,
13407}
13408
13409#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13410pub struct DiagnosticSummary {
13411 pub error_count: usize,
13412 pub warning_count: usize,
13413}
13414
13415impl DiagnosticSummary {
13416 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13417 let mut this = Self {
13418 error_count: 0,
13419 warning_count: 0,
13420 };
13421
13422 for entry in diagnostics {
13423 if entry.diagnostic.is_primary {
13424 match entry.diagnostic.severity {
13425 DiagnosticSeverity::ERROR => this.error_count += 1,
13426 DiagnosticSeverity::WARNING => this.warning_count += 1,
13427 _ => {}
13428 }
13429 }
13430 }
13431
13432 this
13433 }
13434
13435 pub fn is_empty(&self) -> bool {
13436 self.error_count == 0 && self.warning_count == 0
13437 }
13438
13439 pub fn to_proto(
13440 self,
13441 language_server_id: LanguageServerId,
13442 path: &RelPath,
13443 ) -> proto::DiagnosticSummary {
13444 proto::DiagnosticSummary {
13445 path: path.to_proto(),
13446 language_server_id: language_server_id.0 as u64,
13447 error_count: self.error_count as u32,
13448 warning_count: self.warning_count as u32,
13449 }
13450 }
13451}
13452
13453#[derive(Clone, Debug)]
13454pub enum CompletionDocumentation {
13455 /// There is no documentation for this completion.
13456 Undocumented,
13457 /// A single line of documentation.
13458 SingleLine(SharedString),
13459 /// Multiple lines of plain text documentation.
13460 MultiLinePlainText(SharedString),
13461 /// Markdown documentation.
13462 MultiLineMarkdown(SharedString),
13463 /// Both single line and multiple lines of plain text documentation.
13464 SingleLineAndMultiLinePlainText {
13465 single_line: SharedString,
13466 plain_text: Option<SharedString>,
13467 },
13468}
13469
13470impl CompletionDocumentation {
13471 #[cfg(any(test, feature = "test-support"))]
13472 pub fn text(&self) -> SharedString {
13473 match self {
13474 CompletionDocumentation::Undocumented => "".into(),
13475 CompletionDocumentation::SingleLine(s) => s.clone(),
13476 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13477 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13478 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13479 single_line.clone()
13480 }
13481 }
13482 }
13483}
13484
13485impl From<lsp::Documentation> for CompletionDocumentation {
13486 fn from(docs: lsp::Documentation) -> Self {
13487 match docs {
13488 lsp::Documentation::String(text) => {
13489 if text.lines().count() <= 1 {
13490 CompletionDocumentation::SingleLine(text.into())
13491 } else {
13492 CompletionDocumentation::MultiLinePlainText(text.into())
13493 }
13494 }
13495
13496 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13497 lsp::MarkupKind::PlainText => {
13498 if value.lines().count() <= 1 {
13499 CompletionDocumentation::SingleLine(value.into())
13500 } else {
13501 CompletionDocumentation::MultiLinePlainText(value.into())
13502 }
13503 }
13504
13505 lsp::MarkupKind::Markdown => {
13506 CompletionDocumentation::MultiLineMarkdown(value.into())
13507 }
13508 },
13509 }
13510 }
13511}
13512
13513pub enum ResolvedHint {
13514 Resolved(InlayHint),
13515 Resolving(Shared<Task<()>>),
13516}
13517
13518fn glob_literal_prefix(glob: &Path) -> PathBuf {
13519 glob.components()
13520 .take_while(|component| match component {
13521 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13522 _ => true,
13523 })
13524 .collect()
13525}
13526
13527pub struct SshLspAdapter {
13528 name: LanguageServerName,
13529 binary: LanguageServerBinary,
13530 initialization_options: Option<String>,
13531 code_action_kinds: Option<Vec<CodeActionKind>>,
13532}
13533
13534impl SshLspAdapter {
13535 pub fn new(
13536 name: LanguageServerName,
13537 binary: LanguageServerBinary,
13538 initialization_options: Option<String>,
13539 code_action_kinds: Option<String>,
13540 ) -> Self {
13541 Self {
13542 name,
13543 binary,
13544 initialization_options,
13545 code_action_kinds: code_action_kinds
13546 .as_ref()
13547 .and_then(|c| serde_json::from_str(c).ok()),
13548 }
13549 }
13550}
13551
13552impl LspInstaller for SshLspAdapter {
13553 type BinaryVersion = ();
13554 async fn check_if_user_installed(
13555 &self,
13556 _: &dyn LspAdapterDelegate,
13557 _: Option<Toolchain>,
13558 _: &AsyncApp,
13559 ) -> Option<LanguageServerBinary> {
13560 Some(self.binary.clone())
13561 }
13562
13563 async fn cached_server_binary(
13564 &self,
13565 _: PathBuf,
13566 _: &dyn LspAdapterDelegate,
13567 ) -> Option<LanguageServerBinary> {
13568 None
13569 }
13570
13571 async fn fetch_latest_server_version(
13572 &self,
13573 _: &dyn LspAdapterDelegate,
13574 _: bool,
13575 _: &mut AsyncApp,
13576 ) -> Result<()> {
13577 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13578 }
13579
13580 async fn fetch_server_binary(
13581 &self,
13582 _: (),
13583 _: PathBuf,
13584 _: &dyn LspAdapterDelegate,
13585 ) -> Result<LanguageServerBinary> {
13586 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13587 }
13588}
13589
13590#[async_trait(?Send)]
13591impl LspAdapter for SshLspAdapter {
13592 fn name(&self) -> LanguageServerName {
13593 self.name.clone()
13594 }
13595
13596 async fn initialization_options(
13597 self: Arc<Self>,
13598 _: &Arc<dyn LspAdapterDelegate>,
13599 ) -> Result<Option<serde_json::Value>> {
13600 let Some(options) = &self.initialization_options else {
13601 return Ok(None);
13602 };
13603 let result = serde_json::from_str(options)?;
13604 Ok(result)
13605 }
13606
13607 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13608 self.code_action_kinds.clone()
13609 }
13610}
13611
13612pub fn language_server_settings<'a>(
13613 delegate: &'a dyn LspAdapterDelegate,
13614 language: &LanguageServerName,
13615 cx: &'a App,
13616) -> Option<&'a LspSettings> {
13617 language_server_settings_for(
13618 SettingsLocation {
13619 worktree_id: delegate.worktree_id(),
13620 path: RelPath::empty(),
13621 },
13622 language,
13623 cx,
13624 )
13625}
13626
13627pub(crate) fn language_server_settings_for<'a>(
13628 location: SettingsLocation<'a>,
13629 language: &LanguageServerName,
13630 cx: &'a App,
13631) -> Option<&'a LspSettings> {
13632 ProjectSettings::get(Some(location), cx).lsp.get(language)
13633}
13634
13635pub struct LocalLspAdapterDelegate {
13636 lsp_store: WeakEntity<LspStore>,
13637 worktree: worktree::Snapshot,
13638 fs: Arc<dyn Fs>,
13639 http_client: Arc<dyn HttpClient>,
13640 language_registry: Arc<LanguageRegistry>,
13641 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13642}
13643
13644impl LocalLspAdapterDelegate {
13645 pub fn new(
13646 language_registry: Arc<LanguageRegistry>,
13647 environment: &Entity<ProjectEnvironment>,
13648 lsp_store: WeakEntity<LspStore>,
13649 worktree: &Entity<Worktree>,
13650 http_client: Arc<dyn HttpClient>,
13651 fs: Arc<dyn Fs>,
13652 cx: &mut App,
13653 ) -> Arc<Self> {
13654 let load_shell_env_task =
13655 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13656
13657 Arc::new(Self {
13658 lsp_store,
13659 worktree: worktree.read(cx).snapshot(),
13660 fs,
13661 http_client,
13662 language_registry,
13663 load_shell_env_task,
13664 })
13665 }
13666
13667 fn from_local_lsp(
13668 local: &LocalLspStore,
13669 worktree: &Entity<Worktree>,
13670 cx: &mut App,
13671 ) -> Arc<Self> {
13672 Self::new(
13673 local.languages.clone(),
13674 &local.environment,
13675 local.weak.clone(),
13676 worktree,
13677 local.http_client.clone(),
13678 local.fs.clone(),
13679 cx,
13680 )
13681 }
13682}
13683
13684#[async_trait]
13685impl LspAdapterDelegate for LocalLspAdapterDelegate {
13686 fn show_notification(&self, message: &str, cx: &mut App) {
13687 self.lsp_store
13688 .update(cx, |_, cx| {
13689 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13690 })
13691 .ok();
13692 }
13693
13694 fn http_client(&self) -> Arc<dyn HttpClient> {
13695 self.http_client.clone()
13696 }
13697
13698 fn worktree_id(&self) -> WorktreeId {
13699 self.worktree.id()
13700 }
13701
13702 fn worktree_root_path(&self) -> &Path {
13703 self.worktree.abs_path().as_ref()
13704 }
13705
13706 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13707 self.worktree.resolve_executable_path(path)
13708 }
13709
13710 async fn shell_env(&self) -> HashMap<String, String> {
13711 let task = self.load_shell_env_task.clone();
13712 task.await.unwrap_or_default()
13713 }
13714
13715 async fn npm_package_installed_version(
13716 &self,
13717 package_name: &str,
13718 ) -> Result<Option<(PathBuf, String)>> {
13719 let local_package_directory = self.worktree_root_path();
13720 let node_modules_directory = local_package_directory.join("node_modules");
13721
13722 if let Some(version) =
13723 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13724 {
13725 return Ok(Some((node_modules_directory, version)));
13726 }
13727 let Some(npm) = self.which("npm".as_ref()).await else {
13728 log::warn!(
13729 "Failed to find npm executable for {:?}",
13730 local_package_directory
13731 );
13732 return Ok(None);
13733 };
13734
13735 let env = self.shell_env().await;
13736 let output = util::command::new_smol_command(&npm)
13737 .args(["root", "-g"])
13738 .envs(env)
13739 .current_dir(local_package_directory)
13740 .output()
13741 .await?;
13742 let global_node_modules =
13743 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13744
13745 if let Some(version) =
13746 read_package_installed_version(global_node_modules.clone(), package_name).await?
13747 {
13748 return Ok(Some((global_node_modules, version)));
13749 }
13750 return Ok(None);
13751 }
13752
13753 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13754 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13755 if self.fs.is_file(&worktree_abs_path).await {
13756 worktree_abs_path.pop();
13757 }
13758
13759 let env = self.shell_env().await;
13760
13761 let shell_path = env.get("PATH").cloned();
13762
13763 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13764 }
13765
13766 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13767 let mut working_dir = self.worktree_root_path().to_path_buf();
13768 if self.fs.is_file(&working_dir).await {
13769 working_dir.pop();
13770 }
13771 let output = util::command::new_smol_command(&command.path)
13772 .args(command.arguments)
13773 .envs(command.env.clone().unwrap_or_default())
13774 .current_dir(working_dir)
13775 .output()
13776 .await?;
13777
13778 anyhow::ensure!(
13779 output.status.success(),
13780 "{}, stdout: {:?}, stderr: {:?}",
13781 output.status,
13782 String::from_utf8_lossy(&output.stdout),
13783 String::from_utf8_lossy(&output.stderr)
13784 );
13785 Ok(())
13786 }
13787
13788 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13789 self.language_registry
13790 .update_lsp_binary_status(server_name, status);
13791 }
13792
13793 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13794 self.language_registry
13795 .all_lsp_adapters()
13796 .into_iter()
13797 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13798 .collect()
13799 }
13800
13801 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13802 let dir = self.language_registry.language_server_download_dir(name)?;
13803
13804 if !dir.exists() {
13805 smol::fs::create_dir_all(&dir)
13806 .await
13807 .context("failed to create container directory")
13808 .log_err()?;
13809 }
13810
13811 Some(dir)
13812 }
13813
13814 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13815 let entry = self
13816 .worktree
13817 .entry_for_path(path)
13818 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13819 let abs_path = self.worktree.absolutize(&entry.path);
13820 self.fs.load(&abs_path).await
13821 }
13822}
13823
13824async fn populate_labels_for_symbols(
13825 symbols: Vec<CoreSymbol>,
13826 language_registry: &Arc<LanguageRegistry>,
13827 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13828 output: &mut Vec<Symbol>,
13829) {
13830 #[allow(clippy::mutable_key_type)]
13831 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13832
13833 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13834 for symbol in symbols {
13835 let Some(file_name) = symbol.path.file_name() else {
13836 continue;
13837 };
13838 let language = language_registry
13839 .load_language_for_file_path(Path::new(file_name))
13840 .await
13841 .ok()
13842 .or_else(|| {
13843 unknown_paths.insert(file_name.into());
13844 None
13845 });
13846 symbols_by_language
13847 .entry(language)
13848 .or_default()
13849 .push(symbol);
13850 }
13851
13852 for unknown_path in unknown_paths {
13853 log::info!("no language found for symbol in file {unknown_path:?}");
13854 }
13855
13856 let mut label_params = Vec::new();
13857 for (language, mut symbols) in symbols_by_language {
13858 label_params.clear();
13859 label_params.extend(
13860 symbols
13861 .iter_mut()
13862 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13863 );
13864
13865 let mut labels = Vec::new();
13866 if let Some(language) = language {
13867 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13868 language_registry
13869 .lsp_adapters(&language.name())
13870 .first()
13871 .cloned()
13872 });
13873 if let Some(lsp_adapter) = lsp_adapter {
13874 labels = lsp_adapter
13875 .labels_for_symbols(&label_params, &language)
13876 .await
13877 .log_err()
13878 .unwrap_or_default();
13879 }
13880 }
13881
13882 for ((symbol, (name, _)), label) in symbols
13883 .into_iter()
13884 .zip(label_params.drain(..))
13885 .zip(labels.into_iter().chain(iter::repeat(None)))
13886 {
13887 output.push(Symbol {
13888 language_server_name: symbol.language_server_name,
13889 source_worktree_id: symbol.source_worktree_id,
13890 source_language_server_id: symbol.source_language_server_id,
13891 path: symbol.path,
13892 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13893 name,
13894 kind: symbol.kind,
13895 range: symbol.range,
13896 });
13897 }
13898 }
13899}
13900
13901fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13902 match server.capabilities().text_document_sync.as_ref()? {
13903 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13904 // Server wants didSave but didn't specify includeText.
13905 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13906 // Server doesn't want didSave at all.
13907 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13908 // Server provided SaveOptions.
13909 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13910 Some(save_options.include_text.unwrap_or(false))
13911 }
13912 },
13913 // We do not have any save info. Kind affects didChange only.
13914 lsp::TextDocumentSyncCapability::Kind(_) => None,
13915 }
13916}
13917
13918/// Completion items are displayed in a `UniformList`.
13919/// Usually, those items are single-line strings, but in LSP responses,
13920/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13921/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13922/// 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,
13923/// breaking the completions menu presentation.
13924///
13925/// 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.
13926fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13927 let mut new_text = String::with_capacity(label.text.len());
13928 let mut offset_map = vec![0; label.text.len() + 1];
13929 let mut last_char_was_space = false;
13930 let mut new_idx = 0;
13931 let chars = label.text.char_indices().fuse();
13932 let mut newlines_removed = false;
13933
13934 for (idx, c) in chars {
13935 offset_map[idx] = new_idx;
13936
13937 match c {
13938 '\n' if last_char_was_space => {
13939 newlines_removed = true;
13940 }
13941 '\t' | ' ' if last_char_was_space => {}
13942 '\n' if !last_char_was_space => {
13943 new_text.push(' ');
13944 new_idx += 1;
13945 last_char_was_space = true;
13946 newlines_removed = true;
13947 }
13948 ' ' | '\t' => {
13949 new_text.push(' ');
13950 new_idx += 1;
13951 last_char_was_space = true;
13952 }
13953 _ => {
13954 new_text.push(c);
13955 new_idx += c.len_utf8();
13956 last_char_was_space = false;
13957 }
13958 }
13959 }
13960 offset_map[label.text.len()] = new_idx;
13961
13962 // Only modify the label if newlines were removed.
13963 if !newlines_removed {
13964 return;
13965 }
13966
13967 let last_index = new_idx;
13968 let mut run_ranges_errors = Vec::new();
13969 label.runs.retain_mut(|(range, _)| {
13970 match offset_map.get(range.start) {
13971 Some(&start) => range.start = start,
13972 None => {
13973 run_ranges_errors.push(range.clone());
13974 return false;
13975 }
13976 }
13977
13978 match offset_map.get(range.end) {
13979 Some(&end) => range.end = end,
13980 None => {
13981 run_ranges_errors.push(range.clone());
13982 range.end = last_index;
13983 }
13984 }
13985 true
13986 });
13987 if !run_ranges_errors.is_empty() {
13988 log::error!(
13989 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13990 label.text
13991 );
13992 }
13993
13994 let mut wrong_filter_range = None;
13995 if label.filter_range == (0..label.text.len()) {
13996 label.filter_range = 0..new_text.len();
13997 } else {
13998 let mut original_filter_range = Some(label.filter_range.clone());
13999 match offset_map.get(label.filter_range.start) {
14000 Some(&start) => label.filter_range.start = start,
14001 None => {
14002 wrong_filter_range = original_filter_range.take();
14003 label.filter_range.start = last_index;
14004 }
14005 }
14006
14007 match offset_map.get(label.filter_range.end) {
14008 Some(&end) => label.filter_range.end = end,
14009 None => {
14010 wrong_filter_range = original_filter_range.take();
14011 label.filter_range.end = last_index;
14012 }
14013 }
14014 }
14015 if let Some(wrong_filter_range) = wrong_filter_range {
14016 log::error!(
14017 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14018 label.text
14019 );
14020 }
14021
14022 label.text = new_text;
14023}
14024
14025#[cfg(test)]
14026mod tests {
14027 use language::HighlightId;
14028
14029 use super::*;
14030
14031 #[test]
14032 fn test_glob_literal_prefix() {
14033 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14034 assert_eq!(
14035 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14036 Path::new("node_modules")
14037 );
14038 assert_eq!(
14039 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14040 Path::new("foo")
14041 );
14042 assert_eq!(
14043 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14044 Path::new("foo/bar/baz.js")
14045 );
14046
14047 #[cfg(target_os = "windows")]
14048 {
14049 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14050 assert_eq!(
14051 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14052 Path::new("node_modules")
14053 );
14054 assert_eq!(
14055 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14056 Path::new("foo")
14057 );
14058 assert_eq!(
14059 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14060 Path::new("foo/bar/baz.js")
14061 );
14062 }
14063 }
14064
14065 #[test]
14066 fn test_multi_len_chars_normalization() {
14067 let mut label = CodeLabel::new(
14068 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14069 0..6,
14070 vec![(0..6, HighlightId(1))],
14071 );
14072 ensure_uniform_list_compatible_label(&mut label);
14073 assert_eq!(
14074 label,
14075 CodeLabel::new(
14076 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14077 0..6,
14078 vec![(0..6, HighlightId(1))],
14079 )
14080 );
14081 }
14082}