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 None,
440 cx,
441 )
442 .await?;
443
444 let mut initialization_options = Self::initialization_options_for_adapter(
445 adapter.adapter.clone(),
446 &delegate,
447 )
448 .await?;
449
450 match (&mut initialization_options, override_options) {
451 (Some(initialization_options), Some(override_options)) => {
452 merge_json_value_into(override_options, initialization_options);
453 }
454 (None, override_options) => initialization_options = override_options,
455 _ => {}
456 }
457
458 let initialization_params = cx.update(|cx| {
459 let mut params =
460 language_server.default_initialize_params(pull_diagnostics, cx);
461 params.initialization_options = initialization_options;
462 adapter.adapter.prepare_initialize_params(params, cx)
463 })??;
464
465 Self::setup_lsp_messages(
466 lsp_store.clone(),
467 &language_server,
468 delegate.clone(),
469 adapter.clone(),
470 );
471
472 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
473 settings: workspace_config,
474 };
475 let language_server = cx
476 .update(|cx| {
477 language_server.initialize(
478 initialization_params,
479 Arc::new(did_change_configuration_params.clone()),
480 cx,
481 )
482 })?
483 .await
484 .inspect_err(|_| {
485 if let Some(lsp_store) = lsp_store.upgrade() {
486 lsp_store
487 .update(cx, |lsp_store, cx| {
488 lsp_store.cleanup_lsp_data(server_id);
489 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
490 })
491 .ok();
492 }
493 })?;
494
495 language_server.notify::<lsp::notification::DidChangeConfiguration>(
496 did_change_configuration_params,
497 )?;
498
499 anyhow::Ok(language_server)
500 }
501 .await;
502
503 match result {
504 Ok(server) => {
505 lsp_store
506 .update(cx, |lsp_store, cx| {
507 lsp_store.insert_newly_running_language_server(
508 adapter,
509 server.clone(),
510 server_id,
511 key,
512 pending_workspace_folders,
513 cx,
514 );
515 })
516 .ok();
517 stderr_capture.lock().take();
518 Some(server)
519 }
520
521 Err(err) => {
522 let log = stderr_capture.lock().take().unwrap_or_default();
523 delegate.update_status(
524 adapter.name(),
525 BinaryStatus::Failed {
526 error: if log.is_empty() {
527 format!("{err:#}")
528 } else {
529 format!("{err:#}\n-- stderr --\n{log}")
530 },
531 },
532 );
533 log::error!("Failed to start language server {server_name:?}: {err:?}");
534 if !log.is_empty() {
535 log::error!("server stderr: {log}");
536 }
537 None
538 }
539 }
540 })
541 };
542 let state = LanguageServerState::Starting {
543 startup,
544 pending_workspace_folders,
545 };
546
547 self.languages
548 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
549
550 self.language_servers.insert(server_id, state);
551 self.language_server_ids
552 .entry(key)
553 .or_insert(UnifiedLanguageServer {
554 id: server_id,
555 project_roots: Default::default(),
556 });
557 server_id
558 }
559
560 fn get_language_server_binary(
561 &self,
562 adapter: Arc<CachedLspAdapter>,
563 settings: Arc<LspSettings>,
564 toolchain: Option<Toolchain>,
565 delegate: Arc<dyn LspAdapterDelegate>,
566 allow_binary_download: bool,
567 cx: &mut App,
568 ) -> Task<Result<LanguageServerBinary>> {
569 if let Some(settings) = &settings.binary
570 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
571 {
572 let settings = settings.clone();
573
574 return cx.background_spawn(async move {
575 let mut env = delegate.shell_env().await;
576 env.extend(settings.env.unwrap_or_default());
577
578 Ok(LanguageServerBinary {
579 path: delegate.resolve_executable_path(path),
580 env: Some(env),
581 arguments: settings
582 .arguments
583 .unwrap_or_default()
584 .iter()
585 .map(Into::into)
586 .collect(),
587 })
588 });
589 }
590 let lsp_binary_options = LanguageServerBinaryOptions {
591 allow_path_lookup: !settings
592 .binary
593 .as_ref()
594 .and_then(|b| b.ignore_system_version)
595 .unwrap_or_default(),
596 allow_binary_download,
597 pre_release: settings
598 .fetch
599 .as_ref()
600 .and_then(|f| f.pre_release)
601 .unwrap_or(false),
602 };
603
604 cx.spawn(async move |cx| {
605 let (existing_binary, maybe_download_binary) = adapter
606 .clone()
607 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
608 .await
609 .await;
610
611 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
612
613 let mut binary = match (existing_binary, maybe_download_binary) {
614 (binary, None) => binary?,
615 (Err(_), Some(downloader)) => downloader.await?,
616 (Ok(existing_binary), Some(downloader)) => {
617 let mut download_timeout = cx
618 .background_executor()
619 .timer(SERVER_DOWNLOAD_TIMEOUT)
620 .fuse();
621 let mut downloader = downloader.fuse();
622 futures::select! {
623 _ = download_timeout => {
624 // Return existing binary and kick the existing work to the background.
625 cx.spawn(async move |_| downloader.await).detach();
626 Ok(existing_binary)
627 },
628 downloaded_or_existing_binary = downloader => {
629 // If download fails, this results in the existing binary.
630 downloaded_or_existing_binary
631 }
632 }?
633 }
634 };
635 let mut shell_env = delegate.shell_env().await;
636
637 shell_env.extend(binary.env.unwrap_or_default());
638
639 if let Some(settings) = settings.binary.as_ref() {
640 if let Some(arguments) = &settings.arguments {
641 binary.arguments = arguments.iter().map(Into::into).collect();
642 }
643 if let Some(env) = &settings.env {
644 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
645 }
646 }
647
648 binary.env = Some(shell_env);
649 Ok(binary)
650 })
651 }
652
653 fn setup_lsp_messages(
654 lsp_store: WeakEntity<LspStore>,
655 language_server: &LanguageServer,
656 delegate: Arc<dyn LspAdapterDelegate>,
657 adapter: Arc<CachedLspAdapter>,
658 ) {
659 let name = language_server.name();
660 let server_id = language_server.server_id();
661 language_server
662 .on_notification::<lsp::notification::PublishDiagnostics, _>({
663 let adapter = adapter.clone();
664 let this = lsp_store.clone();
665 move |mut params, cx| {
666 let adapter = adapter.clone();
667 if let Some(this) = this.upgrade() {
668 this.update(cx, |this, cx| {
669 {
670 let buffer = params
671 .uri
672 .to_file_path()
673 .map(|file_path| this.get_buffer(&file_path, cx))
674 .ok()
675 .flatten();
676 adapter.process_diagnostics(&mut params, server_id, buffer);
677 }
678
679 this.merge_lsp_diagnostics(
680 DiagnosticSourceKind::Pushed,
681 vec![DocumentDiagnosticsUpdate {
682 server_id,
683 diagnostics: params,
684 result_id: None,
685 disk_based_sources: Cow::Borrowed(
686 &adapter.disk_based_diagnostic_sources,
687 ),
688 }],
689 |_, diagnostic, cx| match diagnostic.source_kind {
690 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
691 adapter.retain_old_diagnostic(diagnostic, cx)
692 }
693 DiagnosticSourceKind::Pulled => true,
694 },
695 cx,
696 )
697 .log_err();
698 })
699 .ok();
700 }
701 }
702 })
703 .detach();
704 language_server
705 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
706 let adapter = adapter.adapter.clone();
707 let delegate = delegate.clone();
708 let this = lsp_store.clone();
709 move |params, cx| {
710 let adapter = adapter.clone();
711 let delegate = delegate.clone();
712 let this = this.clone();
713 let mut cx = cx.clone();
714 async move {
715 let toolchain_for_id = this
716 .update(&mut cx, |this, _| {
717 this.as_local()?.language_server_ids.iter().find_map(
718 |(seed, value)| {
719 (value.id == server_id).then(|| seed.toolchain.clone())
720 },
721 )
722 })?
723 .context("Expected the LSP store to be in a local mode")?;
724
725 let mut scope_uri_to_workspace_config = BTreeMap::new();
726 for item in ¶ms.items {
727 let scope_uri = item.scope_uri.clone();
728 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
729 scope_uri_to_workspace_config.entry(scope_uri.clone())
730 else {
731 // We've already queried workspace configuration of this URI.
732 continue;
733 };
734 let workspace_config = Self::workspace_configuration_for_adapter(
735 adapter.clone(),
736 &delegate,
737 toolchain_for_id.clone(),
738 scope_uri,
739 &mut cx,
740 )
741 .await?;
742 new_scope_uri.insert(workspace_config);
743 }
744
745 Ok(params
746 .items
747 .into_iter()
748 .filter_map(|item| {
749 let workspace_config =
750 scope_uri_to_workspace_config.get(&item.scope_uri)?;
751 if let Some(section) = &item.section {
752 Some(
753 workspace_config
754 .get(section)
755 .cloned()
756 .unwrap_or(serde_json::Value::Null),
757 )
758 } else {
759 Some(workspace_config.clone())
760 }
761 })
762 .collect())
763 }
764 }
765 })
766 .detach();
767
768 language_server
769 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
770 let this = lsp_store.clone();
771 move |_, cx| {
772 let this = this.clone();
773 let cx = cx.clone();
774 async move {
775 let Some(server) =
776 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
777 else {
778 return Ok(None);
779 };
780 let root = server.workspace_folders();
781 Ok(Some(
782 root.into_iter()
783 .map(|uri| WorkspaceFolder {
784 uri,
785 name: Default::default(),
786 })
787 .collect(),
788 ))
789 }
790 }
791 })
792 .detach();
793 // Even though we don't have handling for these requests, respond to them to
794 // avoid stalling any language server like `gopls` which waits for a response
795 // to these requests when initializing.
796 language_server
797 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
798 let this = lsp_store.clone();
799 move |params, cx| {
800 let this = this.clone();
801 let mut cx = cx.clone();
802 async move {
803 this.update(&mut cx, |this, _| {
804 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
805 {
806 status
807 .progress_tokens
808 .insert(ProgressToken::from_lsp(params.token));
809 }
810 })?;
811
812 Ok(())
813 }
814 }
815 })
816 .detach();
817
818 language_server
819 .on_request::<lsp::request::RegisterCapability, _, _>({
820 let lsp_store = lsp_store.clone();
821 move |params, cx| {
822 let lsp_store = lsp_store.clone();
823 let mut cx = cx.clone();
824 async move {
825 lsp_store
826 .update(&mut cx, |lsp_store, cx| {
827 if lsp_store.as_local().is_some() {
828 match lsp_store
829 .register_server_capabilities(server_id, params, cx)
830 {
831 Ok(()) => {}
832 Err(e) => {
833 log::error!(
834 "Failed to register server capabilities: {e:#}"
835 );
836 }
837 };
838 }
839 })
840 .ok();
841 Ok(())
842 }
843 }
844 })
845 .detach();
846
847 language_server
848 .on_request::<lsp::request::UnregisterCapability, _, _>({
849 let lsp_store = lsp_store.clone();
850 move |params, cx| {
851 let lsp_store = lsp_store.clone();
852 let mut cx = cx.clone();
853 async move {
854 lsp_store
855 .update(&mut cx, |lsp_store, cx| {
856 if lsp_store.as_local().is_some() {
857 match lsp_store
858 .unregister_server_capabilities(server_id, params, cx)
859 {
860 Ok(()) => {}
861 Err(e) => {
862 log::error!(
863 "Failed to unregister server capabilities: {e:#}"
864 );
865 }
866 }
867 }
868 })
869 .ok();
870 Ok(())
871 }
872 }
873 })
874 .detach();
875
876 language_server
877 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
878 let this = lsp_store.clone();
879 move |params, cx| {
880 let mut cx = cx.clone();
881 let this = this.clone();
882 async move {
883 LocalLspStore::on_lsp_workspace_edit(
884 this.clone(),
885 params,
886 server_id,
887 &mut cx,
888 )
889 .await
890 }
891 }
892 })
893 .detach();
894
895 language_server
896 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
897 let lsp_store = lsp_store.clone();
898 let request_id = Arc::new(AtomicUsize::new(0));
899 move |(), cx| {
900 let lsp_store = lsp_store.clone();
901 let request_id = request_id.clone();
902 let mut cx = cx.clone();
903 async move {
904 lsp_store
905 .update(&mut cx, |lsp_store, cx| {
906 let request_id =
907 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
908 cx.emit(LspStoreEvent::RefreshInlayHints {
909 server_id,
910 request_id,
911 });
912 lsp_store
913 .downstream_client
914 .as_ref()
915 .map(|(client, project_id)| {
916 client.send(proto::RefreshInlayHints {
917 project_id: *project_id,
918 server_id: server_id.to_proto(),
919 request_id: request_id.map(|id| id as u64),
920 })
921 })
922 })?
923 .transpose()?;
924 Ok(())
925 }
926 }
927 })
928 .detach();
929
930 language_server
931 .on_request::<lsp::request::CodeLensRefresh, _, _>({
932 let this = lsp_store.clone();
933 move |(), cx| {
934 let this = this.clone();
935 let mut cx = cx.clone();
936 async move {
937 this.update(&mut cx, |this, cx| {
938 cx.emit(LspStoreEvent::RefreshCodeLens);
939 this.downstream_client.as_ref().map(|(client, project_id)| {
940 client.send(proto::RefreshCodeLens {
941 project_id: *project_id,
942 })
943 })
944 })?
945 .transpose()?;
946 Ok(())
947 }
948 }
949 })
950 .detach();
951
952 language_server
953 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
954 let this = lsp_store.clone();
955 move |(), cx| {
956 let this = this.clone();
957 let mut cx = cx.clone();
958 async move {
959 this.update(&mut cx, |lsp_store, _| {
960 lsp_store.pull_workspace_diagnostics(server_id);
961 lsp_store
962 .downstream_client
963 .as_ref()
964 .map(|(client, project_id)| {
965 client.send(proto::PullWorkspaceDiagnostics {
966 project_id: *project_id,
967 server_id: server_id.to_proto(),
968 })
969 })
970 })?
971 .transpose()?;
972 Ok(())
973 }
974 }
975 })
976 .detach();
977
978 language_server
979 .on_request::<lsp::request::ShowMessageRequest, _, _>({
980 let this = lsp_store.clone();
981 let name = name.to_string();
982 move |params, cx| {
983 let this = this.clone();
984 let name = name.to_string();
985 let mut cx = cx.clone();
986 async move {
987 let actions = params.actions.unwrap_or_default();
988 let (tx, rx) = smol::channel::bounded(1);
989 let request = LanguageServerPromptRequest {
990 level: match params.typ {
991 lsp::MessageType::ERROR => PromptLevel::Critical,
992 lsp::MessageType::WARNING => PromptLevel::Warning,
993 _ => PromptLevel::Info,
994 },
995 message: params.message,
996 actions,
997 response_channel: tx,
998 lsp_name: name.clone(),
999 };
1000
1001 let did_update = this
1002 .update(&mut cx, |_, cx| {
1003 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1004 })
1005 .is_ok();
1006 if did_update {
1007 let response = rx.recv().await.ok();
1008 Ok(response)
1009 } else {
1010 Ok(None)
1011 }
1012 }
1013 }
1014 })
1015 .detach();
1016 language_server
1017 .on_notification::<lsp::notification::ShowMessage, _>({
1018 let this = lsp_store.clone();
1019 let name = name.to_string();
1020 move |params, cx| {
1021 let this = this.clone();
1022 let name = name.to_string();
1023 let mut cx = cx.clone();
1024
1025 let (tx, _) = smol::channel::bounded(1);
1026 let request = LanguageServerPromptRequest {
1027 level: match params.typ {
1028 lsp::MessageType::ERROR => PromptLevel::Critical,
1029 lsp::MessageType::WARNING => PromptLevel::Warning,
1030 _ => PromptLevel::Info,
1031 },
1032 message: params.message,
1033 actions: vec![],
1034 response_channel: tx,
1035 lsp_name: name,
1036 };
1037
1038 let _ = this.update(&mut cx, |_, cx| {
1039 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1040 });
1041 }
1042 })
1043 .detach();
1044
1045 let disk_based_diagnostics_progress_token =
1046 adapter.disk_based_diagnostics_progress_token.clone();
1047
1048 language_server
1049 .on_notification::<lsp::notification::Progress, _>({
1050 let this = lsp_store.clone();
1051 move |params, cx| {
1052 if let Some(this) = this.upgrade() {
1053 this.update(cx, |this, cx| {
1054 this.on_lsp_progress(
1055 params,
1056 server_id,
1057 disk_based_diagnostics_progress_token.clone(),
1058 cx,
1059 );
1060 })
1061 .ok();
1062 }
1063 }
1064 })
1065 .detach();
1066
1067 language_server
1068 .on_notification::<lsp::notification::LogMessage, _>({
1069 let this = lsp_store.clone();
1070 move |params, cx| {
1071 if let Some(this) = this.upgrade() {
1072 this.update(cx, |_, cx| {
1073 cx.emit(LspStoreEvent::LanguageServerLog(
1074 server_id,
1075 LanguageServerLogType::Log(params.typ),
1076 params.message,
1077 ));
1078 })
1079 .ok();
1080 }
1081 }
1082 })
1083 .detach();
1084
1085 language_server
1086 .on_notification::<lsp::notification::LogTrace, _>({
1087 let this = lsp_store.clone();
1088 move |params, cx| {
1089 let mut cx = cx.clone();
1090 if let Some(this) = this.upgrade() {
1091 this.update(&mut cx, |_, cx| {
1092 cx.emit(LspStoreEvent::LanguageServerLog(
1093 server_id,
1094 LanguageServerLogType::Trace {
1095 verbose_info: params.verbose,
1096 },
1097 params.message,
1098 ));
1099 })
1100 .ok();
1101 }
1102 }
1103 })
1104 .detach();
1105
1106 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1107 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1108 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1109 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1110 }
1111
1112 fn shutdown_language_servers_on_quit(
1113 &mut self,
1114 _: &mut Context<LspStore>,
1115 ) -> impl Future<Output = ()> + use<> {
1116 let shutdown_futures = self
1117 .language_servers
1118 .drain()
1119 .map(|(_, server_state)| Self::shutdown_server(server_state))
1120 .collect::<Vec<_>>();
1121
1122 async move {
1123 join_all(shutdown_futures).await;
1124 }
1125 }
1126
1127 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1128 match server_state {
1129 LanguageServerState::Running { server, .. } => {
1130 if let Some(shutdown) = server.shutdown() {
1131 shutdown.await;
1132 }
1133 }
1134 LanguageServerState::Starting { startup, .. } => {
1135 if let Some(server) = startup.await
1136 && let Some(shutdown) = server.shutdown()
1137 {
1138 shutdown.await;
1139 }
1140 }
1141 }
1142 Ok(())
1143 }
1144
1145 fn language_servers_for_worktree(
1146 &self,
1147 worktree_id: WorktreeId,
1148 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1149 self.language_server_ids
1150 .iter()
1151 .filter_map(move |(seed, state)| {
1152 if seed.worktree_id != worktree_id {
1153 return None;
1154 }
1155
1156 if let Some(LanguageServerState::Running { server, .. }) =
1157 self.language_servers.get(&state.id)
1158 {
1159 Some(server)
1160 } else {
1161 None
1162 }
1163 })
1164 }
1165
1166 fn language_server_ids_for_project_path(
1167 &self,
1168 project_path: ProjectPath,
1169 language: &Language,
1170 cx: &mut App,
1171 ) -> Vec<LanguageServerId> {
1172 let Some(worktree) = self
1173 .worktree_store
1174 .read(cx)
1175 .worktree_for_id(project_path.worktree_id, cx)
1176 else {
1177 return Vec::new();
1178 };
1179 let delegate: Arc<dyn ManifestDelegate> =
1180 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1181
1182 self.lsp_tree
1183 .get(
1184 project_path,
1185 language.name(),
1186 language.manifest(),
1187 &delegate,
1188 cx,
1189 )
1190 .collect::<Vec<_>>()
1191 }
1192
1193 fn language_server_ids_for_buffer(
1194 &self,
1195 buffer: &Buffer,
1196 cx: &mut App,
1197 ) -> Vec<LanguageServerId> {
1198 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1199 let worktree_id = file.worktree_id(cx);
1200
1201 let path: Arc<RelPath> = file
1202 .path()
1203 .parent()
1204 .map(Arc::from)
1205 .unwrap_or_else(|| file.path().clone());
1206 let worktree_path = ProjectPath { worktree_id, path };
1207 self.language_server_ids_for_project_path(worktree_path, language, cx)
1208 } else {
1209 Vec::new()
1210 }
1211 }
1212
1213 fn language_servers_for_buffer<'a>(
1214 &'a self,
1215 buffer: &'a Buffer,
1216 cx: &'a mut App,
1217 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1218 self.language_server_ids_for_buffer(buffer, cx)
1219 .into_iter()
1220 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1221 LanguageServerState::Running {
1222 adapter, server, ..
1223 } => Some((adapter, server)),
1224 _ => None,
1225 })
1226 }
1227
1228 async fn execute_code_action_kind_locally(
1229 lsp_store: WeakEntity<LspStore>,
1230 mut buffers: Vec<Entity<Buffer>>,
1231 kind: CodeActionKind,
1232 push_to_history: bool,
1233 cx: &mut AsyncApp,
1234 ) -> anyhow::Result<ProjectTransaction> {
1235 // Do not allow multiple concurrent code actions requests for the
1236 // same buffer.
1237 lsp_store.update(cx, |this, cx| {
1238 let this = this.as_local_mut().unwrap();
1239 buffers.retain(|buffer| {
1240 this.buffers_being_formatted
1241 .insert(buffer.read(cx).remote_id())
1242 });
1243 })?;
1244 let _cleanup = defer({
1245 let this = lsp_store.clone();
1246 let mut cx = cx.clone();
1247 let buffers = &buffers;
1248 move || {
1249 this.update(&mut cx, |this, cx| {
1250 let this = this.as_local_mut().unwrap();
1251 for buffer in buffers {
1252 this.buffers_being_formatted
1253 .remove(&buffer.read(cx).remote_id());
1254 }
1255 })
1256 .ok();
1257 }
1258 });
1259 let mut project_transaction = ProjectTransaction::default();
1260
1261 for buffer in &buffers {
1262 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1263 buffer.update(cx, |buffer, cx| {
1264 lsp_store
1265 .as_local()
1266 .unwrap()
1267 .language_servers_for_buffer(buffer, cx)
1268 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1269 .collect::<Vec<_>>()
1270 })
1271 })?;
1272 for (_, language_server) in adapters_and_servers.iter() {
1273 let actions = Self::get_server_code_actions_from_action_kinds(
1274 &lsp_store,
1275 language_server.server_id(),
1276 vec![kind.clone()],
1277 buffer,
1278 cx,
1279 )
1280 .await?;
1281 Self::execute_code_actions_on_server(
1282 &lsp_store,
1283 language_server,
1284 actions,
1285 push_to_history,
1286 &mut project_transaction,
1287 cx,
1288 )
1289 .await?;
1290 }
1291 }
1292 Ok(project_transaction)
1293 }
1294
1295 async fn format_locally(
1296 lsp_store: WeakEntity<LspStore>,
1297 mut buffers: Vec<FormattableBuffer>,
1298 push_to_history: bool,
1299 trigger: FormatTrigger,
1300 logger: zlog::Logger,
1301 cx: &mut AsyncApp,
1302 ) -> anyhow::Result<ProjectTransaction> {
1303 // Do not allow multiple concurrent formatting requests for the
1304 // same buffer.
1305 lsp_store.update(cx, |this, cx| {
1306 let this = this.as_local_mut().unwrap();
1307 buffers.retain(|buffer| {
1308 this.buffers_being_formatted
1309 .insert(buffer.handle.read(cx).remote_id())
1310 });
1311 })?;
1312
1313 let _cleanup = defer({
1314 let this = lsp_store.clone();
1315 let mut cx = cx.clone();
1316 let buffers = &buffers;
1317 move || {
1318 this.update(&mut cx, |this, cx| {
1319 let this = this.as_local_mut().unwrap();
1320 for buffer in buffers {
1321 this.buffers_being_formatted
1322 .remove(&buffer.handle.read(cx).remote_id());
1323 }
1324 })
1325 .ok();
1326 }
1327 });
1328
1329 let mut project_transaction = ProjectTransaction::default();
1330
1331 for buffer in &buffers {
1332 zlog::debug!(
1333 logger =>
1334 "formatting buffer '{:?}'",
1335 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1336 );
1337 // Create an empty transaction to hold all of the formatting edits.
1338 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1339 // ensure no transactions created while formatting are
1340 // grouped with the previous transaction in the history
1341 // based on the transaction group interval
1342 buffer.finalize_last_transaction();
1343 buffer
1344 .start_transaction()
1345 .context("transaction already open")?;
1346 buffer.end_transaction(cx);
1347 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1348 buffer.finalize_last_transaction();
1349 anyhow::Ok(transaction_id)
1350 })??;
1351
1352 let result = Self::format_buffer_locally(
1353 lsp_store.clone(),
1354 buffer,
1355 formatting_transaction_id,
1356 trigger,
1357 logger,
1358 cx,
1359 )
1360 .await;
1361
1362 buffer.handle.update(cx, |buffer, cx| {
1363 let Some(formatting_transaction) =
1364 buffer.get_transaction(formatting_transaction_id).cloned()
1365 else {
1366 zlog::warn!(logger => "no formatting transaction");
1367 return;
1368 };
1369 if formatting_transaction.edit_ids.is_empty() {
1370 zlog::debug!(logger => "no changes made while formatting");
1371 buffer.forget_transaction(formatting_transaction_id);
1372 return;
1373 }
1374 if !push_to_history {
1375 zlog::trace!(logger => "forgetting format transaction");
1376 buffer.forget_transaction(formatting_transaction.id);
1377 }
1378 project_transaction
1379 .0
1380 .insert(cx.entity(), formatting_transaction);
1381 })?;
1382
1383 result?;
1384 }
1385
1386 Ok(project_transaction)
1387 }
1388
1389 async fn format_buffer_locally(
1390 lsp_store: WeakEntity<LspStore>,
1391 buffer: &FormattableBuffer,
1392 formatting_transaction_id: clock::Lamport,
1393 trigger: FormatTrigger,
1394 logger: zlog::Logger,
1395 cx: &mut AsyncApp,
1396 ) -> Result<()> {
1397 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1398 buffer.handle.update(cx, |buffer, cx| {
1399 let adapters_and_servers = lsp_store
1400 .as_local()
1401 .unwrap()
1402 .language_servers_for_buffer(buffer, cx)
1403 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1404 .collect::<Vec<_>>();
1405 let settings =
1406 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1407 .into_owned();
1408 (adapters_and_servers, settings)
1409 })
1410 })?;
1411
1412 /// Apply edits to the buffer that will become part of the formatting transaction.
1413 /// Fails if the buffer has been edited since the start of that transaction.
1414 fn extend_formatting_transaction(
1415 buffer: &FormattableBuffer,
1416 formatting_transaction_id: text::TransactionId,
1417 cx: &mut AsyncApp,
1418 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1419 ) -> anyhow::Result<()> {
1420 buffer.handle.update(cx, |buffer, cx| {
1421 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1422 if last_transaction_id != Some(formatting_transaction_id) {
1423 anyhow::bail!("Buffer edited while formatting. Aborting")
1424 }
1425 buffer.start_transaction();
1426 operation(buffer, cx);
1427 if let Some(transaction_id) = buffer.end_transaction(cx) {
1428 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1429 }
1430 Ok(())
1431 })?
1432 }
1433
1434 // handle whitespace formatting
1435 if settings.remove_trailing_whitespace_on_save {
1436 zlog::trace!(logger => "removing trailing whitespace");
1437 let diff = buffer
1438 .handle
1439 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1440 .await;
1441 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1442 buffer.apply_diff(diff, cx);
1443 })?;
1444 }
1445
1446 if settings.ensure_final_newline_on_save {
1447 zlog::trace!(logger => "ensuring final newline");
1448 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1449 buffer.ensure_final_newline(cx);
1450 })?;
1451 }
1452
1453 // Formatter for `code_actions_on_format` that runs before
1454 // the rest of the formatters
1455 let mut code_actions_on_format_formatters = None;
1456 let should_run_code_actions_on_format = !matches!(
1457 (trigger, &settings.format_on_save),
1458 (FormatTrigger::Save, &FormatOnSave::Off)
1459 );
1460 if should_run_code_actions_on_format {
1461 let have_code_actions_to_run_on_format = settings
1462 .code_actions_on_format
1463 .values()
1464 .any(|enabled| *enabled);
1465 if have_code_actions_to_run_on_format {
1466 zlog::trace!(logger => "going to run code actions on format");
1467 code_actions_on_format_formatters = Some(
1468 settings
1469 .code_actions_on_format
1470 .iter()
1471 .filter_map(|(action, enabled)| enabled.then_some(action))
1472 .cloned()
1473 .map(Formatter::CodeAction)
1474 .collect::<Vec<_>>(),
1475 );
1476 }
1477 }
1478
1479 let formatters = match (trigger, &settings.format_on_save) {
1480 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1481 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1482 settings.formatter.as_ref()
1483 }
1484 };
1485
1486 let formatters = code_actions_on_format_formatters
1487 .iter()
1488 .flatten()
1489 .chain(formatters);
1490
1491 for formatter in formatters {
1492 let formatter = if formatter == &Formatter::Auto {
1493 if settings.prettier.allowed {
1494 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1495 &Formatter::Prettier
1496 } else {
1497 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1498 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1499 }
1500 } else {
1501 formatter
1502 };
1503 match formatter {
1504 Formatter::Auto => unreachable!("Auto resolved above"),
1505 Formatter::Prettier => {
1506 let logger = zlog::scoped!(logger => "prettier");
1507 zlog::trace!(logger => "formatting");
1508 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1509
1510 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1511 lsp_store.prettier_store().unwrap().downgrade()
1512 })?;
1513 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1514 .await
1515 .transpose()?;
1516 let Some(diff) = diff else {
1517 zlog::trace!(logger => "No changes");
1518 continue;
1519 };
1520
1521 extend_formatting_transaction(
1522 buffer,
1523 formatting_transaction_id,
1524 cx,
1525 |buffer, cx| {
1526 buffer.apply_diff(diff, cx);
1527 },
1528 )?;
1529 }
1530 Formatter::External { command, arguments } => {
1531 let logger = zlog::scoped!(logger => "command");
1532 zlog::trace!(logger => "formatting");
1533 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1534
1535 let diff = Self::format_via_external_command(
1536 buffer,
1537 command.as_ref(),
1538 arguments.as_deref(),
1539 cx,
1540 )
1541 .await
1542 .with_context(|| {
1543 format!("Failed to format buffer via external command: {}", command)
1544 })?;
1545 let Some(diff) = diff else {
1546 zlog::trace!(logger => "No changes");
1547 continue;
1548 };
1549
1550 extend_formatting_transaction(
1551 buffer,
1552 formatting_transaction_id,
1553 cx,
1554 |buffer, cx| {
1555 buffer.apply_diff(diff, cx);
1556 },
1557 )?;
1558 }
1559 Formatter::LanguageServer(specifier) => {
1560 let logger = zlog::scoped!(logger => "language-server");
1561 zlog::trace!(logger => "formatting");
1562 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1563
1564 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1565 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1566 continue;
1567 };
1568
1569 let language_server = match specifier {
1570 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1571 adapters_and_servers.iter().find_map(|(adapter, server)| {
1572 if adapter.name.0.as_ref() == name {
1573 Some(server.clone())
1574 } else {
1575 None
1576 }
1577 })
1578 }
1579 settings::LanguageServerFormatterSpecifier::Current => {
1580 adapters_and_servers.first().map(|e| e.1.clone())
1581 }
1582 };
1583
1584 let Some(language_server) = language_server else {
1585 log::debug!(
1586 "No language server found to format buffer '{:?}'. Skipping",
1587 buffer_path_abs.as_path().to_string_lossy()
1588 );
1589 continue;
1590 };
1591
1592 zlog::trace!(
1593 logger =>
1594 "Formatting buffer '{:?}' using language server '{:?}'",
1595 buffer_path_abs.as_path().to_string_lossy(),
1596 language_server.name()
1597 );
1598
1599 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1600 zlog::trace!(logger => "formatting ranges");
1601 Self::format_ranges_via_lsp(
1602 &lsp_store,
1603 &buffer.handle,
1604 ranges,
1605 buffer_path_abs,
1606 &language_server,
1607 &settings,
1608 cx,
1609 )
1610 .await
1611 .context("Failed to format ranges via language server")?
1612 } else {
1613 zlog::trace!(logger => "formatting full");
1614 Self::format_via_lsp(
1615 &lsp_store,
1616 &buffer.handle,
1617 buffer_path_abs,
1618 &language_server,
1619 &settings,
1620 cx,
1621 )
1622 .await
1623 .context("failed to format via language server")?
1624 };
1625
1626 if edits.is_empty() {
1627 zlog::trace!(logger => "No changes");
1628 continue;
1629 }
1630 extend_formatting_transaction(
1631 buffer,
1632 formatting_transaction_id,
1633 cx,
1634 |buffer, cx| {
1635 buffer.edit(edits, None, cx);
1636 },
1637 )?;
1638 }
1639 Formatter::CodeAction(code_action_name) => {
1640 let logger = zlog::scoped!(logger => "code-actions");
1641 zlog::trace!(logger => "formatting");
1642 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1643
1644 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1645 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1646 continue;
1647 };
1648
1649 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1650 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1651
1652 let mut actions_and_servers = Vec::new();
1653
1654 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1655 let actions_result = Self::get_server_code_actions_from_action_kinds(
1656 &lsp_store,
1657 language_server.server_id(),
1658 vec![code_action_kind.clone()],
1659 &buffer.handle,
1660 cx,
1661 )
1662 .await
1663 .with_context(|| {
1664 format!(
1665 "Failed to resolve code action {:?} with language server {}",
1666 code_action_kind,
1667 language_server.name()
1668 )
1669 });
1670 let Ok(actions) = actions_result else {
1671 // note: it may be better to set result to the error and break formatters here
1672 // but for now we try to execute the actions that we can resolve and skip the rest
1673 zlog::error!(
1674 logger =>
1675 "Failed to resolve code action {:?} with language server {}",
1676 code_action_kind,
1677 language_server.name()
1678 );
1679 continue;
1680 };
1681 for action in actions {
1682 actions_and_servers.push((action, index));
1683 }
1684 }
1685
1686 if actions_and_servers.is_empty() {
1687 zlog::warn!(logger => "No code actions were resolved, continuing");
1688 continue;
1689 }
1690
1691 'actions: for (mut action, server_index) in actions_and_servers {
1692 let server = &adapters_and_servers[server_index].1;
1693
1694 let describe_code_action = |action: &CodeAction| {
1695 format!(
1696 "code action '{}' with title \"{}\" on server {}",
1697 action
1698 .lsp_action
1699 .action_kind()
1700 .unwrap_or("unknown".into())
1701 .as_str(),
1702 action.lsp_action.title(),
1703 server.name(),
1704 )
1705 };
1706
1707 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1708
1709 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1710 zlog::error!(
1711 logger =>
1712 "Failed to resolve {}. Error: {}",
1713 describe_code_action(&action),
1714 err
1715 );
1716 continue;
1717 }
1718
1719 if let Some(edit) = action.lsp_action.edit().cloned() {
1720 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1721 // but filters out and logs warnings for code actions that require unreasonably
1722 // difficult handling on our part, such as:
1723 // - applying edits that call commands
1724 // which can result in arbitrary workspace edits being sent from the server that
1725 // have no way of being tied back to the command that initiated them (i.e. we
1726 // can't know which edits are part of the format request, or if the server is done sending
1727 // actions in response to the command)
1728 // - actions that create/delete/modify/rename files other than the one we are formatting
1729 // as we then would need to handle such changes correctly in the local history as well
1730 // as the remote history through the ProjectTransaction
1731 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1732 // Supporting these actions is not impossible, but not supported as of yet.
1733 if edit.changes.is_none() && edit.document_changes.is_none() {
1734 zlog::trace!(
1735 logger =>
1736 "No changes for code action. Skipping {}",
1737 describe_code_action(&action),
1738 );
1739 continue;
1740 }
1741
1742 let mut operations = Vec::new();
1743 if let Some(document_changes) = edit.document_changes {
1744 match document_changes {
1745 lsp::DocumentChanges::Edits(edits) => operations.extend(
1746 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1747 ),
1748 lsp::DocumentChanges::Operations(ops) => operations = ops,
1749 }
1750 } else if let Some(changes) = edit.changes {
1751 operations.extend(changes.into_iter().map(|(uri, edits)| {
1752 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1753 text_document:
1754 lsp::OptionalVersionedTextDocumentIdentifier {
1755 uri,
1756 version: None,
1757 },
1758 edits: edits.into_iter().map(Edit::Plain).collect(),
1759 })
1760 }));
1761 }
1762
1763 let mut edits = Vec::with_capacity(operations.len());
1764
1765 if operations.is_empty() {
1766 zlog::trace!(
1767 logger =>
1768 "No changes for code action. Skipping {}",
1769 describe_code_action(&action),
1770 );
1771 continue;
1772 }
1773 for operation in operations {
1774 let op = match operation {
1775 lsp::DocumentChangeOperation::Edit(op) => op,
1776 lsp::DocumentChangeOperation::Op(_) => {
1777 zlog::warn!(
1778 logger =>
1779 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1780 describe_code_action(&action),
1781 );
1782 continue 'actions;
1783 }
1784 };
1785 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1786 zlog::warn!(
1787 logger =>
1788 "Failed to convert URI '{:?}' to file path. Skipping {}",
1789 &op.text_document.uri,
1790 describe_code_action(&action),
1791 );
1792 continue 'actions;
1793 };
1794 if &file_path != buffer_path_abs {
1795 zlog::warn!(
1796 logger =>
1797 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1798 file_path,
1799 buffer_path_abs,
1800 describe_code_action(&action),
1801 );
1802 continue 'actions;
1803 }
1804
1805 let mut lsp_edits = Vec::new();
1806 for edit in op.edits {
1807 match edit {
1808 Edit::Plain(edit) => {
1809 if !lsp_edits.contains(&edit) {
1810 lsp_edits.push(edit);
1811 }
1812 }
1813 Edit::Annotated(edit) => {
1814 if !lsp_edits.contains(&edit.text_edit) {
1815 lsp_edits.push(edit.text_edit);
1816 }
1817 }
1818 Edit::Snippet(_) => {
1819 zlog::warn!(
1820 logger =>
1821 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1822 describe_code_action(&action),
1823 );
1824 continue 'actions;
1825 }
1826 }
1827 }
1828 let edits_result = lsp_store
1829 .update(cx, |lsp_store, cx| {
1830 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1831 &buffer.handle,
1832 lsp_edits,
1833 server.server_id(),
1834 op.text_document.version,
1835 cx,
1836 )
1837 })?
1838 .await;
1839 let Ok(resolved_edits) = edits_result else {
1840 zlog::warn!(
1841 logger =>
1842 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1843 buffer_path_abs.as_path(),
1844 describe_code_action(&action),
1845 );
1846 continue 'actions;
1847 };
1848 edits.extend(resolved_edits);
1849 }
1850
1851 if edits.is_empty() {
1852 zlog::warn!(logger => "No edits resolved from LSP");
1853 continue;
1854 }
1855
1856 extend_formatting_transaction(
1857 buffer,
1858 formatting_transaction_id,
1859 cx,
1860 |buffer, cx| {
1861 zlog::info!(
1862 "Applying edits {edits:?}. Content: {:?}",
1863 buffer.text()
1864 );
1865 buffer.edit(edits, None, cx);
1866 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1867 },
1868 )?;
1869 }
1870
1871 if let Some(command) = action.lsp_action.command() {
1872 zlog::warn!(
1873 logger =>
1874 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1875 &command.command,
1876 );
1877
1878 // bail early if command is invalid
1879 let server_capabilities = server.capabilities();
1880 let available_commands = server_capabilities
1881 .execute_command_provider
1882 .as_ref()
1883 .map(|options| options.commands.as_slice())
1884 .unwrap_or_default();
1885 if !available_commands.contains(&command.command) {
1886 zlog::warn!(
1887 logger =>
1888 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1889 command.command,
1890 server.name(),
1891 );
1892 continue;
1893 }
1894
1895 // noop so we just ensure buffer hasn't been edited since resolving code actions
1896 extend_formatting_transaction(
1897 buffer,
1898 formatting_transaction_id,
1899 cx,
1900 |_, _| {},
1901 )?;
1902 zlog::info!(logger => "Executing command {}", &command.command);
1903
1904 lsp_store.update(cx, |this, _| {
1905 this.as_local_mut()
1906 .unwrap()
1907 .last_workspace_edits_by_language_server
1908 .remove(&server.server_id());
1909 })?;
1910
1911 let execute_command_result = server
1912 .request::<lsp::request::ExecuteCommand>(
1913 lsp::ExecuteCommandParams {
1914 command: command.command.clone(),
1915 arguments: command.arguments.clone().unwrap_or_default(),
1916 ..Default::default()
1917 },
1918 )
1919 .await
1920 .into_response();
1921
1922 if execute_command_result.is_err() {
1923 zlog::error!(
1924 logger =>
1925 "Failed to execute command '{}' as part of {}",
1926 &command.command,
1927 describe_code_action(&action),
1928 );
1929 continue 'actions;
1930 }
1931
1932 let mut project_transaction_command =
1933 lsp_store.update(cx, |this, _| {
1934 this.as_local_mut()
1935 .unwrap()
1936 .last_workspace_edits_by_language_server
1937 .remove(&server.server_id())
1938 .unwrap_or_default()
1939 })?;
1940
1941 if let Some(transaction) =
1942 project_transaction_command.0.remove(&buffer.handle)
1943 {
1944 zlog::trace!(
1945 logger =>
1946 "Successfully captured {} edits that resulted from command {}",
1947 transaction.edit_ids.len(),
1948 &command.command,
1949 );
1950 let transaction_id_project_transaction = transaction.id;
1951 buffer.handle.update(cx, |buffer, _| {
1952 // it may have been removed from history if push_to_history was
1953 // false in deserialize_workspace_edit. If so push it so we
1954 // can merge it with the format transaction
1955 // and pop the combined transaction off the history stack
1956 // later if push_to_history is false
1957 if buffer.get_transaction(transaction.id).is_none() {
1958 buffer.push_transaction(transaction, Instant::now());
1959 }
1960 buffer.merge_transactions(
1961 transaction_id_project_transaction,
1962 formatting_transaction_id,
1963 );
1964 })?;
1965 }
1966
1967 if !project_transaction_command.0.is_empty() {
1968 let mut extra_buffers = String::new();
1969 for buffer in project_transaction_command.0.keys() {
1970 buffer
1971 .read_with(cx, |b, cx| {
1972 if let Some(path) = b.project_path(cx) {
1973 if !extra_buffers.is_empty() {
1974 extra_buffers.push_str(", ");
1975 }
1976 extra_buffers.push_str(path.path.as_unix_str());
1977 }
1978 })
1979 .ok();
1980 }
1981 zlog::warn!(
1982 logger =>
1983 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1984 &command.command,
1985 extra_buffers,
1986 );
1987 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1988 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1989 // add it so it's included, and merge it into the format transaction when its created later
1990 }
1991 }
1992 }
1993 }
1994 }
1995 }
1996
1997 Ok(())
1998 }
1999
2000 pub async fn format_ranges_via_lsp(
2001 this: &WeakEntity<LspStore>,
2002 buffer_handle: &Entity<Buffer>,
2003 ranges: &[Range<Anchor>],
2004 abs_path: &Path,
2005 language_server: &Arc<LanguageServer>,
2006 settings: &LanguageSettings,
2007 cx: &mut AsyncApp,
2008 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2009 let capabilities = &language_server.capabilities();
2010 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2011 if range_formatting_provider == Some(&OneOf::Left(false)) {
2012 anyhow::bail!(
2013 "{} language server does not support range formatting",
2014 language_server.name()
2015 );
2016 }
2017
2018 let uri = file_path_to_lsp_url(abs_path)?;
2019 let text_document = lsp::TextDocumentIdentifier::new(uri);
2020
2021 let lsp_edits = {
2022 let mut lsp_ranges = Vec::new();
2023 this.update(cx, |_this, cx| {
2024 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2025 // not have been sent to the language server. This seems like a fairly systemic
2026 // issue, though, the resolution probably is not specific to formatting.
2027 //
2028 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2029 // LSP.
2030 let snapshot = buffer_handle.read(cx).snapshot();
2031 for range in ranges {
2032 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2033 }
2034 anyhow::Ok(())
2035 })??;
2036
2037 let mut edits = None;
2038 for range in lsp_ranges {
2039 if let Some(mut edit) = language_server
2040 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2041 text_document: text_document.clone(),
2042 range,
2043 options: lsp_command::lsp_formatting_options(settings),
2044 work_done_progress_params: Default::default(),
2045 })
2046 .await
2047 .into_response()?
2048 {
2049 edits.get_or_insert_with(Vec::new).append(&mut edit);
2050 }
2051 }
2052 edits
2053 };
2054
2055 if let Some(lsp_edits) = lsp_edits {
2056 this.update(cx, |this, cx| {
2057 this.as_local_mut().unwrap().edits_from_lsp(
2058 buffer_handle,
2059 lsp_edits,
2060 language_server.server_id(),
2061 None,
2062 cx,
2063 )
2064 })?
2065 .await
2066 } else {
2067 Ok(Vec::with_capacity(0))
2068 }
2069 }
2070
2071 async fn format_via_lsp(
2072 this: &WeakEntity<LspStore>,
2073 buffer: &Entity<Buffer>,
2074 abs_path: &Path,
2075 language_server: &Arc<LanguageServer>,
2076 settings: &LanguageSettings,
2077 cx: &mut AsyncApp,
2078 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2079 let logger = zlog::scoped!("lsp_format");
2080 zlog::debug!(logger => "Formatting via LSP");
2081
2082 let uri = file_path_to_lsp_url(abs_path)?;
2083 let text_document = lsp::TextDocumentIdentifier::new(uri);
2084 let capabilities = &language_server.capabilities();
2085
2086 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2087 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2088
2089 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2090 let _timer = zlog::time!(logger => "format-full");
2091 language_server
2092 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2093 text_document,
2094 options: lsp_command::lsp_formatting_options(settings),
2095 work_done_progress_params: Default::default(),
2096 })
2097 .await
2098 .into_response()?
2099 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2100 let _timer = zlog::time!(logger => "format-range");
2101 let buffer_start = lsp::Position::new(0, 0);
2102 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2103 language_server
2104 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2105 text_document: text_document.clone(),
2106 range: lsp::Range::new(buffer_start, buffer_end),
2107 options: lsp_command::lsp_formatting_options(settings),
2108 work_done_progress_params: Default::default(),
2109 })
2110 .await
2111 .into_response()?
2112 } else {
2113 None
2114 };
2115
2116 if let Some(lsp_edits) = lsp_edits {
2117 this.update(cx, |this, cx| {
2118 this.as_local_mut().unwrap().edits_from_lsp(
2119 buffer,
2120 lsp_edits,
2121 language_server.server_id(),
2122 None,
2123 cx,
2124 )
2125 })?
2126 .await
2127 } else {
2128 Ok(Vec::with_capacity(0))
2129 }
2130 }
2131
2132 async fn format_via_external_command(
2133 buffer: &FormattableBuffer,
2134 command: &str,
2135 arguments: Option<&[String]>,
2136 cx: &mut AsyncApp,
2137 ) -> Result<Option<Diff>> {
2138 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2139 let file = File::from_dyn(buffer.file())?;
2140 let worktree = file.worktree.read(cx);
2141 let mut worktree_path = worktree.abs_path().to_path_buf();
2142 if worktree.root_entry()?.is_file() {
2143 worktree_path.pop();
2144 }
2145 Some(worktree_path)
2146 })?;
2147
2148 let mut child = util::command::new_smol_command(command);
2149
2150 if let Some(buffer_env) = buffer.env.as_ref() {
2151 child.envs(buffer_env);
2152 }
2153
2154 if let Some(working_dir_path) = working_dir_path {
2155 child.current_dir(working_dir_path);
2156 }
2157
2158 if let Some(arguments) = arguments {
2159 child.args(arguments.iter().map(|arg| {
2160 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2161 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2162 } else {
2163 arg.replace("{buffer_path}", "Untitled")
2164 }
2165 }));
2166 }
2167
2168 let mut child = child
2169 .stdin(smol::process::Stdio::piped())
2170 .stdout(smol::process::Stdio::piped())
2171 .stderr(smol::process::Stdio::piped())
2172 .spawn()?;
2173
2174 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2175 let text = buffer
2176 .handle
2177 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2178 for chunk in text.chunks() {
2179 stdin.write_all(chunk.as_bytes()).await?;
2180 }
2181 stdin.flush().await?;
2182
2183 let output = child.output().await?;
2184 anyhow::ensure!(
2185 output.status.success(),
2186 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2187 output.status.code(),
2188 String::from_utf8_lossy(&output.stdout),
2189 String::from_utf8_lossy(&output.stderr),
2190 );
2191
2192 let stdout = String::from_utf8(output.stdout)?;
2193 Ok(Some(
2194 buffer
2195 .handle
2196 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2197 .await,
2198 ))
2199 }
2200
2201 async fn try_resolve_code_action(
2202 lang_server: &LanguageServer,
2203 action: &mut CodeAction,
2204 ) -> anyhow::Result<()> {
2205 match &mut action.lsp_action {
2206 LspAction::Action(lsp_action) => {
2207 if !action.resolved
2208 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2209 && lsp_action.data.is_some()
2210 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2211 {
2212 *lsp_action = Box::new(
2213 lang_server
2214 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2215 .await
2216 .into_response()?,
2217 );
2218 }
2219 }
2220 LspAction::CodeLens(lens) => {
2221 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2222 *lens = lang_server
2223 .request::<lsp::request::CodeLensResolve>(lens.clone())
2224 .await
2225 .into_response()?;
2226 }
2227 }
2228 LspAction::Command(_) => {}
2229 }
2230
2231 action.resolved = true;
2232 anyhow::Ok(())
2233 }
2234
2235 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2236 let buffer = buffer_handle.read(cx);
2237
2238 let file = buffer.file().cloned();
2239
2240 let Some(file) = File::from_dyn(file.as_ref()) else {
2241 return;
2242 };
2243 if !file.is_local() {
2244 return;
2245 }
2246 let path = ProjectPath::from_file(file, cx);
2247 let worktree_id = file.worktree_id(cx);
2248 let language = buffer.language().cloned();
2249
2250 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2251 for (server_id, diagnostics) in
2252 diagnostics.get(file.path()).cloned().unwrap_or_default()
2253 {
2254 self.update_buffer_diagnostics(
2255 buffer_handle,
2256 server_id,
2257 None,
2258 None,
2259 diagnostics,
2260 Vec::new(),
2261 cx,
2262 )
2263 .log_err();
2264 }
2265 }
2266 let Some(language) = language else {
2267 return;
2268 };
2269 let Some(snapshot) = self
2270 .worktree_store
2271 .read(cx)
2272 .worktree_for_id(worktree_id, cx)
2273 .map(|worktree| worktree.read(cx).snapshot())
2274 else {
2275 return;
2276 };
2277 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2278
2279 for server_id in
2280 self.lsp_tree
2281 .get(path, language.name(), language.manifest(), &delegate, cx)
2282 {
2283 let server = self
2284 .language_servers
2285 .get(&server_id)
2286 .and_then(|server_state| {
2287 if let LanguageServerState::Running { server, .. } = server_state {
2288 Some(server.clone())
2289 } else {
2290 None
2291 }
2292 });
2293 let server = match server {
2294 Some(server) => server,
2295 None => continue,
2296 };
2297
2298 buffer_handle.update(cx, |buffer, cx| {
2299 buffer.set_completion_triggers(
2300 server.server_id(),
2301 server
2302 .capabilities()
2303 .completion_provider
2304 .as_ref()
2305 .and_then(|provider| {
2306 provider
2307 .trigger_characters
2308 .as_ref()
2309 .map(|characters| characters.iter().cloned().collect())
2310 })
2311 .unwrap_or_default(),
2312 cx,
2313 );
2314 });
2315 }
2316 }
2317
2318 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2319 buffer.update(cx, |buffer, cx| {
2320 let Some(language) = buffer.language() else {
2321 return;
2322 };
2323 let path = ProjectPath {
2324 worktree_id: old_file.worktree_id(cx),
2325 path: old_file.path.clone(),
2326 };
2327 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2328 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2329 buffer.set_completion_triggers(server_id, Default::default(), cx);
2330 }
2331 });
2332 }
2333
2334 fn update_buffer_diagnostics(
2335 &mut self,
2336 buffer: &Entity<Buffer>,
2337 server_id: LanguageServerId,
2338 result_id: Option<String>,
2339 version: Option<i32>,
2340 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2341 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2342 cx: &mut Context<LspStore>,
2343 ) -> Result<()> {
2344 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2345 Ordering::Equal
2346 .then_with(|| b.is_primary.cmp(&a.is_primary))
2347 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2348 .then_with(|| a.severity.cmp(&b.severity))
2349 .then_with(|| a.message.cmp(&b.message))
2350 }
2351
2352 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2353 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2354 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2355
2356 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2357 Ordering::Equal
2358 .then_with(|| a.range.start.cmp(&b.range.start))
2359 .then_with(|| b.range.end.cmp(&a.range.end))
2360 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2361 });
2362
2363 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2364
2365 let edits_since_save = std::cell::LazyCell::new(|| {
2366 let saved_version = buffer.read(cx).saved_version();
2367 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2368 });
2369
2370 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2371
2372 for (new_diagnostic, entry) in diagnostics {
2373 let start;
2374 let end;
2375 if new_diagnostic && entry.diagnostic.is_disk_based {
2376 // Some diagnostics are based on files on disk instead of buffers'
2377 // current contents. Adjust these diagnostics' ranges to reflect
2378 // any unsaved edits.
2379 // Do not alter the reused ones though, as their coordinates were stored as anchors
2380 // and were properly adjusted on reuse.
2381 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2382 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2383 } else {
2384 start = entry.range.start;
2385 end = entry.range.end;
2386 }
2387
2388 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2389 ..snapshot.clip_point_utf16(end, Bias::Right);
2390
2391 // Expand empty ranges by one codepoint
2392 if range.start == range.end {
2393 // This will be go to the next boundary when being clipped
2394 range.end.column += 1;
2395 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2396 if range.start == range.end && range.end.column > 0 {
2397 range.start.column -= 1;
2398 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2399 }
2400 }
2401
2402 sanitized_diagnostics.push(DiagnosticEntry {
2403 range,
2404 diagnostic: entry.diagnostic,
2405 });
2406 }
2407 drop(edits_since_save);
2408
2409 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2410 buffer.update(cx, |buffer, cx| {
2411 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2412 self.buffer_pull_diagnostics_result_ids
2413 .entry(server_id)
2414 .or_default()
2415 .insert(abs_path, result_id);
2416 }
2417
2418 buffer.update_diagnostics(server_id, set, cx)
2419 });
2420
2421 Ok(())
2422 }
2423
2424 fn register_language_server_for_invisible_worktree(
2425 &mut self,
2426 worktree: &Entity<Worktree>,
2427 language_server_id: LanguageServerId,
2428 cx: &mut App,
2429 ) {
2430 let worktree = worktree.read(cx);
2431 let worktree_id = worktree.id();
2432 debug_assert!(!worktree.is_visible());
2433 let Some(mut origin_seed) = self
2434 .language_server_ids
2435 .iter()
2436 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2437 else {
2438 return;
2439 };
2440 origin_seed.worktree_id = worktree_id;
2441 self.language_server_ids
2442 .entry(origin_seed)
2443 .or_insert_with(|| UnifiedLanguageServer {
2444 id: language_server_id,
2445 project_roots: Default::default(),
2446 });
2447 }
2448
2449 fn register_buffer_with_language_servers(
2450 &mut self,
2451 buffer_handle: &Entity<Buffer>,
2452 only_register_servers: HashSet<LanguageServerSelector>,
2453 cx: &mut Context<LspStore>,
2454 ) {
2455 let buffer = buffer_handle.read(cx);
2456 let buffer_id = buffer.remote_id();
2457
2458 let Some(file) = File::from_dyn(buffer.file()) else {
2459 return;
2460 };
2461 if !file.is_local() {
2462 return;
2463 }
2464
2465 let abs_path = file.abs_path(cx);
2466 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2467 return;
2468 };
2469 let initial_snapshot = buffer.text_snapshot();
2470 let worktree_id = file.worktree_id(cx);
2471
2472 let Some(language) = buffer.language().cloned() else {
2473 return;
2474 };
2475 let path: Arc<RelPath> = file
2476 .path()
2477 .parent()
2478 .map(Arc::from)
2479 .unwrap_or_else(|| file.path().clone());
2480 let Some(worktree) = self
2481 .worktree_store
2482 .read(cx)
2483 .worktree_for_id(worktree_id, cx)
2484 else {
2485 return;
2486 };
2487 let language_name = language.name();
2488 let (reused, delegate, servers) = self
2489 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2490 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2491 .unwrap_or_else(|| {
2492 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2493 let delegate: Arc<dyn ManifestDelegate> =
2494 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2495
2496 let servers = self
2497 .lsp_tree
2498 .walk(
2499 ProjectPath { worktree_id, path },
2500 language.name(),
2501 language.manifest(),
2502 &delegate,
2503 cx,
2504 )
2505 .collect::<Vec<_>>();
2506 (false, lsp_delegate, servers)
2507 });
2508 let servers_and_adapters = servers
2509 .into_iter()
2510 .filter_map(|server_node| {
2511 if reused && server_node.server_id().is_none() {
2512 return None;
2513 }
2514 if !only_register_servers.is_empty() {
2515 if let Some(server_id) = server_node.server_id()
2516 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2517 {
2518 return None;
2519 }
2520 if let Some(name) = server_node.name()
2521 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2522 {
2523 return None;
2524 }
2525 }
2526
2527 let server_id = server_node.server_id_or_init(|disposition| {
2528 let path = &disposition.path;
2529
2530 {
2531 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2532
2533 let server_id = self.get_or_insert_language_server(
2534 &worktree,
2535 delegate.clone(),
2536 disposition,
2537 &language_name,
2538 cx,
2539 );
2540
2541 if let Some(state) = self.language_servers.get(&server_id)
2542 && let Ok(uri) = uri
2543 {
2544 state.add_workspace_folder(uri);
2545 };
2546 server_id
2547 }
2548 })?;
2549 let server_state = self.language_servers.get(&server_id)?;
2550 if let LanguageServerState::Running {
2551 server, adapter, ..
2552 } = server_state
2553 {
2554 Some((server.clone(), adapter.clone()))
2555 } else {
2556 None
2557 }
2558 })
2559 .collect::<Vec<_>>();
2560 for (server, adapter) in servers_and_adapters {
2561 buffer_handle.update(cx, |buffer, cx| {
2562 buffer.set_completion_triggers(
2563 server.server_id(),
2564 server
2565 .capabilities()
2566 .completion_provider
2567 .as_ref()
2568 .and_then(|provider| {
2569 provider
2570 .trigger_characters
2571 .as_ref()
2572 .map(|characters| characters.iter().cloned().collect())
2573 })
2574 .unwrap_or_default(),
2575 cx,
2576 );
2577 });
2578
2579 let snapshot = LspBufferSnapshot {
2580 version: 0,
2581 snapshot: initial_snapshot.clone(),
2582 };
2583
2584 let mut registered = false;
2585 self.buffer_snapshots
2586 .entry(buffer_id)
2587 .or_default()
2588 .entry(server.server_id())
2589 .or_insert_with(|| {
2590 registered = true;
2591 server.register_buffer(
2592 uri.clone(),
2593 adapter.language_id(&language.name()),
2594 0,
2595 initial_snapshot.text(),
2596 );
2597
2598 vec![snapshot]
2599 });
2600
2601 self.buffers_opened_in_servers
2602 .entry(buffer_id)
2603 .or_default()
2604 .insert(server.server_id());
2605 if registered {
2606 cx.emit(LspStoreEvent::LanguageServerUpdate {
2607 language_server_id: server.server_id(),
2608 name: None,
2609 message: proto::update_language_server::Variant::RegisteredForBuffer(
2610 proto::RegisteredForBuffer {
2611 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2612 buffer_id: buffer_id.to_proto(),
2613 },
2614 ),
2615 });
2616 }
2617 }
2618 }
2619
2620 fn reuse_existing_language_server<'lang_name>(
2621 &self,
2622 server_tree: &LanguageServerTree,
2623 worktree: &Entity<Worktree>,
2624 language_name: &'lang_name LanguageName,
2625 cx: &mut App,
2626 ) -> Option<(
2627 Arc<LocalLspAdapterDelegate>,
2628 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2629 )> {
2630 if worktree.read(cx).is_visible() {
2631 return None;
2632 }
2633
2634 let worktree_store = self.worktree_store.read(cx);
2635 let servers = server_tree
2636 .instances
2637 .iter()
2638 .filter(|(worktree_id, _)| {
2639 worktree_store
2640 .worktree_for_id(**worktree_id, cx)
2641 .is_some_and(|worktree| worktree.read(cx).is_visible())
2642 })
2643 .flat_map(|(worktree_id, servers)| {
2644 servers
2645 .roots
2646 .iter()
2647 .flat_map(|(_, language_servers)| language_servers)
2648 .map(move |(_, (server_node, server_languages))| {
2649 (worktree_id, server_node, server_languages)
2650 })
2651 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2652 .map(|(worktree_id, server_node, _)| {
2653 (
2654 *worktree_id,
2655 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2656 )
2657 })
2658 })
2659 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2660 acc.entry(worktree_id)
2661 .or_insert_with(Vec::new)
2662 .push(server_node);
2663 acc
2664 })
2665 .into_values()
2666 .max_by_key(|servers| servers.len())?;
2667
2668 let worktree_id = worktree.read(cx).id();
2669 let apply = move |tree: &mut LanguageServerTree| {
2670 for server_node in &servers {
2671 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2672 }
2673 servers
2674 };
2675
2676 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2677 Some((delegate, apply))
2678 }
2679
2680 pub(crate) fn unregister_old_buffer_from_language_servers(
2681 &mut self,
2682 buffer: &Entity<Buffer>,
2683 old_file: &File,
2684 cx: &mut App,
2685 ) {
2686 let old_path = match old_file.as_local() {
2687 Some(local) => local.abs_path(cx),
2688 None => return,
2689 };
2690
2691 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2692 debug_panic!("{old_path:?} is not parseable as an URI");
2693 return;
2694 };
2695 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2696 }
2697
2698 pub(crate) fn unregister_buffer_from_language_servers(
2699 &mut self,
2700 buffer: &Entity<Buffer>,
2701 file_url: &lsp::Uri,
2702 cx: &mut App,
2703 ) {
2704 buffer.update(cx, |buffer, cx| {
2705 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2706
2707 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2708 if snapshots
2709 .as_mut()
2710 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2711 {
2712 language_server.unregister_buffer(file_url.clone());
2713 }
2714 }
2715 });
2716 }
2717
2718 fn buffer_snapshot_for_lsp_version(
2719 &mut self,
2720 buffer: &Entity<Buffer>,
2721 server_id: LanguageServerId,
2722 version: Option<i32>,
2723 cx: &App,
2724 ) -> Result<TextBufferSnapshot> {
2725 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2726
2727 if let Some(version) = version {
2728 let buffer_id = buffer.read(cx).remote_id();
2729 let snapshots = if let Some(snapshots) = self
2730 .buffer_snapshots
2731 .get_mut(&buffer_id)
2732 .and_then(|m| m.get_mut(&server_id))
2733 {
2734 snapshots
2735 } else if version == 0 {
2736 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2737 // We detect this case and treat it as if the version was `None`.
2738 return Ok(buffer.read(cx).text_snapshot());
2739 } else {
2740 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2741 };
2742
2743 let found_snapshot = snapshots
2744 .binary_search_by_key(&version, |e| e.version)
2745 .map(|ix| snapshots[ix].snapshot.clone())
2746 .map_err(|_| {
2747 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2748 })?;
2749
2750 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2751 Ok(found_snapshot)
2752 } else {
2753 Ok((buffer.read(cx)).text_snapshot())
2754 }
2755 }
2756
2757 async fn get_server_code_actions_from_action_kinds(
2758 lsp_store: &WeakEntity<LspStore>,
2759 language_server_id: LanguageServerId,
2760 code_action_kinds: Vec<lsp::CodeActionKind>,
2761 buffer: &Entity<Buffer>,
2762 cx: &mut AsyncApp,
2763 ) -> Result<Vec<CodeAction>> {
2764 let actions = lsp_store
2765 .update(cx, move |this, cx| {
2766 let request = GetCodeActions {
2767 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2768 kinds: Some(code_action_kinds),
2769 };
2770 let server = LanguageServerToQuery::Other(language_server_id);
2771 this.request_lsp(buffer.clone(), server, request, cx)
2772 })?
2773 .await?;
2774 Ok(actions)
2775 }
2776
2777 pub async fn execute_code_actions_on_server(
2778 lsp_store: &WeakEntity<LspStore>,
2779 language_server: &Arc<LanguageServer>,
2780
2781 actions: Vec<CodeAction>,
2782 push_to_history: bool,
2783 project_transaction: &mut ProjectTransaction,
2784 cx: &mut AsyncApp,
2785 ) -> anyhow::Result<()> {
2786 for mut action in actions {
2787 Self::try_resolve_code_action(language_server, &mut action)
2788 .await
2789 .context("resolving a formatting code action")?;
2790
2791 if let Some(edit) = action.lsp_action.edit() {
2792 if edit.changes.is_none() && edit.document_changes.is_none() {
2793 continue;
2794 }
2795
2796 let new = Self::deserialize_workspace_edit(
2797 lsp_store.upgrade().context("project dropped")?,
2798 edit.clone(),
2799 push_to_history,
2800 language_server.clone(),
2801 cx,
2802 )
2803 .await?;
2804 project_transaction.0.extend(new.0);
2805 }
2806
2807 if let Some(command) = action.lsp_action.command() {
2808 let server_capabilities = language_server.capabilities();
2809 let available_commands = server_capabilities
2810 .execute_command_provider
2811 .as_ref()
2812 .map(|options| options.commands.as_slice())
2813 .unwrap_or_default();
2814 if available_commands.contains(&command.command) {
2815 lsp_store.update(cx, |lsp_store, _| {
2816 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2817 mode.last_workspace_edits_by_language_server
2818 .remove(&language_server.server_id());
2819 }
2820 })?;
2821
2822 language_server
2823 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2824 command: command.command.clone(),
2825 arguments: command.arguments.clone().unwrap_or_default(),
2826 ..Default::default()
2827 })
2828 .await
2829 .into_response()
2830 .context("execute command")?;
2831
2832 lsp_store.update(cx, |this, _| {
2833 if let LspStoreMode::Local(mode) = &mut this.mode {
2834 project_transaction.0.extend(
2835 mode.last_workspace_edits_by_language_server
2836 .remove(&language_server.server_id())
2837 .unwrap_or_default()
2838 .0,
2839 )
2840 }
2841 })?;
2842 } else {
2843 log::warn!(
2844 "Cannot execute a command {} not listed in the language server capabilities",
2845 command.command
2846 )
2847 }
2848 }
2849 }
2850 Ok(())
2851 }
2852
2853 pub async fn deserialize_text_edits(
2854 this: Entity<LspStore>,
2855 buffer_to_edit: Entity<Buffer>,
2856 edits: Vec<lsp::TextEdit>,
2857 push_to_history: bool,
2858 _: Arc<CachedLspAdapter>,
2859 language_server: Arc<LanguageServer>,
2860 cx: &mut AsyncApp,
2861 ) -> Result<Option<Transaction>> {
2862 let edits = this
2863 .update(cx, |this, cx| {
2864 this.as_local_mut().unwrap().edits_from_lsp(
2865 &buffer_to_edit,
2866 edits,
2867 language_server.server_id(),
2868 None,
2869 cx,
2870 )
2871 })?
2872 .await?;
2873
2874 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2875 buffer.finalize_last_transaction();
2876 buffer.start_transaction();
2877 for (range, text) in edits {
2878 buffer.edit([(range, text)], None, cx);
2879 }
2880
2881 if buffer.end_transaction(cx).is_some() {
2882 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2883 if !push_to_history {
2884 buffer.forget_transaction(transaction.id);
2885 }
2886 Some(transaction)
2887 } else {
2888 None
2889 }
2890 })?;
2891
2892 Ok(transaction)
2893 }
2894
2895 #[allow(clippy::type_complexity)]
2896 pub(crate) fn edits_from_lsp(
2897 &mut self,
2898 buffer: &Entity<Buffer>,
2899 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2900 server_id: LanguageServerId,
2901 version: Option<i32>,
2902 cx: &mut Context<LspStore>,
2903 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2904 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2905 cx.background_spawn(async move {
2906 let snapshot = snapshot?;
2907 let mut lsp_edits = lsp_edits
2908 .into_iter()
2909 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2910 .collect::<Vec<_>>();
2911
2912 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2913
2914 let mut lsp_edits = lsp_edits.into_iter().peekable();
2915 let mut edits = Vec::new();
2916 while let Some((range, mut new_text)) = lsp_edits.next() {
2917 // Clip invalid ranges provided by the language server.
2918 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2919 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2920
2921 // Combine any LSP edits that are adjacent.
2922 //
2923 // Also, combine LSP edits that are separated from each other by only
2924 // a newline. This is important because for some code actions,
2925 // Rust-analyzer rewrites the entire buffer via a series of edits that
2926 // are separated by unchanged newline characters.
2927 //
2928 // In order for the diffing logic below to work properly, any edits that
2929 // cancel each other out must be combined into one.
2930 while let Some((next_range, next_text)) = lsp_edits.peek() {
2931 if next_range.start.0 > range.end {
2932 if next_range.start.0.row > range.end.row + 1
2933 || next_range.start.0.column > 0
2934 || snapshot.clip_point_utf16(
2935 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2936 Bias::Left,
2937 ) > range.end
2938 {
2939 break;
2940 }
2941 new_text.push('\n');
2942 }
2943 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2944 new_text.push_str(next_text);
2945 lsp_edits.next();
2946 }
2947
2948 // For multiline edits, perform a diff of the old and new text so that
2949 // we can identify the changes more precisely, preserving the locations
2950 // of any anchors positioned in the unchanged regions.
2951 if range.end.row > range.start.row {
2952 let offset = range.start.to_offset(&snapshot);
2953 let old_text = snapshot.text_for_range(range).collect::<String>();
2954 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2955 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2956 (
2957 snapshot.anchor_after(offset + range.start)
2958 ..snapshot.anchor_before(offset + range.end),
2959 replacement,
2960 )
2961 }));
2962 } else if range.end == range.start {
2963 let anchor = snapshot.anchor_after(range.start);
2964 edits.push((anchor..anchor, new_text.into()));
2965 } else {
2966 let edit_start = snapshot.anchor_after(range.start);
2967 let edit_end = snapshot.anchor_before(range.end);
2968 edits.push((edit_start..edit_end, new_text.into()));
2969 }
2970 }
2971
2972 Ok(edits)
2973 })
2974 }
2975
2976 pub(crate) async fn deserialize_workspace_edit(
2977 this: Entity<LspStore>,
2978 edit: lsp::WorkspaceEdit,
2979 push_to_history: bool,
2980 language_server: Arc<LanguageServer>,
2981 cx: &mut AsyncApp,
2982 ) -> Result<ProjectTransaction> {
2983 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2984
2985 let mut operations = Vec::new();
2986 if let Some(document_changes) = edit.document_changes {
2987 match document_changes {
2988 lsp::DocumentChanges::Edits(edits) => {
2989 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2990 }
2991 lsp::DocumentChanges::Operations(ops) => operations = ops,
2992 }
2993 } else if let Some(changes) = edit.changes {
2994 operations.extend(changes.into_iter().map(|(uri, edits)| {
2995 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2996 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2997 uri,
2998 version: None,
2999 },
3000 edits: edits.into_iter().map(Edit::Plain).collect(),
3001 })
3002 }));
3003 }
3004
3005 let mut project_transaction = ProjectTransaction::default();
3006 for operation in operations {
3007 match operation {
3008 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3009 let abs_path = op
3010 .uri
3011 .to_file_path()
3012 .map_err(|()| anyhow!("can't convert URI to path"))?;
3013
3014 if let Some(parent_path) = abs_path.parent() {
3015 fs.create_dir(parent_path).await?;
3016 }
3017 if abs_path.ends_with("/") {
3018 fs.create_dir(&abs_path).await?;
3019 } else {
3020 fs.create_file(
3021 &abs_path,
3022 op.options
3023 .map(|options| fs::CreateOptions {
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
3033 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3034 let source_abs_path = op
3035 .old_uri
3036 .to_file_path()
3037 .map_err(|()| anyhow!("can't convert URI to path"))?;
3038 let target_abs_path = op
3039 .new_uri
3040 .to_file_path()
3041 .map_err(|()| anyhow!("can't convert URI to path"))?;
3042
3043 let options = fs::RenameOptions {
3044 overwrite: op
3045 .options
3046 .as_ref()
3047 .and_then(|options| options.overwrite)
3048 .unwrap_or(false),
3049 ignore_if_exists: op
3050 .options
3051 .as_ref()
3052 .and_then(|options| options.ignore_if_exists)
3053 .unwrap_or(false),
3054 create_parents: true,
3055 };
3056
3057 fs.rename(&source_abs_path, &target_abs_path, options)
3058 .await?;
3059 }
3060
3061 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3062 let abs_path = op
3063 .uri
3064 .to_file_path()
3065 .map_err(|()| anyhow!("can't convert URI to path"))?;
3066 let options = op
3067 .options
3068 .map(|options| fs::RemoveOptions {
3069 recursive: options.recursive.unwrap_or(false),
3070 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3071 })
3072 .unwrap_or_default();
3073 if abs_path.ends_with("/") {
3074 fs.remove_dir(&abs_path, options).await?;
3075 } else {
3076 fs.remove_file(&abs_path, options).await?;
3077 }
3078 }
3079
3080 lsp::DocumentChangeOperation::Edit(op) => {
3081 let buffer_to_edit = this
3082 .update(cx, |this, cx| {
3083 this.open_local_buffer_via_lsp(
3084 op.text_document.uri.clone(),
3085 language_server.server_id(),
3086 cx,
3087 )
3088 })?
3089 .await?;
3090
3091 let edits = this
3092 .update(cx, |this, cx| {
3093 let path = buffer_to_edit.read(cx).project_path(cx);
3094 let active_entry = this.active_entry;
3095 let is_active_entry = path.is_some_and(|project_path| {
3096 this.worktree_store
3097 .read(cx)
3098 .entry_for_path(&project_path, cx)
3099 .is_some_and(|entry| Some(entry.id) == active_entry)
3100 });
3101 let local = this.as_local_mut().unwrap();
3102
3103 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3104 for edit in op.edits {
3105 match edit {
3106 Edit::Plain(edit) => {
3107 if !edits.contains(&edit) {
3108 edits.push(edit)
3109 }
3110 }
3111 Edit::Annotated(edit) => {
3112 if !edits.contains(&edit.text_edit) {
3113 edits.push(edit.text_edit)
3114 }
3115 }
3116 Edit::Snippet(edit) => {
3117 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3118 else {
3119 continue;
3120 };
3121
3122 if is_active_entry {
3123 snippet_edits.push((edit.range, snippet));
3124 } else {
3125 // Since this buffer is not focused, apply a normal edit.
3126 let new_edit = TextEdit {
3127 range: edit.range,
3128 new_text: snippet.text,
3129 };
3130 if !edits.contains(&new_edit) {
3131 edits.push(new_edit);
3132 }
3133 }
3134 }
3135 }
3136 }
3137 if !snippet_edits.is_empty() {
3138 let buffer_id = buffer_to_edit.read(cx).remote_id();
3139 let version = if let Some(buffer_version) = op.text_document.version
3140 {
3141 local
3142 .buffer_snapshot_for_lsp_version(
3143 &buffer_to_edit,
3144 language_server.server_id(),
3145 Some(buffer_version),
3146 cx,
3147 )
3148 .ok()
3149 .map(|snapshot| snapshot.version)
3150 } else {
3151 Some(buffer_to_edit.read(cx).saved_version().clone())
3152 };
3153
3154 let most_recent_edit =
3155 version.and_then(|version| version.most_recent());
3156 // Check if the edit that triggered that edit has been made by this participant.
3157
3158 if let Some(most_recent_edit) = most_recent_edit {
3159 cx.emit(LspStoreEvent::SnippetEdit {
3160 buffer_id,
3161 edits: snippet_edits,
3162 most_recent_edit,
3163 });
3164 }
3165 }
3166
3167 local.edits_from_lsp(
3168 &buffer_to_edit,
3169 edits,
3170 language_server.server_id(),
3171 op.text_document.version,
3172 cx,
3173 )
3174 })?
3175 .await?;
3176
3177 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3178 buffer.finalize_last_transaction();
3179 buffer.start_transaction();
3180 for (range, text) in edits {
3181 buffer.edit([(range, text)], None, cx);
3182 }
3183
3184 buffer.end_transaction(cx).and_then(|transaction_id| {
3185 if push_to_history {
3186 buffer.finalize_last_transaction();
3187 buffer.get_transaction(transaction_id).cloned()
3188 } else {
3189 buffer.forget_transaction(transaction_id)
3190 }
3191 })
3192 })?;
3193 if let Some(transaction) = transaction {
3194 project_transaction.0.insert(buffer_to_edit, transaction);
3195 }
3196 }
3197 }
3198 }
3199
3200 Ok(project_transaction)
3201 }
3202
3203 async fn on_lsp_workspace_edit(
3204 this: WeakEntity<LspStore>,
3205 params: lsp::ApplyWorkspaceEditParams,
3206 server_id: LanguageServerId,
3207 cx: &mut AsyncApp,
3208 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3209 let this = this.upgrade().context("project project closed")?;
3210 let language_server = this
3211 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3212 .context("language server not found")?;
3213 let transaction = Self::deserialize_workspace_edit(
3214 this.clone(),
3215 params.edit,
3216 true,
3217 language_server.clone(),
3218 cx,
3219 )
3220 .await
3221 .log_err();
3222 this.update(cx, |this, _| {
3223 if let Some(transaction) = transaction {
3224 this.as_local_mut()
3225 .unwrap()
3226 .last_workspace_edits_by_language_server
3227 .insert(server_id, transaction);
3228 }
3229 })?;
3230 Ok(lsp::ApplyWorkspaceEditResponse {
3231 applied: true,
3232 failed_change: None,
3233 failure_reason: None,
3234 })
3235 }
3236
3237 fn remove_worktree(
3238 &mut self,
3239 id_to_remove: WorktreeId,
3240 cx: &mut Context<LspStore>,
3241 ) -> Vec<LanguageServerId> {
3242 self.diagnostics.remove(&id_to_remove);
3243 self.prettier_store.update(cx, |prettier_store, cx| {
3244 prettier_store.remove_worktree(id_to_remove, cx);
3245 });
3246
3247 let mut servers_to_remove = BTreeSet::default();
3248 let mut servers_to_preserve = HashSet::default();
3249 for (seed, state) in &self.language_server_ids {
3250 if seed.worktree_id == id_to_remove {
3251 servers_to_remove.insert(state.id);
3252 } else {
3253 servers_to_preserve.insert(state.id);
3254 }
3255 }
3256 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3257 self.language_server_ids
3258 .retain(|_, state| !servers_to_remove.contains(&state.id));
3259 for server_id_to_remove in &servers_to_remove {
3260 self.language_server_watched_paths
3261 .remove(server_id_to_remove);
3262 self.language_server_paths_watched_for_rename
3263 .remove(server_id_to_remove);
3264 self.last_workspace_edits_by_language_server
3265 .remove(server_id_to_remove);
3266 self.language_servers.remove(server_id_to_remove);
3267 self.buffer_pull_diagnostics_result_ids
3268 .remove(server_id_to_remove);
3269 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3270 buffer_servers.remove(server_id_to_remove);
3271 }
3272 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3273 }
3274 servers_to_remove.into_iter().collect()
3275 }
3276
3277 fn rebuild_watched_paths_inner<'a>(
3278 &'a self,
3279 language_server_id: LanguageServerId,
3280 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3281 cx: &mut Context<LspStore>,
3282 ) -> LanguageServerWatchedPathsBuilder {
3283 let worktrees = self
3284 .worktree_store
3285 .read(cx)
3286 .worktrees()
3287 .filter_map(|worktree| {
3288 self.language_servers_for_worktree(worktree.read(cx).id())
3289 .find(|server| server.server_id() == language_server_id)
3290 .map(|_| worktree)
3291 })
3292 .collect::<Vec<_>>();
3293
3294 let mut worktree_globs = HashMap::default();
3295 let mut abs_globs = HashMap::default();
3296 log::trace!(
3297 "Processing new watcher paths for language server with id {}",
3298 language_server_id
3299 );
3300
3301 for watcher in watchers {
3302 if let Some((worktree, literal_prefix, pattern)) =
3303 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3304 {
3305 worktree.update(cx, |worktree, _| {
3306 if let Some((tree, glob)) =
3307 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3308 {
3309 tree.add_path_prefix_to_scan(literal_prefix);
3310 worktree_globs
3311 .entry(tree.id())
3312 .or_insert_with(GlobSetBuilder::new)
3313 .add(glob);
3314 }
3315 });
3316 } else {
3317 let (path, pattern) = match &watcher.glob_pattern {
3318 lsp::GlobPattern::String(s) => {
3319 let watcher_path = SanitizedPath::new(s);
3320 let path = glob_literal_prefix(watcher_path.as_path());
3321 let pattern = watcher_path
3322 .as_path()
3323 .strip_prefix(&path)
3324 .map(|p| p.to_string_lossy().into_owned())
3325 .unwrap_or_else(|e| {
3326 debug_panic!(
3327 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3328 s,
3329 path.display(),
3330 e
3331 );
3332 watcher_path.as_path().to_string_lossy().into_owned()
3333 });
3334 (path, pattern)
3335 }
3336 lsp::GlobPattern::Relative(rp) => {
3337 let Ok(mut base_uri) = match &rp.base_uri {
3338 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3339 lsp::OneOf::Right(base_uri) => base_uri,
3340 }
3341 .to_file_path() else {
3342 continue;
3343 };
3344
3345 let path = glob_literal_prefix(Path::new(&rp.pattern));
3346 let pattern = Path::new(&rp.pattern)
3347 .strip_prefix(&path)
3348 .map(|p| p.to_string_lossy().into_owned())
3349 .unwrap_or_else(|e| {
3350 debug_panic!(
3351 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3352 rp.pattern,
3353 path.display(),
3354 e
3355 );
3356 rp.pattern.clone()
3357 });
3358 base_uri.push(path);
3359 (base_uri, pattern)
3360 }
3361 };
3362
3363 if let Some(glob) = Glob::new(&pattern).log_err() {
3364 if !path
3365 .components()
3366 .any(|c| matches!(c, path::Component::Normal(_)))
3367 {
3368 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3369 // rather than adding a new watcher for `/`.
3370 for worktree in &worktrees {
3371 worktree_globs
3372 .entry(worktree.read(cx).id())
3373 .or_insert_with(GlobSetBuilder::new)
3374 .add(glob.clone());
3375 }
3376 } else {
3377 abs_globs
3378 .entry(path.into())
3379 .or_insert_with(GlobSetBuilder::new)
3380 .add(glob);
3381 }
3382 }
3383 }
3384 }
3385
3386 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3387 for (worktree_id, builder) in worktree_globs {
3388 if let Ok(globset) = builder.build() {
3389 watch_builder.watch_worktree(worktree_id, globset);
3390 }
3391 }
3392 for (abs_path, builder) in abs_globs {
3393 if let Ok(globset) = builder.build() {
3394 watch_builder.watch_abs_path(abs_path, globset);
3395 }
3396 }
3397 watch_builder
3398 }
3399
3400 fn worktree_and_path_for_file_watcher(
3401 worktrees: &[Entity<Worktree>],
3402 watcher: &FileSystemWatcher,
3403 cx: &App,
3404 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3405 worktrees.iter().find_map(|worktree| {
3406 let tree = worktree.read(cx);
3407 let worktree_root_path = tree.abs_path();
3408 let path_style = tree.path_style();
3409 match &watcher.glob_pattern {
3410 lsp::GlobPattern::String(s) => {
3411 let watcher_path = SanitizedPath::new(s);
3412 let relative = watcher_path
3413 .as_path()
3414 .strip_prefix(&worktree_root_path)
3415 .ok()?;
3416 let literal_prefix = glob_literal_prefix(relative);
3417 Some((
3418 worktree.clone(),
3419 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3420 relative.to_string_lossy().into_owned(),
3421 ))
3422 }
3423 lsp::GlobPattern::Relative(rp) => {
3424 let base_uri = match &rp.base_uri {
3425 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3426 lsp::OneOf::Right(base_uri) => base_uri,
3427 }
3428 .to_file_path()
3429 .ok()?;
3430 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3431 let mut literal_prefix = relative.to_owned();
3432 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3433 Some((
3434 worktree.clone(),
3435 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3436 rp.pattern.clone(),
3437 ))
3438 }
3439 }
3440 })
3441 }
3442
3443 fn rebuild_watched_paths(
3444 &mut self,
3445 language_server_id: LanguageServerId,
3446 cx: &mut Context<LspStore>,
3447 ) {
3448 let Some(registrations) = self
3449 .language_server_dynamic_registrations
3450 .get(&language_server_id)
3451 else {
3452 return;
3453 };
3454
3455 let watch_builder = self.rebuild_watched_paths_inner(
3456 language_server_id,
3457 registrations.did_change_watched_files.values().flatten(),
3458 cx,
3459 );
3460 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3461 self.language_server_watched_paths
3462 .insert(language_server_id, watcher);
3463
3464 cx.notify();
3465 }
3466
3467 fn on_lsp_did_change_watched_files(
3468 &mut self,
3469 language_server_id: LanguageServerId,
3470 registration_id: &str,
3471 params: DidChangeWatchedFilesRegistrationOptions,
3472 cx: &mut Context<LspStore>,
3473 ) {
3474 let registrations = self
3475 .language_server_dynamic_registrations
3476 .entry(language_server_id)
3477 .or_default();
3478
3479 registrations
3480 .did_change_watched_files
3481 .insert(registration_id.to_string(), params.watchers);
3482
3483 self.rebuild_watched_paths(language_server_id, cx);
3484 }
3485
3486 fn on_lsp_unregister_did_change_watched_files(
3487 &mut self,
3488 language_server_id: LanguageServerId,
3489 registration_id: &str,
3490 cx: &mut Context<LspStore>,
3491 ) {
3492 let registrations = self
3493 .language_server_dynamic_registrations
3494 .entry(language_server_id)
3495 .or_default();
3496
3497 if registrations
3498 .did_change_watched_files
3499 .remove(registration_id)
3500 .is_some()
3501 {
3502 log::info!(
3503 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3504 language_server_id,
3505 registration_id
3506 );
3507 } else {
3508 log::warn!(
3509 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3510 language_server_id,
3511 registration_id
3512 );
3513 }
3514
3515 self.rebuild_watched_paths(language_server_id, cx);
3516 }
3517
3518 async fn initialization_options_for_adapter(
3519 adapter: Arc<dyn LspAdapter>,
3520 delegate: &Arc<dyn LspAdapterDelegate>,
3521 ) -> Result<Option<serde_json::Value>> {
3522 let Some(mut initialization_config) =
3523 adapter.clone().initialization_options(delegate).await?
3524 else {
3525 return Ok(None);
3526 };
3527
3528 for other_adapter in delegate.registered_lsp_adapters() {
3529 if other_adapter.name() == adapter.name() {
3530 continue;
3531 }
3532 if let Ok(Some(target_config)) = other_adapter
3533 .clone()
3534 .additional_initialization_options(adapter.name(), delegate)
3535 .await
3536 {
3537 merge_json_value_into(target_config.clone(), &mut initialization_config);
3538 }
3539 }
3540
3541 Ok(Some(initialization_config))
3542 }
3543
3544 async fn workspace_configuration_for_adapter(
3545 adapter: Arc<dyn LspAdapter>,
3546 delegate: &Arc<dyn LspAdapterDelegate>,
3547 toolchain: Option<Toolchain>,
3548 requested_uri: Option<Uri>,
3549 cx: &mut AsyncApp,
3550 ) -> Result<serde_json::Value> {
3551 let mut workspace_config = adapter
3552 .clone()
3553 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3554 .await?;
3555
3556 for other_adapter in delegate.registered_lsp_adapters() {
3557 if other_adapter.name() == adapter.name() {
3558 continue;
3559 }
3560 if let Ok(Some(target_config)) = other_adapter
3561 .clone()
3562 .additional_workspace_configuration(adapter.name(), delegate, cx)
3563 .await
3564 {
3565 merge_json_value_into(target_config.clone(), &mut workspace_config);
3566 }
3567 }
3568
3569 Ok(workspace_config)
3570 }
3571
3572 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3573 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3574 Some(server.clone())
3575 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3576 Some(Arc::clone(server))
3577 } else {
3578 None
3579 }
3580 }
3581}
3582
3583fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3584 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3585 cx.emit(LspStoreEvent::LanguageServerUpdate {
3586 language_server_id: server.server_id(),
3587 name: Some(server.name()),
3588 message: proto::update_language_server::Variant::MetadataUpdated(
3589 proto::ServerMetadataUpdated {
3590 capabilities: Some(capabilities),
3591 binary: Some(proto::LanguageServerBinaryInfo {
3592 path: server.binary().path.to_string_lossy().into_owned(),
3593 arguments: server
3594 .binary()
3595 .arguments
3596 .iter()
3597 .map(|arg| arg.to_string_lossy().into_owned())
3598 .collect(),
3599 }),
3600 configuration: serde_json::to_string(server.configuration()).ok(),
3601 workspace_folders: server
3602 .workspace_folders()
3603 .iter()
3604 .map(|uri| uri.to_string())
3605 .collect(),
3606 },
3607 ),
3608 });
3609 }
3610}
3611
3612#[derive(Debug)]
3613pub struct FormattableBuffer {
3614 handle: Entity<Buffer>,
3615 abs_path: Option<PathBuf>,
3616 env: Option<HashMap<String, String>>,
3617 ranges: Option<Vec<Range<Anchor>>>,
3618}
3619
3620pub struct RemoteLspStore {
3621 upstream_client: Option<AnyProtoClient>,
3622 upstream_project_id: u64,
3623}
3624
3625pub(crate) enum LspStoreMode {
3626 Local(LocalLspStore), // ssh host and collab host
3627 Remote(RemoteLspStore), // collab guest
3628}
3629
3630impl LspStoreMode {
3631 fn is_local(&self) -> bool {
3632 matches!(self, LspStoreMode::Local(_))
3633 }
3634}
3635
3636pub struct LspStore {
3637 mode: LspStoreMode,
3638 last_formatting_failure: Option<String>,
3639 downstream_client: Option<(AnyProtoClient, u64)>,
3640 nonce: u128,
3641 buffer_store: Entity<BufferStore>,
3642 worktree_store: Entity<WorktreeStore>,
3643 pub languages: Arc<LanguageRegistry>,
3644 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3645 active_entry: Option<ProjectEntryId>,
3646 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3647 _maintain_buffer_languages: Task<()>,
3648 diagnostic_summaries:
3649 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3650 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3651 lsp_data: HashMap<BufferId, BufferLspData>,
3652 next_hint_id: Arc<AtomicUsize>,
3653}
3654
3655#[derive(Debug)]
3656pub struct BufferLspData {
3657 buffer_version: Global,
3658 document_colors: Option<DocumentColorData>,
3659 code_lens: Option<CodeLensData>,
3660 inlay_hints: BufferInlayHints,
3661 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3662 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3663}
3664
3665#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3666struct LspKey {
3667 request_type: TypeId,
3668 server_queried: Option<LanguageServerId>,
3669}
3670
3671impl BufferLspData {
3672 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3673 Self {
3674 buffer_version: buffer.read(cx).version(),
3675 document_colors: None,
3676 code_lens: None,
3677 inlay_hints: BufferInlayHints::new(buffer, cx),
3678 lsp_requests: HashMap::default(),
3679 chunk_lsp_requests: HashMap::default(),
3680 }
3681 }
3682
3683 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3684 if let Some(document_colors) = &mut self.document_colors {
3685 document_colors.colors.remove(&for_server);
3686 document_colors.cache_version += 1;
3687 }
3688
3689 if let Some(code_lens) = &mut self.code_lens {
3690 code_lens.lens.remove(&for_server);
3691 }
3692
3693 self.inlay_hints.remove_server_data(for_server);
3694 }
3695
3696 #[cfg(any(test, feature = "test-support"))]
3697 pub fn inlay_hints(&self) -> &BufferInlayHints {
3698 &self.inlay_hints
3699 }
3700}
3701
3702#[derive(Debug, Default, Clone)]
3703pub struct DocumentColors {
3704 pub colors: HashSet<DocumentColor>,
3705 pub cache_version: Option<usize>,
3706}
3707
3708type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3709type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3710
3711#[derive(Debug, Default)]
3712struct DocumentColorData {
3713 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3714 cache_version: usize,
3715 colors_update: Option<(Global, DocumentColorTask)>,
3716}
3717
3718#[derive(Debug, Default)]
3719struct CodeLensData {
3720 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3721 update: Option<(Global, CodeLensTask)>,
3722}
3723
3724#[derive(Debug)]
3725pub enum LspStoreEvent {
3726 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3727 LanguageServerRemoved(LanguageServerId),
3728 LanguageServerUpdate {
3729 language_server_id: LanguageServerId,
3730 name: Option<LanguageServerName>,
3731 message: proto::update_language_server::Variant,
3732 },
3733 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3734 LanguageServerPrompt(LanguageServerPromptRequest),
3735 LanguageDetected {
3736 buffer: Entity<Buffer>,
3737 new_language: Option<Arc<Language>>,
3738 },
3739 Notification(String),
3740 RefreshInlayHints {
3741 server_id: LanguageServerId,
3742 request_id: Option<usize>,
3743 },
3744 RefreshCodeLens,
3745 DiagnosticsUpdated {
3746 server_id: LanguageServerId,
3747 paths: Vec<ProjectPath>,
3748 },
3749 DiskBasedDiagnosticsStarted {
3750 language_server_id: LanguageServerId,
3751 },
3752 DiskBasedDiagnosticsFinished {
3753 language_server_id: LanguageServerId,
3754 },
3755 SnippetEdit {
3756 buffer_id: BufferId,
3757 edits: Vec<(lsp::Range, Snippet)>,
3758 most_recent_edit: clock::Lamport,
3759 },
3760}
3761
3762#[derive(Clone, Debug, Serialize)]
3763pub struct LanguageServerStatus {
3764 pub name: LanguageServerName,
3765 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3766 pub has_pending_diagnostic_updates: bool,
3767 pub progress_tokens: HashSet<ProgressToken>,
3768 pub worktree: Option<WorktreeId>,
3769 pub binary: Option<LanguageServerBinary>,
3770 pub configuration: Option<Value>,
3771 pub workspace_folders: BTreeSet<Uri>,
3772}
3773
3774#[derive(Clone, Debug)]
3775struct CoreSymbol {
3776 pub language_server_name: LanguageServerName,
3777 pub source_worktree_id: WorktreeId,
3778 pub source_language_server_id: LanguageServerId,
3779 pub path: SymbolLocation,
3780 pub name: String,
3781 pub kind: lsp::SymbolKind,
3782 pub range: Range<Unclipped<PointUtf16>>,
3783}
3784
3785#[derive(Clone, Debug, PartialEq, Eq)]
3786pub enum SymbolLocation {
3787 InProject(ProjectPath),
3788 OutsideProject {
3789 abs_path: Arc<Path>,
3790 signature: [u8; 32],
3791 },
3792}
3793
3794impl SymbolLocation {
3795 fn file_name(&self) -> Option<&str> {
3796 match self {
3797 Self::InProject(path) => path.path.file_name(),
3798 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3799 }
3800 }
3801}
3802
3803impl LspStore {
3804 pub fn init(client: &AnyProtoClient) {
3805 client.add_entity_request_handler(Self::handle_lsp_query);
3806 client.add_entity_message_handler(Self::handle_lsp_query_response);
3807 client.add_entity_request_handler(Self::handle_restart_language_servers);
3808 client.add_entity_request_handler(Self::handle_stop_language_servers);
3809 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3810 client.add_entity_message_handler(Self::handle_start_language_server);
3811 client.add_entity_message_handler(Self::handle_update_language_server);
3812 client.add_entity_message_handler(Self::handle_language_server_log);
3813 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3814 client.add_entity_request_handler(Self::handle_format_buffers);
3815 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3816 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3817 client.add_entity_request_handler(Self::handle_apply_code_action);
3818 client.add_entity_request_handler(Self::handle_get_project_symbols);
3819 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3820 client.add_entity_request_handler(Self::handle_get_color_presentation);
3821 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3822 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3823 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3824 client.add_entity_request_handler(Self::handle_on_type_formatting);
3825 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3826 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3827 client.add_entity_request_handler(Self::handle_rename_project_entry);
3828 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3829 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3830 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3831 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3832 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3833 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3834 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3835
3836 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3837 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3838 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3839 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3840 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3841 client.add_entity_request_handler(
3842 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3843 );
3844 client.add_entity_request_handler(
3845 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3846 );
3847 client.add_entity_request_handler(
3848 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3849 );
3850 }
3851
3852 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3853 match &self.mode {
3854 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3855 _ => None,
3856 }
3857 }
3858
3859 pub fn as_local(&self) -> Option<&LocalLspStore> {
3860 match &self.mode {
3861 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3862 _ => None,
3863 }
3864 }
3865
3866 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3867 match &mut self.mode {
3868 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3869 _ => None,
3870 }
3871 }
3872
3873 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3874 match &self.mode {
3875 LspStoreMode::Remote(RemoteLspStore {
3876 upstream_client: Some(upstream_client),
3877 upstream_project_id,
3878 ..
3879 }) => Some((upstream_client.clone(), *upstream_project_id)),
3880
3881 LspStoreMode::Remote(RemoteLspStore {
3882 upstream_client: None,
3883 ..
3884 }) => None,
3885 LspStoreMode::Local(_) => None,
3886 }
3887 }
3888
3889 pub fn new_local(
3890 buffer_store: Entity<BufferStore>,
3891 worktree_store: Entity<WorktreeStore>,
3892 prettier_store: Entity<PrettierStore>,
3893 toolchain_store: Entity<LocalToolchainStore>,
3894 environment: Entity<ProjectEnvironment>,
3895 manifest_tree: Entity<ManifestTree>,
3896 languages: Arc<LanguageRegistry>,
3897 http_client: Arc<dyn HttpClient>,
3898 fs: Arc<dyn Fs>,
3899 cx: &mut Context<Self>,
3900 ) -> Self {
3901 let yarn = YarnPathStore::new(fs.clone(), cx);
3902 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3903 .detach();
3904 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3905 .detach();
3906 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3907 .detach();
3908 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3909 .detach();
3910 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3911 .detach();
3912 subscribe_to_binary_statuses(&languages, cx).detach();
3913
3914 let _maintain_workspace_config = {
3915 let (sender, receiver) = watch::channel();
3916 (Self::maintain_workspace_config(receiver, cx), sender)
3917 };
3918
3919 Self {
3920 mode: LspStoreMode::Local(LocalLspStore {
3921 weak: cx.weak_entity(),
3922 worktree_store: worktree_store.clone(),
3923
3924 supplementary_language_servers: Default::default(),
3925 languages: languages.clone(),
3926 language_server_ids: Default::default(),
3927 language_servers: Default::default(),
3928 last_workspace_edits_by_language_server: Default::default(),
3929 language_server_watched_paths: Default::default(),
3930 language_server_paths_watched_for_rename: Default::default(),
3931 language_server_dynamic_registrations: Default::default(),
3932 buffers_being_formatted: Default::default(),
3933 buffer_snapshots: Default::default(),
3934 prettier_store,
3935 environment,
3936 http_client,
3937 fs,
3938 yarn,
3939 next_diagnostic_group_id: Default::default(),
3940 diagnostics: Default::default(),
3941 _subscription: cx.on_app_quit(|this, cx| {
3942 this.as_local_mut()
3943 .unwrap()
3944 .shutdown_language_servers_on_quit(cx)
3945 }),
3946 lsp_tree: LanguageServerTree::new(
3947 manifest_tree,
3948 languages.clone(),
3949 toolchain_store.clone(),
3950 ),
3951 toolchain_store,
3952 registered_buffers: HashMap::default(),
3953 buffers_opened_in_servers: HashMap::default(),
3954 buffer_pull_diagnostics_result_ids: HashMap::default(),
3955 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3956 .manifest_file_names(),
3957 }),
3958 last_formatting_failure: None,
3959 downstream_client: None,
3960 buffer_store,
3961 worktree_store,
3962 languages: languages.clone(),
3963 language_server_statuses: Default::default(),
3964 nonce: StdRng::from_os_rng().random(),
3965 diagnostic_summaries: HashMap::default(),
3966 lsp_server_capabilities: HashMap::default(),
3967 lsp_data: HashMap::default(),
3968 next_hint_id: Arc::default(),
3969 active_entry: None,
3970 _maintain_workspace_config,
3971 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3972 }
3973 }
3974
3975 fn send_lsp_proto_request<R: LspCommand>(
3976 &self,
3977 buffer: Entity<Buffer>,
3978 client: AnyProtoClient,
3979 upstream_project_id: u64,
3980 request: R,
3981 cx: &mut Context<LspStore>,
3982 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3983 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3984 return Task::ready(Ok(R::Response::default()));
3985 }
3986 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3987 cx.spawn(async move |this, cx| {
3988 let response = client.request(message).await?;
3989 let this = this.upgrade().context("project dropped")?;
3990 request
3991 .response_from_proto(response, this, buffer, cx.clone())
3992 .await
3993 })
3994 }
3995
3996 pub(super) fn new_remote(
3997 buffer_store: Entity<BufferStore>,
3998 worktree_store: Entity<WorktreeStore>,
3999 languages: Arc<LanguageRegistry>,
4000 upstream_client: AnyProtoClient,
4001 project_id: u64,
4002 cx: &mut Context<Self>,
4003 ) -> Self {
4004 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4005 .detach();
4006 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4007 .detach();
4008 subscribe_to_binary_statuses(&languages, cx).detach();
4009 let _maintain_workspace_config = {
4010 let (sender, receiver) = watch::channel();
4011 (Self::maintain_workspace_config(receiver, cx), sender)
4012 };
4013 Self {
4014 mode: LspStoreMode::Remote(RemoteLspStore {
4015 upstream_client: Some(upstream_client),
4016 upstream_project_id: project_id,
4017 }),
4018 downstream_client: None,
4019 last_formatting_failure: None,
4020 buffer_store,
4021 worktree_store,
4022 languages: languages.clone(),
4023 language_server_statuses: Default::default(),
4024 nonce: StdRng::from_os_rng().random(),
4025 diagnostic_summaries: HashMap::default(),
4026 lsp_server_capabilities: HashMap::default(),
4027 next_hint_id: Arc::default(),
4028 lsp_data: HashMap::default(),
4029 active_entry: None,
4030
4031 _maintain_workspace_config,
4032 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4033 }
4034 }
4035
4036 fn on_buffer_store_event(
4037 &mut self,
4038 _: Entity<BufferStore>,
4039 event: &BufferStoreEvent,
4040 cx: &mut Context<Self>,
4041 ) {
4042 match event {
4043 BufferStoreEvent::BufferAdded(buffer) => {
4044 self.on_buffer_added(buffer, cx).log_err();
4045 }
4046 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4047 let buffer_id = buffer.read(cx).remote_id();
4048 if let Some(local) = self.as_local_mut()
4049 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4050 {
4051 local.reset_buffer(buffer, old_file, cx);
4052
4053 if local.registered_buffers.contains_key(&buffer_id) {
4054 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4055 }
4056 }
4057
4058 self.detect_language_for_buffer(buffer, cx);
4059 if let Some(local) = self.as_local_mut() {
4060 local.initialize_buffer(buffer, cx);
4061 if local.registered_buffers.contains_key(&buffer_id) {
4062 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4063 }
4064 }
4065 }
4066 _ => {}
4067 }
4068 }
4069
4070 fn on_worktree_store_event(
4071 &mut self,
4072 _: Entity<WorktreeStore>,
4073 event: &WorktreeStoreEvent,
4074 cx: &mut Context<Self>,
4075 ) {
4076 match event {
4077 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4078 if !worktree.read(cx).is_local() {
4079 return;
4080 }
4081 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4082 worktree::Event::UpdatedEntries(changes) => {
4083 this.update_local_worktree_language_servers(&worktree, changes, cx);
4084 }
4085 worktree::Event::UpdatedGitRepositories(_)
4086 | worktree::Event::DeletedEntry(_) => {}
4087 })
4088 .detach()
4089 }
4090 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4091 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4092 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4093 }
4094 WorktreeStoreEvent::WorktreeReleased(..)
4095 | WorktreeStoreEvent::WorktreeOrderChanged
4096 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4097 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4098 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4099 }
4100 }
4101
4102 fn on_prettier_store_event(
4103 &mut self,
4104 _: Entity<PrettierStore>,
4105 event: &PrettierStoreEvent,
4106 cx: &mut Context<Self>,
4107 ) {
4108 match event {
4109 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4110 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4111 }
4112 PrettierStoreEvent::LanguageServerAdded {
4113 new_server_id,
4114 name,
4115 prettier_server,
4116 } => {
4117 self.register_supplementary_language_server(
4118 *new_server_id,
4119 name.clone(),
4120 prettier_server.clone(),
4121 cx,
4122 );
4123 }
4124 }
4125 }
4126
4127 fn on_toolchain_store_event(
4128 &mut self,
4129 _: Entity<LocalToolchainStore>,
4130 event: &ToolchainStoreEvent,
4131 _: &mut Context<Self>,
4132 ) {
4133 if let ToolchainStoreEvent::ToolchainActivated = event {
4134 self.request_workspace_config_refresh()
4135 }
4136 }
4137
4138 fn request_workspace_config_refresh(&mut self) {
4139 *self._maintain_workspace_config.1.borrow_mut() = ();
4140 }
4141
4142 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4143 self.as_local().map(|local| local.prettier_store.clone())
4144 }
4145
4146 fn on_buffer_event(
4147 &mut self,
4148 buffer: Entity<Buffer>,
4149 event: &language::BufferEvent,
4150 cx: &mut Context<Self>,
4151 ) {
4152 match event {
4153 language::BufferEvent::Edited => {
4154 self.on_buffer_edited(buffer, cx);
4155 }
4156
4157 language::BufferEvent::Saved => {
4158 self.on_buffer_saved(buffer, cx);
4159 }
4160
4161 _ => {}
4162 }
4163 }
4164
4165 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4166 buffer
4167 .read(cx)
4168 .set_language_registry(self.languages.clone());
4169
4170 cx.subscribe(buffer, |this, buffer, event, cx| {
4171 this.on_buffer_event(buffer, event, cx);
4172 })
4173 .detach();
4174
4175 self.detect_language_for_buffer(buffer, cx);
4176 if let Some(local) = self.as_local_mut() {
4177 local.initialize_buffer(buffer, cx);
4178 }
4179
4180 Ok(())
4181 }
4182
4183 pub(crate) fn register_buffer_with_language_servers(
4184 &mut self,
4185 buffer: &Entity<Buffer>,
4186 only_register_servers: HashSet<LanguageServerSelector>,
4187 ignore_refcounts: bool,
4188 cx: &mut Context<Self>,
4189 ) -> OpenLspBufferHandle {
4190 let buffer_id = buffer.read(cx).remote_id();
4191 let handle = cx.new(|_| buffer.clone());
4192 if let Some(local) = self.as_local_mut() {
4193 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4194 if !ignore_refcounts {
4195 *refcount += 1;
4196 }
4197
4198 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4199 // 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
4200 // 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
4201 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4202 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4203 return handle;
4204 };
4205 if !file.is_local() {
4206 return handle;
4207 }
4208
4209 if ignore_refcounts || *refcount == 1 {
4210 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4211 }
4212 if !ignore_refcounts {
4213 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4214 let refcount = {
4215 let local = lsp_store.as_local_mut().unwrap();
4216 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4217 debug_panic!("bad refcounting");
4218 return;
4219 };
4220
4221 *refcount -= 1;
4222 *refcount
4223 };
4224 if refcount == 0 {
4225 lsp_store.lsp_data.remove(&buffer_id);
4226 let local = lsp_store.as_local_mut().unwrap();
4227 local.registered_buffers.remove(&buffer_id);
4228 local.buffers_opened_in_servers.remove(&buffer_id);
4229 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4230 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4231 }
4232 }
4233 })
4234 .detach();
4235 }
4236 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4237 let buffer_id = buffer.read(cx).remote_id().to_proto();
4238 cx.background_spawn(async move {
4239 upstream_client
4240 .request(proto::RegisterBufferWithLanguageServers {
4241 project_id: upstream_project_id,
4242 buffer_id,
4243 only_servers: only_register_servers
4244 .into_iter()
4245 .map(|selector| {
4246 let selector = match selector {
4247 LanguageServerSelector::Id(language_server_id) => {
4248 proto::language_server_selector::Selector::ServerId(
4249 language_server_id.to_proto(),
4250 )
4251 }
4252 LanguageServerSelector::Name(language_server_name) => {
4253 proto::language_server_selector::Selector::Name(
4254 language_server_name.to_string(),
4255 )
4256 }
4257 };
4258 proto::LanguageServerSelector {
4259 selector: Some(selector),
4260 }
4261 })
4262 .collect(),
4263 })
4264 .await
4265 })
4266 .detach();
4267 } else {
4268 // Our remote connection got closed
4269 }
4270 handle
4271 }
4272
4273 fn maintain_buffer_languages(
4274 languages: Arc<LanguageRegistry>,
4275 cx: &mut Context<Self>,
4276 ) -> Task<()> {
4277 let mut subscription = languages.subscribe();
4278 let mut prev_reload_count = languages.reload_count();
4279 cx.spawn(async move |this, cx| {
4280 while let Some(()) = subscription.next().await {
4281 if let Some(this) = this.upgrade() {
4282 // If the language registry has been reloaded, then remove and
4283 // re-assign the languages on all open buffers.
4284 let reload_count = languages.reload_count();
4285 if reload_count > prev_reload_count {
4286 prev_reload_count = reload_count;
4287 this.update(cx, |this, cx| {
4288 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4289 for buffer in buffer_store.buffers() {
4290 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4291 {
4292 buffer.update(cx, |buffer, cx| {
4293 buffer.set_language_async(None, cx)
4294 });
4295 if let Some(local) = this.as_local_mut() {
4296 local.reset_buffer(&buffer, &f, cx);
4297
4298 if local
4299 .registered_buffers
4300 .contains_key(&buffer.read(cx).remote_id())
4301 && let Some(file_url) =
4302 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4303 {
4304 local.unregister_buffer_from_language_servers(
4305 &buffer, &file_url, cx,
4306 );
4307 }
4308 }
4309 }
4310 }
4311 });
4312 })
4313 .ok();
4314 }
4315
4316 this.update(cx, |this, cx| {
4317 let mut plain_text_buffers = Vec::new();
4318 let mut buffers_with_unknown_injections = Vec::new();
4319 for handle in this.buffer_store.read(cx).buffers() {
4320 let buffer = handle.read(cx);
4321 if buffer.language().is_none()
4322 || buffer.language() == Some(&*language::PLAIN_TEXT)
4323 {
4324 plain_text_buffers.push(handle);
4325 } else if buffer.contains_unknown_injections() {
4326 buffers_with_unknown_injections.push(handle);
4327 }
4328 }
4329
4330 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4331 // and reused later in the invisible worktrees.
4332 plain_text_buffers.sort_by_key(|buffer| {
4333 Reverse(
4334 File::from_dyn(buffer.read(cx).file())
4335 .map(|file| file.worktree.read(cx).is_visible()),
4336 )
4337 });
4338
4339 for buffer in plain_text_buffers {
4340 this.detect_language_for_buffer(&buffer, cx);
4341 if let Some(local) = this.as_local_mut() {
4342 local.initialize_buffer(&buffer, cx);
4343 if local
4344 .registered_buffers
4345 .contains_key(&buffer.read(cx).remote_id())
4346 {
4347 local.register_buffer_with_language_servers(
4348 &buffer,
4349 HashSet::default(),
4350 cx,
4351 );
4352 }
4353 }
4354 }
4355
4356 for buffer in buffers_with_unknown_injections {
4357 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4358 }
4359 })
4360 .ok();
4361 }
4362 }
4363 })
4364 }
4365
4366 fn detect_language_for_buffer(
4367 &mut self,
4368 buffer_handle: &Entity<Buffer>,
4369 cx: &mut Context<Self>,
4370 ) -> Option<language::AvailableLanguage> {
4371 // If the buffer has a language, set it and start the language server if we haven't already.
4372 let buffer = buffer_handle.read(cx);
4373 let file = buffer.file()?;
4374
4375 let content = buffer.as_rope();
4376 let available_language = self.languages.language_for_file(file, Some(content), cx);
4377 if let Some(available_language) = &available_language {
4378 if let Some(Ok(Ok(new_language))) = self
4379 .languages
4380 .load_language(available_language)
4381 .now_or_never()
4382 {
4383 self.set_language_for_buffer(buffer_handle, new_language, cx);
4384 }
4385 } else {
4386 cx.emit(LspStoreEvent::LanguageDetected {
4387 buffer: buffer_handle.clone(),
4388 new_language: None,
4389 });
4390 }
4391
4392 available_language
4393 }
4394
4395 pub(crate) fn set_language_for_buffer(
4396 &mut self,
4397 buffer_entity: &Entity<Buffer>,
4398 new_language: Arc<Language>,
4399 cx: &mut Context<Self>,
4400 ) {
4401 let buffer = buffer_entity.read(cx);
4402 let buffer_file = buffer.file().cloned();
4403 let buffer_id = buffer.remote_id();
4404 if let Some(local_store) = self.as_local_mut()
4405 && local_store.registered_buffers.contains_key(&buffer_id)
4406 && let Some(abs_path) =
4407 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4408 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4409 {
4410 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4411 }
4412 buffer_entity.update(cx, |buffer, cx| {
4413 if buffer
4414 .language()
4415 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4416 {
4417 buffer.set_language_async(Some(new_language.clone()), cx);
4418 }
4419 });
4420
4421 let settings =
4422 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4423 let buffer_file = File::from_dyn(buffer_file.as_ref());
4424
4425 let worktree_id = if let Some(file) = buffer_file {
4426 let worktree = file.worktree.clone();
4427
4428 if let Some(local) = self.as_local_mut()
4429 && local.registered_buffers.contains_key(&buffer_id)
4430 {
4431 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4432 }
4433 Some(worktree.read(cx).id())
4434 } else {
4435 None
4436 };
4437
4438 if settings.prettier.allowed
4439 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4440 {
4441 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4442 if let Some(prettier_store) = prettier_store {
4443 prettier_store.update(cx, |prettier_store, cx| {
4444 prettier_store.install_default_prettier(
4445 worktree_id,
4446 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4447 cx,
4448 )
4449 })
4450 }
4451 }
4452
4453 cx.emit(LspStoreEvent::LanguageDetected {
4454 buffer: buffer_entity.clone(),
4455 new_language: Some(new_language),
4456 })
4457 }
4458
4459 pub fn buffer_store(&self) -> Entity<BufferStore> {
4460 self.buffer_store.clone()
4461 }
4462
4463 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4464 self.active_entry = active_entry;
4465 }
4466
4467 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4468 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4469 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4470 {
4471 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4472 summaries
4473 .iter()
4474 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4475 });
4476 if let Some(summary) = summaries.next() {
4477 client
4478 .send(proto::UpdateDiagnosticSummary {
4479 project_id: downstream_project_id,
4480 worktree_id: worktree.id().to_proto(),
4481 summary: Some(summary),
4482 more_summaries: summaries.collect(),
4483 })
4484 .log_err();
4485 }
4486 }
4487 }
4488
4489 fn is_capable_for_proto_request<R>(
4490 &self,
4491 buffer: &Entity<Buffer>,
4492 request: &R,
4493 cx: &App,
4494 ) -> bool
4495 where
4496 R: LspCommand,
4497 {
4498 self.check_if_capable_for_proto_request(
4499 buffer,
4500 |capabilities| {
4501 request.check_capabilities(AdapterServerCapabilities {
4502 server_capabilities: capabilities.clone(),
4503 code_action_kinds: None,
4504 })
4505 },
4506 cx,
4507 )
4508 }
4509
4510 fn check_if_capable_for_proto_request<F>(
4511 &self,
4512 buffer: &Entity<Buffer>,
4513 check: F,
4514 cx: &App,
4515 ) -> bool
4516 where
4517 F: FnMut(&lsp::ServerCapabilities) -> bool,
4518 {
4519 let Some(language) = buffer.read(cx).language().cloned() else {
4520 return false;
4521 };
4522 let relevant_language_servers = self
4523 .languages
4524 .lsp_adapters(&language.name())
4525 .into_iter()
4526 .map(|lsp_adapter| lsp_adapter.name())
4527 .collect::<HashSet<_>>();
4528 self.language_server_statuses
4529 .iter()
4530 .filter_map(|(server_id, server_status)| {
4531 relevant_language_servers
4532 .contains(&server_status.name)
4533 .then_some(server_id)
4534 })
4535 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4536 .any(check)
4537 }
4538
4539 fn all_capable_for_proto_request<F>(
4540 &self,
4541 buffer: &Entity<Buffer>,
4542 mut check: F,
4543 cx: &App,
4544 ) -> Vec<lsp::LanguageServerId>
4545 where
4546 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4547 {
4548 let Some(language) = buffer.read(cx).language().cloned() else {
4549 return Vec::default();
4550 };
4551 let relevant_language_servers = self
4552 .languages
4553 .lsp_adapters(&language.name())
4554 .into_iter()
4555 .map(|lsp_adapter| lsp_adapter.name())
4556 .collect::<HashSet<_>>();
4557 self.language_server_statuses
4558 .iter()
4559 .filter_map(|(server_id, server_status)| {
4560 relevant_language_servers
4561 .contains(&server_status.name)
4562 .then_some((server_id, &server_status.name))
4563 })
4564 .filter_map(|(server_id, server_name)| {
4565 self.lsp_server_capabilities
4566 .get(server_id)
4567 .map(|c| (server_id, server_name, c))
4568 })
4569 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4570 .map(|(server_id, _, _)| *server_id)
4571 .collect()
4572 }
4573
4574 pub fn request_lsp<R>(
4575 &mut self,
4576 buffer: Entity<Buffer>,
4577 server: LanguageServerToQuery,
4578 request: R,
4579 cx: &mut Context<Self>,
4580 ) -> Task<Result<R::Response>>
4581 where
4582 R: LspCommand,
4583 <R::LspRequest as lsp::request::Request>::Result: Send,
4584 <R::LspRequest as lsp::request::Request>::Params: Send,
4585 {
4586 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4587 return self.send_lsp_proto_request(
4588 buffer,
4589 upstream_client,
4590 upstream_project_id,
4591 request,
4592 cx,
4593 );
4594 }
4595
4596 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4597 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4598 local
4599 .language_servers_for_buffer(buffer, cx)
4600 .find(|(_, server)| {
4601 request.check_capabilities(server.adapter_server_capabilities())
4602 })
4603 .map(|(_, server)| server.clone())
4604 }),
4605 LanguageServerToQuery::Other(id) => self
4606 .language_server_for_local_buffer(buffer, id, cx)
4607 .and_then(|(_, server)| {
4608 request
4609 .check_capabilities(server.adapter_server_capabilities())
4610 .then(|| Arc::clone(server))
4611 }),
4612 }) else {
4613 return Task::ready(Ok(Default::default()));
4614 };
4615
4616 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4617
4618 let Some(file) = file else {
4619 return Task::ready(Ok(Default::default()));
4620 };
4621
4622 let lsp_params = match request.to_lsp_params_or_response(
4623 &file.abs_path(cx),
4624 buffer.read(cx),
4625 &language_server,
4626 cx,
4627 ) {
4628 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4629 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4630 Err(err) => {
4631 let message = format!(
4632 "{} via {} failed: {}",
4633 request.display_name(),
4634 language_server.name(),
4635 err
4636 );
4637 // rust-analyzer likes to error with this when its still loading up
4638 if !message.ends_with("content modified") {
4639 log::warn!("{message}");
4640 }
4641 return Task::ready(Err(anyhow!(message)));
4642 }
4643 };
4644
4645 let status = request.status();
4646 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4647 return Task::ready(Ok(Default::default()));
4648 }
4649 cx.spawn(async move |this, cx| {
4650 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4651
4652 let id = lsp_request.id();
4653 let _cleanup = if status.is_some() {
4654 cx.update(|cx| {
4655 this.update(cx, |this, cx| {
4656 this.on_lsp_work_start(
4657 language_server.server_id(),
4658 ProgressToken::Number(id),
4659 LanguageServerProgress {
4660 is_disk_based_diagnostics_progress: false,
4661 is_cancellable: false,
4662 title: None,
4663 message: status.clone(),
4664 percentage: None,
4665 last_update_at: cx.background_executor().now(),
4666 },
4667 cx,
4668 );
4669 })
4670 })
4671 .log_err();
4672
4673 Some(defer(|| {
4674 cx.update(|cx| {
4675 this.update(cx, |this, cx| {
4676 this.on_lsp_work_end(
4677 language_server.server_id(),
4678 ProgressToken::Number(id),
4679 cx,
4680 );
4681 })
4682 })
4683 .log_err();
4684 }))
4685 } else {
4686 None
4687 };
4688
4689 let result = lsp_request.await.into_response();
4690
4691 let response = result.map_err(|err| {
4692 let message = format!(
4693 "{} via {} failed: {}",
4694 request.display_name(),
4695 language_server.name(),
4696 err
4697 );
4698 // rust-analyzer likes to error with this when its still loading up
4699 if !message.ends_with("content modified") {
4700 log::warn!("{message}");
4701 }
4702 anyhow::anyhow!(message)
4703 })?;
4704
4705 request
4706 .response_from_lsp(
4707 response,
4708 this.upgrade().context("no app context")?,
4709 buffer,
4710 language_server.server_id(),
4711 cx.clone(),
4712 )
4713 .await
4714 })
4715 }
4716
4717 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4718 let mut language_formatters_to_check = Vec::new();
4719 for buffer in self.buffer_store.read(cx).buffers() {
4720 let buffer = buffer.read(cx);
4721 let buffer_file = File::from_dyn(buffer.file());
4722 let buffer_language = buffer.language();
4723 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4724 if buffer_language.is_some() {
4725 language_formatters_to_check.push((
4726 buffer_file.map(|f| f.worktree_id(cx)),
4727 settings.into_owned(),
4728 ));
4729 }
4730 }
4731
4732 self.request_workspace_config_refresh();
4733
4734 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4735 prettier_store.update(cx, |prettier_store, cx| {
4736 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4737 })
4738 }
4739
4740 cx.notify();
4741 }
4742
4743 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4744 let buffer_store = self.buffer_store.clone();
4745 let Some(local) = self.as_local_mut() else {
4746 return;
4747 };
4748 let mut adapters = BTreeMap::default();
4749 let get_adapter = {
4750 let languages = local.languages.clone();
4751 let environment = local.environment.clone();
4752 let weak = local.weak.clone();
4753 let worktree_store = local.worktree_store.clone();
4754 let http_client = local.http_client.clone();
4755 let fs = local.fs.clone();
4756 move |worktree_id, cx: &mut App| {
4757 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4758 Some(LocalLspAdapterDelegate::new(
4759 languages.clone(),
4760 &environment,
4761 weak.clone(),
4762 &worktree,
4763 http_client.clone(),
4764 fs.clone(),
4765 cx,
4766 ))
4767 }
4768 };
4769
4770 let mut messages_to_report = Vec::new();
4771 let (new_tree, to_stop) = {
4772 let mut rebase = local.lsp_tree.rebase();
4773 let buffers = buffer_store
4774 .read(cx)
4775 .buffers()
4776 .filter_map(|buffer| {
4777 let raw_buffer = buffer.read(cx);
4778 if !local
4779 .registered_buffers
4780 .contains_key(&raw_buffer.remote_id())
4781 {
4782 return None;
4783 }
4784 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4785 let language = raw_buffer.language().cloned()?;
4786 Some((file, language, raw_buffer.remote_id()))
4787 })
4788 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4789 for (file, language, buffer_id) in buffers {
4790 let worktree_id = file.worktree_id(cx);
4791 let Some(worktree) = local
4792 .worktree_store
4793 .read(cx)
4794 .worktree_for_id(worktree_id, cx)
4795 else {
4796 continue;
4797 };
4798
4799 if let Some((_, apply)) = local.reuse_existing_language_server(
4800 rebase.server_tree(),
4801 &worktree,
4802 &language.name(),
4803 cx,
4804 ) {
4805 (apply)(rebase.server_tree());
4806 } else if let Some(lsp_delegate) = adapters
4807 .entry(worktree_id)
4808 .or_insert_with(|| get_adapter(worktree_id, cx))
4809 .clone()
4810 {
4811 let delegate =
4812 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4813 let path = file
4814 .path()
4815 .parent()
4816 .map(Arc::from)
4817 .unwrap_or_else(|| file.path().clone());
4818 let worktree_path = ProjectPath { worktree_id, path };
4819 let abs_path = file.abs_path(cx);
4820 let nodes = rebase
4821 .walk(
4822 worktree_path,
4823 language.name(),
4824 language.manifest(),
4825 delegate.clone(),
4826 cx,
4827 )
4828 .collect::<Vec<_>>();
4829 for node in nodes {
4830 let server_id = node.server_id_or_init(|disposition| {
4831 let path = &disposition.path;
4832 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4833 let key = LanguageServerSeed {
4834 worktree_id,
4835 name: disposition.server_name.clone(),
4836 settings: disposition.settings.clone(),
4837 toolchain: local.toolchain_store.read(cx).active_toolchain(
4838 path.worktree_id,
4839 &path.path,
4840 language.name(),
4841 ),
4842 };
4843 local.language_server_ids.remove(&key);
4844
4845 let server_id = local.get_or_insert_language_server(
4846 &worktree,
4847 lsp_delegate.clone(),
4848 disposition,
4849 &language.name(),
4850 cx,
4851 );
4852 if let Some(state) = local.language_servers.get(&server_id)
4853 && let Ok(uri) = uri
4854 {
4855 state.add_workspace_folder(uri);
4856 };
4857 server_id
4858 });
4859
4860 if let Some(language_server_id) = server_id {
4861 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4862 language_server_id,
4863 name: node.name(),
4864 message:
4865 proto::update_language_server::Variant::RegisteredForBuffer(
4866 proto::RegisteredForBuffer {
4867 buffer_abs_path: abs_path
4868 .to_string_lossy()
4869 .into_owned(),
4870 buffer_id: buffer_id.to_proto(),
4871 },
4872 ),
4873 });
4874 }
4875 }
4876 } else {
4877 continue;
4878 }
4879 }
4880 rebase.finish()
4881 };
4882 for message in messages_to_report {
4883 cx.emit(message);
4884 }
4885 local.lsp_tree = new_tree;
4886 for (id, _) in to_stop {
4887 self.stop_local_language_server(id, cx).detach();
4888 }
4889 }
4890
4891 pub fn apply_code_action(
4892 &self,
4893 buffer_handle: Entity<Buffer>,
4894 mut action: CodeAction,
4895 push_to_history: bool,
4896 cx: &mut Context<Self>,
4897 ) -> Task<Result<ProjectTransaction>> {
4898 if let Some((upstream_client, project_id)) = self.upstream_client() {
4899 let request = proto::ApplyCodeAction {
4900 project_id,
4901 buffer_id: buffer_handle.read(cx).remote_id().into(),
4902 action: Some(Self::serialize_code_action(&action)),
4903 };
4904 let buffer_store = self.buffer_store();
4905 cx.spawn(async move |_, cx| {
4906 let response = upstream_client
4907 .request(request)
4908 .await?
4909 .transaction
4910 .context("missing transaction")?;
4911
4912 buffer_store
4913 .update(cx, |buffer_store, cx| {
4914 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4915 })?
4916 .await
4917 })
4918 } else if self.mode.is_local() {
4919 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4920 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4921 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4922 }) else {
4923 return Task::ready(Ok(ProjectTransaction::default()));
4924 };
4925 cx.spawn(async move |this, cx| {
4926 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4927 .await
4928 .context("resolving a code action")?;
4929 if let Some(edit) = action.lsp_action.edit()
4930 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4931 return LocalLspStore::deserialize_workspace_edit(
4932 this.upgrade().context("no app present")?,
4933 edit.clone(),
4934 push_to_history,
4935
4936 lang_server.clone(),
4937 cx,
4938 )
4939 .await;
4940 }
4941
4942 if let Some(command) = action.lsp_action.command() {
4943 let server_capabilities = lang_server.capabilities();
4944 let available_commands = server_capabilities
4945 .execute_command_provider
4946 .as_ref()
4947 .map(|options| options.commands.as_slice())
4948 .unwrap_or_default();
4949 if available_commands.contains(&command.command) {
4950 this.update(cx, |this, _| {
4951 this.as_local_mut()
4952 .unwrap()
4953 .last_workspace_edits_by_language_server
4954 .remove(&lang_server.server_id());
4955 })?;
4956
4957 let _result = lang_server
4958 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4959 command: command.command.clone(),
4960 arguments: command.arguments.clone().unwrap_or_default(),
4961 ..lsp::ExecuteCommandParams::default()
4962 })
4963 .await.into_response()
4964 .context("execute command")?;
4965
4966 return this.update(cx, |this, _| {
4967 this.as_local_mut()
4968 .unwrap()
4969 .last_workspace_edits_by_language_server
4970 .remove(&lang_server.server_id())
4971 .unwrap_or_default()
4972 });
4973 } else {
4974 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4975 }
4976 }
4977
4978 Ok(ProjectTransaction::default())
4979 })
4980 } else {
4981 Task::ready(Err(anyhow!("no upstream client and not local")))
4982 }
4983 }
4984
4985 pub fn apply_code_action_kind(
4986 &mut self,
4987 buffers: HashSet<Entity<Buffer>>,
4988 kind: CodeActionKind,
4989 push_to_history: bool,
4990 cx: &mut Context<Self>,
4991 ) -> Task<anyhow::Result<ProjectTransaction>> {
4992 if self.as_local().is_some() {
4993 cx.spawn(async move |lsp_store, cx| {
4994 let buffers = buffers.into_iter().collect::<Vec<_>>();
4995 let result = LocalLspStore::execute_code_action_kind_locally(
4996 lsp_store.clone(),
4997 buffers,
4998 kind,
4999 push_to_history,
5000 cx,
5001 )
5002 .await;
5003 lsp_store.update(cx, |lsp_store, _| {
5004 lsp_store.update_last_formatting_failure(&result);
5005 })?;
5006 result
5007 })
5008 } else if let Some((client, project_id)) = self.upstream_client() {
5009 let buffer_store = self.buffer_store();
5010 cx.spawn(async move |lsp_store, cx| {
5011 let result = client
5012 .request(proto::ApplyCodeActionKind {
5013 project_id,
5014 kind: kind.as_str().to_owned(),
5015 buffer_ids: buffers
5016 .iter()
5017 .map(|buffer| {
5018 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5019 })
5020 .collect::<Result<_>>()?,
5021 })
5022 .await
5023 .and_then(|result| result.transaction.context("missing transaction"));
5024 lsp_store.update(cx, |lsp_store, _| {
5025 lsp_store.update_last_formatting_failure(&result);
5026 })?;
5027
5028 let transaction_response = result?;
5029 buffer_store
5030 .update(cx, |buffer_store, cx| {
5031 buffer_store.deserialize_project_transaction(
5032 transaction_response,
5033 push_to_history,
5034 cx,
5035 )
5036 })?
5037 .await
5038 })
5039 } else {
5040 Task::ready(Ok(ProjectTransaction::default()))
5041 }
5042 }
5043
5044 pub fn resolved_hint(
5045 &mut self,
5046 buffer_id: BufferId,
5047 id: InlayId,
5048 cx: &mut Context<Self>,
5049 ) -> Option<ResolvedHint> {
5050 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5051
5052 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5053 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5054 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5055 let (server_id, resolve_data) = match &hint.resolve_state {
5056 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5057 ResolveState::Resolving => {
5058 return Some(ResolvedHint::Resolving(
5059 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5060 ));
5061 }
5062 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5063 };
5064
5065 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5066 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5067 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5068 id,
5069 cx.spawn(async move |lsp_store, cx| {
5070 let resolved_hint = resolve_task.await;
5071 lsp_store
5072 .update(cx, |lsp_store, _| {
5073 if let Some(old_inlay_hint) = lsp_store
5074 .lsp_data
5075 .get_mut(&buffer_id)
5076 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5077 {
5078 match resolved_hint {
5079 Ok(resolved_hint) => {
5080 *old_inlay_hint = resolved_hint;
5081 }
5082 Err(e) => {
5083 old_inlay_hint.resolve_state =
5084 ResolveState::CanResolve(server_id, resolve_data);
5085 log::error!("Inlay hint resolve failed: {e:#}");
5086 }
5087 }
5088 }
5089 })
5090 .ok();
5091 })
5092 .shared(),
5093 );
5094 debug_assert!(
5095 previous_task.is_none(),
5096 "Did not change hint's resolve state after spawning its resolve"
5097 );
5098 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5099 None
5100 }
5101
5102 fn resolve_inlay_hint(
5103 &self,
5104 mut hint: InlayHint,
5105 buffer: Entity<Buffer>,
5106 server_id: LanguageServerId,
5107 cx: &mut Context<Self>,
5108 ) -> Task<anyhow::Result<InlayHint>> {
5109 if let Some((upstream_client, project_id)) = self.upstream_client() {
5110 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5111 {
5112 hint.resolve_state = ResolveState::Resolved;
5113 return Task::ready(Ok(hint));
5114 }
5115 let request = proto::ResolveInlayHint {
5116 project_id,
5117 buffer_id: buffer.read(cx).remote_id().into(),
5118 language_server_id: server_id.0 as u64,
5119 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5120 };
5121 cx.background_spawn(async move {
5122 let response = upstream_client
5123 .request(request)
5124 .await
5125 .context("inlay hints proto request")?;
5126 match response.hint {
5127 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5128 .context("inlay hints proto resolve response conversion"),
5129 None => Ok(hint),
5130 }
5131 })
5132 } else {
5133 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5134 self.language_server_for_local_buffer(buffer, server_id, cx)
5135 .map(|(_, server)| server.clone())
5136 }) else {
5137 return Task::ready(Ok(hint));
5138 };
5139 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5140 return Task::ready(Ok(hint));
5141 }
5142 let buffer_snapshot = buffer.read(cx).snapshot();
5143 cx.spawn(async move |_, cx| {
5144 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5145 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5146 );
5147 let resolved_hint = resolve_task
5148 .await
5149 .into_response()
5150 .context("inlay hint resolve LSP request")?;
5151 let resolved_hint = InlayHints::lsp_to_project_hint(
5152 resolved_hint,
5153 &buffer,
5154 server_id,
5155 ResolveState::Resolved,
5156 false,
5157 cx,
5158 )
5159 .await?;
5160 Ok(resolved_hint)
5161 })
5162 }
5163 }
5164
5165 pub fn resolve_color_presentation(
5166 &mut self,
5167 mut color: DocumentColor,
5168 buffer: Entity<Buffer>,
5169 server_id: LanguageServerId,
5170 cx: &mut Context<Self>,
5171 ) -> Task<Result<DocumentColor>> {
5172 if color.resolved {
5173 return Task::ready(Ok(color));
5174 }
5175
5176 if let Some((upstream_client, project_id)) = self.upstream_client() {
5177 let start = color.lsp_range.start;
5178 let end = color.lsp_range.end;
5179 let request = proto::GetColorPresentation {
5180 project_id,
5181 server_id: server_id.to_proto(),
5182 buffer_id: buffer.read(cx).remote_id().into(),
5183 color: Some(proto::ColorInformation {
5184 red: color.color.red,
5185 green: color.color.green,
5186 blue: color.color.blue,
5187 alpha: color.color.alpha,
5188 lsp_range_start: Some(proto::PointUtf16 {
5189 row: start.line,
5190 column: start.character,
5191 }),
5192 lsp_range_end: Some(proto::PointUtf16 {
5193 row: end.line,
5194 column: end.character,
5195 }),
5196 }),
5197 };
5198 cx.background_spawn(async move {
5199 let response = upstream_client
5200 .request(request)
5201 .await
5202 .context("color presentation proto request")?;
5203 color.resolved = true;
5204 color.color_presentations = response
5205 .presentations
5206 .into_iter()
5207 .map(|presentation| ColorPresentation {
5208 label: SharedString::from(presentation.label),
5209 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5210 additional_text_edits: presentation
5211 .additional_text_edits
5212 .into_iter()
5213 .filter_map(deserialize_lsp_edit)
5214 .collect(),
5215 })
5216 .collect();
5217 Ok(color)
5218 })
5219 } else {
5220 let path = match buffer
5221 .update(cx, |buffer, cx| {
5222 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5223 })
5224 .context("buffer with the missing path")
5225 {
5226 Ok(path) => path,
5227 Err(e) => return Task::ready(Err(e)),
5228 };
5229 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5230 self.language_server_for_local_buffer(buffer, server_id, cx)
5231 .map(|(_, server)| server.clone())
5232 }) else {
5233 return Task::ready(Ok(color));
5234 };
5235 cx.background_spawn(async move {
5236 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5237 lsp::ColorPresentationParams {
5238 text_document: make_text_document_identifier(&path)?,
5239 color: color.color,
5240 range: color.lsp_range,
5241 work_done_progress_params: Default::default(),
5242 partial_result_params: Default::default(),
5243 },
5244 );
5245 color.color_presentations = resolve_task
5246 .await
5247 .into_response()
5248 .context("color presentation resolve LSP request")?
5249 .into_iter()
5250 .map(|presentation| ColorPresentation {
5251 label: SharedString::from(presentation.label),
5252 text_edit: presentation.text_edit,
5253 additional_text_edits: presentation
5254 .additional_text_edits
5255 .unwrap_or_default(),
5256 })
5257 .collect();
5258 color.resolved = true;
5259 Ok(color)
5260 })
5261 }
5262 }
5263
5264 pub(crate) fn linked_edits(
5265 &mut self,
5266 buffer: &Entity<Buffer>,
5267 position: Anchor,
5268 cx: &mut Context<Self>,
5269 ) -> Task<Result<Vec<Range<Anchor>>>> {
5270 let snapshot = buffer.read(cx).snapshot();
5271 let scope = snapshot.language_scope_at(position);
5272 let Some(server_id) = self
5273 .as_local()
5274 .and_then(|local| {
5275 buffer.update(cx, |buffer, cx| {
5276 local
5277 .language_servers_for_buffer(buffer, cx)
5278 .filter(|(_, server)| {
5279 LinkedEditingRange::check_server_capabilities(server.capabilities())
5280 })
5281 .filter(|(adapter, _)| {
5282 scope
5283 .as_ref()
5284 .map(|scope| scope.language_allowed(&adapter.name))
5285 .unwrap_or(true)
5286 })
5287 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5288 .next()
5289 })
5290 })
5291 .or_else(|| {
5292 self.upstream_client()
5293 .is_some()
5294 .then_some(LanguageServerToQuery::FirstCapable)
5295 })
5296 .filter(|_| {
5297 maybe!({
5298 let language = buffer.read(cx).language_at(position)?;
5299 Some(
5300 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5301 .linked_edits,
5302 )
5303 }) == Some(true)
5304 })
5305 else {
5306 return Task::ready(Ok(Vec::new()));
5307 };
5308
5309 self.request_lsp(
5310 buffer.clone(),
5311 server_id,
5312 LinkedEditingRange { position },
5313 cx,
5314 )
5315 }
5316
5317 fn apply_on_type_formatting(
5318 &mut self,
5319 buffer: Entity<Buffer>,
5320 position: Anchor,
5321 trigger: String,
5322 cx: &mut Context<Self>,
5323 ) -> Task<Result<Option<Transaction>>> {
5324 if let Some((client, project_id)) = self.upstream_client() {
5325 if !self.check_if_capable_for_proto_request(
5326 &buffer,
5327 |capabilities| {
5328 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5329 },
5330 cx,
5331 ) {
5332 return Task::ready(Ok(None));
5333 }
5334 let request = proto::OnTypeFormatting {
5335 project_id,
5336 buffer_id: buffer.read(cx).remote_id().into(),
5337 position: Some(serialize_anchor(&position)),
5338 trigger,
5339 version: serialize_version(&buffer.read(cx).version()),
5340 };
5341 cx.background_spawn(async move {
5342 client
5343 .request(request)
5344 .await?
5345 .transaction
5346 .map(language::proto::deserialize_transaction)
5347 .transpose()
5348 })
5349 } else if let Some(local) = self.as_local_mut() {
5350 let buffer_id = buffer.read(cx).remote_id();
5351 local.buffers_being_formatted.insert(buffer_id);
5352 cx.spawn(async move |this, cx| {
5353 let _cleanup = defer({
5354 let this = this.clone();
5355 let mut cx = cx.clone();
5356 move || {
5357 this.update(&mut cx, |this, _| {
5358 if let Some(local) = this.as_local_mut() {
5359 local.buffers_being_formatted.remove(&buffer_id);
5360 }
5361 })
5362 .ok();
5363 }
5364 });
5365
5366 buffer
5367 .update(cx, |buffer, _| {
5368 buffer.wait_for_edits(Some(position.timestamp))
5369 })?
5370 .await?;
5371 this.update(cx, |this, cx| {
5372 let position = position.to_point_utf16(buffer.read(cx));
5373 this.on_type_format(buffer, position, trigger, false, cx)
5374 })?
5375 .await
5376 })
5377 } else {
5378 Task::ready(Err(anyhow!("No upstream client or local language server")))
5379 }
5380 }
5381
5382 pub fn on_type_format<T: ToPointUtf16>(
5383 &mut self,
5384 buffer: Entity<Buffer>,
5385 position: T,
5386 trigger: String,
5387 push_to_history: bool,
5388 cx: &mut Context<Self>,
5389 ) -> Task<Result<Option<Transaction>>> {
5390 let position = position.to_point_utf16(buffer.read(cx));
5391 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5392 }
5393
5394 fn on_type_format_impl(
5395 &mut self,
5396 buffer: Entity<Buffer>,
5397 position: PointUtf16,
5398 trigger: String,
5399 push_to_history: bool,
5400 cx: &mut Context<Self>,
5401 ) -> Task<Result<Option<Transaction>>> {
5402 let options = buffer.update(cx, |buffer, cx| {
5403 lsp_command::lsp_formatting_options(
5404 language_settings(
5405 buffer.language_at(position).map(|l| l.name()),
5406 buffer.file(),
5407 cx,
5408 )
5409 .as_ref(),
5410 )
5411 });
5412
5413 cx.spawn(async move |this, cx| {
5414 if let Some(waiter) =
5415 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5416 {
5417 waiter.await?;
5418 }
5419 cx.update(|cx| {
5420 this.update(cx, |this, cx| {
5421 this.request_lsp(
5422 buffer.clone(),
5423 LanguageServerToQuery::FirstCapable,
5424 OnTypeFormatting {
5425 position,
5426 trigger,
5427 options,
5428 push_to_history,
5429 },
5430 cx,
5431 )
5432 })
5433 })??
5434 .await
5435 })
5436 }
5437
5438 pub fn definitions(
5439 &mut self,
5440 buffer: &Entity<Buffer>,
5441 position: PointUtf16,
5442 cx: &mut Context<Self>,
5443 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5444 if let Some((upstream_client, project_id)) = self.upstream_client() {
5445 let request = GetDefinitions { position };
5446 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5447 return Task::ready(Ok(None));
5448 }
5449 let request_task = upstream_client.request_lsp(
5450 project_id,
5451 None,
5452 LSP_REQUEST_TIMEOUT,
5453 cx.background_executor().clone(),
5454 request.to_proto(project_id, buffer.read(cx)),
5455 );
5456 let buffer = buffer.clone();
5457 cx.spawn(async move |weak_lsp_store, cx| {
5458 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5459 return Ok(None);
5460 };
5461 let Some(responses) = request_task.await? else {
5462 return Ok(None);
5463 };
5464 let actions = join_all(responses.payload.into_iter().map(|response| {
5465 GetDefinitions { position }.response_from_proto(
5466 response.response,
5467 lsp_store.clone(),
5468 buffer.clone(),
5469 cx.clone(),
5470 )
5471 }))
5472 .await;
5473
5474 Ok(Some(
5475 actions
5476 .into_iter()
5477 .collect::<Result<Vec<Vec<_>>>>()?
5478 .into_iter()
5479 .flatten()
5480 .dedup()
5481 .collect(),
5482 ))
5483 })
5484 } else {
5485 let definitions_task = self.request_multiple_lsp_locally(
5486 buffer,
5487 Some(position),
5488 GetDefinitions { position },
5489 cx,
5490 );
5491 cx.background_spawn(async move {
5492 Ok(Some(
5493 definitions_task
5494 .await
5495 .into_iter()
5496 .flat_map(|(_, definitions)| definitions)
5497 .dedup()
5498 .collect(),
5499 ))
5500 })
5501 }
5502 }
5503
5504 pub fn declarations(
5505 &mut self,
5506 buffer: &Entity<Buffer>,
5507 position: PointUtf16,
5508 cx: &mut Context<Self>,
5509 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5510 if let Some((upstream_client, project_id)) = self.upstream_client() {
5511 let request = GetDeclarations { position };
5512 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5513 return Task::ready(Ok(None));
5514 }
5515 let request_task = upstream_client.request_lsp(
5516 project_id,
5517 None,
5518 LSP_REQUEST_TIMEOUT,
5519 cx.background_executor().clone(),
5520 request.to_proto(project_id, buffer.read(cx)),
5521 );
5522 let buffer = buffer.clone();
5523 cx.spawn(async move |weak_lsp_store, cx| {
5524 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5525 return Ok(None);
5526 };
5527 let Some(responses) = request_task.await? else {
5528 return Ok(None);
5529 };
5530 let actions = join_all(responses.payload.into_iter().map(|response| {
5531 GetDeclarations { position }.response_from_proto(
5532 response.response,
5533 lsp_store.clone(),
5534 buffer.clone(),
5535 cx.clone(),
5536 )
5537 }))
5538 .await;
5539
5540 Ok(Some(
5541 actions
5542 .into_iter()
5543 .collect::<Result<Vec<Vec<_>>>>()?
5544 .into_iter()
5545 .flatten()
5546 .dedup()
5547 .collect(),
5548 ))
5549 })
5550 } else {
5551 let declarations_task = self.request_multiple_lsp_locally(
5552 buffer,
5553 Some(position),
5554 GetDeclarations { position },
5555 cx,
5556 );
5557 cx.background_spawn(async move {
5558 Ok(Some(
5559 declarations_task
5560 .await
5561 .into_iter()
5562 .flat_map(|(_, declarations)| declarations)
5563 .dedup()
5564 .collect(),
5565 ))
5566 })
5567 }
5568 }
5569
5570 pub fn type_definitions(
5571 &mut self,
5572 buffer: &Entity<Buffer>,
5573 position: PointUtf16,
5574 cx: &mut Context<Self>,
5575 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5576 if let Some((upstream_client, project_id)) = self.upstream_client() {
5577 let request = GetTypeDefinitions { position };
5578 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5579 return Task::ready(Ok(None));
5580 }
5581 let request_task = upstream_client.request_lsp(
5582 project_id,
5583 None,
5584 LSP_REQUEST_TIMEOUT,
5585 cx.background_executor().clone(),
5586 request.to_proto(project_id, buffer.read(cx)),
5587 );
5588 let buffer = buffer.clone();
5589 cx.spawn(async move |weak_lsp_store, cx| {
5590 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5591 return Ok(None);
5592 };
5593 let Some(responses) = request_task.await? else {
5594 return Ok(None);
5595 };
5596 let actions = join_all(responses.payload.into_iter().map(|response| {
5597 GetTypeDefinitions { position }.response_from_proto(
5598 response.response,
5599 lsp_store.clone(),
5600 buffer.clone(),
5601 cx.clone(),
5602 )
5603 }))
5604 .await;
5605
5606 Ok(Some(
5607 actions
5608 .into_iter()
5609 .collect::<Result<Vec<Vec<_>>>>()?
5610 .into_iter()
5611 .flatten()
5612 .dedup()
5613 .collect(),
5614 ))
5615 })
5616 } else {
5617 let type_definitions_task = self.request_multiple_lsp_locally(
5618 buffer,
5619 Some(position),
5620 GetTypeDefinitions { position },
5621 cx,
5622 );
5623 cx.background_spawn(async move {
5624 Ok(Some(
5625 type_definitions_task
5626 .await
5627 .into_iter()
5628 .flat_map(|(_, type_definitions)| type_definitions)
5629 .dedup()
5630 .collect(),
5631 ))
5632 })
5633 }
5634 }
5635
5636 pub fn implementations(
5637 &mut self,
5638 buffer: &Entity<Buffer>,
5639 position: PointUtf16,
5640 cx: &mut Context<Self>,
5641 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5642 if let Some((upstream_client, project_id)) = self.upstream_client() {
5643 let request = GetImplementations { position };
5644 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5645 return Task::ready(Ok(None));
5646 }
5647 let request_task = upstream_client.request_lsp(
5648 project_id,
5649 None,
5650 LSP_REQUEST_TIMEOUT,
5651 cx.background_executor().clone(),
5652 request.to_proto(project_id, buffer.read(cx)),
5653 );
5654 let buffer = buffer.clone();
5655 cx.spawn(async move |weak_lsp_store, cx| {
5656 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5657 return Ok(None);
5658 };
5659 let Some(responses) = request_task.await? else {
5660 return Ok(None);
5661 };
5662 let actions = join_all(responses.payload.into_iter().map(|response| {
5663 GetImplementations { position }.response_from_proto(
5664 response.response,
5665 lsp_store.clone(),
5666 buffer.clone(),
5667 cx.clone(),
5668 )
5669 }))
5670 .await;
5671
5672 Ok(Some(
5673 actions
5674 .into_iter()
5675 .collect::<Result<Vec<Vec<_>>>>()?
5676 .into_iter()
5677 .flatten()
5678 .dedup()
5679 .collect(),
5680 ))
5681 })
5682 } else {
5683 let implementations_task = self.request_multiple_lsp_locally(
5684 buffer,
5685 Some(position),
5686 GetImplementations { position },
5687 cx,
5688 );
5689 cx.background_spawn(async move {
5690 Ok(Some(
5691 implementations_task
5692 .await
5693 .into_iter()
5694 .flat_map(|(_, implementations)| implementations)
5695 .dedup()
5696 .collect(),
5697 ))
5698 })
5699 }
5700 }
5701
5702 pub fn references(
5703 &mut self,
5704 buffer: &Entity<Buffer>,
5705 position: PointUtf16,
5706 cx: &mut Context<Self>,
5707 ) -> Task<Result<Option<Vec<Location>>>> {
5708 if let Some((upstream_client, project_id)) = self.upstream_client() {
5709 let request = GetReferences { position };
5710 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5711 return Task::ready(Ok(None));
5712 }
5713
5714 let request_task = upstream_client.request_lsp(
5715 project_id,
5716 None,
5717 LSP_REQUEST_TIMEOUT,
5718 cx.background_executor().clone(),
5719 request.to_proto(project_id, buffer.read(cx)),
5720 );
5721 let buffer = buffer.clone();
5722 cx.spawn(async move |weak_lsp_store, cx| {
5723 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5724 return Ok(None);
5725 };
5726 let Some(responses) = request_task.await? else {
5727 return Ok(None);
5728 };
5729
5730 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5731 GetReferences { position }.response_from_proto(
5732 lsp_response.response,
5733 lsp_store.clone(),
5734 buffer.clone(),
5735 cx.clone(),
5736 )
5737 }))
5738 .await
5739 .into_iter()
5740 .collect::<Result<Vec<Vec<_>>>>()?
5741 .into_iter()
5742 .flatten()
5743 .dedup()
5744 .collect();
5745 Ok(Some(locations))
5746 })
5747 } else {
5748 let references_task = self.request_multiple_lsp_locally(
5749 buffer,
5750 Some(position),
5751 GetReferences { position },
5752 cx,
5753 );
5754 cx.background_spawn(async move {
5755 Ok(Some(
5756 references_task
5757 .await
5758 .into_iter()
5759 .flat_map(|(_, references)| references)
5760 .dedup()
5761 .collect(),
5762 ))
5763 })
5764 }
5765 }
5766
5767 pub fn code_actions(
5768 &mut self,
5769 buffer: &Entity<Buffer>,
5770 range: Range<Anchor>,
5771 kinds: Option<Vec<CodeActionKind>>,
5772 cx: &mut Context<Self>,
5773 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5774 if let Some((upstream_client, project_id)) = self.upstream_client() {
5775 let request = GetCodeActions {
5776 range: range.clone(),
5777 kinds: kinds.clone(),
5778 };
5779 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5780 return Task::ready(Ok(None));
5781 }
5782 let request_task = upstream_client.request_lsp(
5783 project_id,
5784 None,
5785 LSP_REQUEST_TIMEOUT,
5786 cx.background_executor().clone(),
5787 request.to_proto(project_id, buffer.read(cx)),
5788 );
5789 let buffer = buffer.clone();
5790 cx.spawn(async move |weak_lsp_store, cx| {
5791 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5792 return Ok(None);
5793 };
5794 let Some(responses) = request_task.await? else {
5795 return Ok(None);
5796 };
5797 let actions = join_all(responses.payload.into_iter().map(|response| {
5798 GetCodeActions {
5799 range: range.clone(),
5800 kinds: kinds.clone(),
5801 }
5802 .response_from_proto(
5803 response.response,
5804 lsp_store.clone(),
5805 buffer.clone(),
5806 cx.clone(),
5807 )
5808 }))
5809 .await;
5810
5811 Ok(Some(
5812 actions
5813 .into_iter()
5814 .collect::<Result<Vec<Vec<_>>>>()?
5815 .into_iter()
5816 .flatten()
5817 .collect(),
5818 ))
5819 })
5820 } else {
5821 let all_actions_task = self.request_multiple_lsp_locally(
5822 buffer,
5823 Some(range.start),
5824 GetCodeActions { range, kinds },
5825 cx,
5826 );
5827 cx.background_spawn(async move {
5828 Ok(Some(
5829 all_actions_task
5830 .await
5831 .into_iter()
5832 .flat_map(|(_, actions)| actions)
5833 .collect(),
5834 ))
5835 })
5836 }
5837 }
5838
5839 pub fn code_lens_actions(
5840 &mut self,
5841 buffer: &Entity<Buffer>,
5842 cx: &mut Context<Self>,
5843 ) -> CodeLensTask {
5844 let version_queried_for = buffer.read(cx).version();
5845 let buffer_id = buffer.read(cx).remote_id();
5846 let existing_servers = self.as_local().map(|local| {
5847 local
5848 .buffers_opened_in_servers
5849 .get(&buffer_id)
5850 .cloned()
5851 .unwrap_or_default()
5852 });
5853
5854 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5855 if let Some(cached_lens) = &lsp_data.code_lens {
5856 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5857 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5858 existing_servers != cached_lens.lens.keys().copied().collect()
5859 });
5860 if !has_different_servers {
5861 return Task::ready(Ok(Some(
5862 cached_lens.lens.values().flatten().cloned().collect(),
5863 )))
5864 .shared();
5865 }
5866 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5867 if !version_queried_for.changed_since(updating_for) {
5868 return running_update.clone();
5869 }
5870 }
5871 }
5872 }
5873
5874 let lens_lsp_data = self
5875 .latest_lsp_data(buffer, cx)
5876 .code_lens
5877 .get_or_insert_default();
5878 let buffer = buffer.clone();
5879 let query_version_queried_for = version_queried_for.clone();
5880 let new_task = cx
5881 .spawn(async move |lsp_store, cx| {
5882 cx.background_executor()
5883 .timer(Duration::from_millis(30))
5884 .await;
5885 let fetched_lens = lsp_store
5886 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5887 .map_err(Arc::new)?
5888 .await
5889 .context("fetching code lens")
5890 .map_err(Arc::new);
5891 let fetched_lens = match fetched_lens {
5892 Ok(fetched_lens) => fetched_lens,
5893 Err(e) => {
5894 lsp_store
5895 .update(cx, |lsp_store, _| {
5896 if let Some(lens_lsp_data) = lsp_store
5897 .lsp_data
5898 .get_mut(&buffer_id)
5899 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5900 {
5901 lens_lsp_data.update = None;
5902 }
5903 })
5904 .ok();
5905 return Err(e);
5906 }
5907 };
5908
5909 lsp_store
5910 .update(cx, |lsp_store, _| {
5911 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5912 let code_lens = lsp_data.code_lens.as_mut()?;
5913 if let Some(fetched_lens) = fetched_lens {
5914 if lsp_data.buffer_version == query_version_queried_for {
5915 code_lens.lens.extend(fetched_lens);
5916 } else if !lsp_data
5917 .buffer_version
5918 .changed_since(&query_version_queried_for)
5919 {
5920 lsp_data.buffer_version = query_version_queried_for;
5921 code_lens.lens = fetched_lens;
5922 }
5923 }
5924 code_lens.update = None;
5925 Some(code_lens.lens.values().flatten().cloned().collect())
5926 })
5927 .map_err(Arc::new)
5928 })
5929 .shared();
5930 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5931 new_task
5932 }
5933
5934 fn fetch_code_lens(
5935 &mut self,
5936 buffer: &Entity<Buffer>,
5937 cx: &mut Context<Self>,
5938 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5939 if let Some((upstream_client, project_id)) = self.upstream_client() {
5940 let request = GetCodeLens;
5941 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5942 return Task::ready(Ok(None));
5943 }
5944 let request_task = upstream_client.request_lsp(
5945 project_id,
5946 None,
5947 LSP_REQUEST_TIMEOUT,
5948 cx.background_executor().clone(),
5949 request.to_proto(project_id, buffer.read(cx)),
5950 );
5951 let buffer = buffer.clone();
5952 cx.spawn(async move |weak_lsp_store, cx| {
5953 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5954 return Ok(None);
5955 };
5956 let Some(responses) = request_task.await? else {
5957 return Ok(None);
5958 };
5959
5960 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5961 let lsp_store = lsp_store.clone();
5962 let buffer = buffer.clone();
5963 let cx = cx.clone();
5964 async move {
5965 (
5966 LanguageServerId::from_proto(response.server_id),
5967 GetCodeLens
5968 .response_from_proto(response.response, lsp_store, buffer, cx)
5969 .await,
5970 )
5971 }
5972 }))
5973 .await;
5974
5975 let mut has_errors = false;
5976 let code_lens_actions = code_lens_actions
5977 .into_iter()
5978 .filter_map(|(server_id, code_lens)| match code_lens {
5979 Ok(code_lens) => Some((server_id, code_lens)),
5980 Err(e) => {
5981 has_errors = true;
5982 log::error!("{e:#}");
5983 None
5984 }
5985 })
5986 .collect::<HashMap<_, _>>();
5987 anyhow::ensure!(
5988 !has_errors || !code_lens_actions.is_empty(),
5989 "Failed to fetch code lens"
5990 );
5991 Ok(Some(code_lens_actions))
5992 })
5993 } else {
5994 let code_lens_actions_task =
5995 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5996 cx.background_spawn(async move {
5997 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5998 })
5999 }
6000 }
6001
6002 #[inline(never)]
6003 pub fn completions(
6004 &self,
6005 buffer: &Entity<Buffer>,
6006 position: PointUtf16,
6007 context: CompletionContext,
6008 cx: &mut Context<Self>,
6009 ) -> Task<Result<Vec<CompletionResponse>>> {
6010 let language_registry = self.languages.clone();
6011
6012 if let Some((upstream_client, project_id)) = self.upstream_client() {
6013 let snapshot = buffer.read(cx).snapshot();
6014 let offset = position.to_offset(&snapshot);
6015 let scope = snapshot.language_scope_at(offset);
6016 let capable_lsps = self.all_capable_for_proto_request(
6017 buffer,
6018 |server_name, capabilities| {
6019 capabilities.completion_provider.is_some()
6020 && scope
6021 .as_ref()
6022 .map(|scope| scope.language_allowed(server_name))
6023 .unwrap_or(true)
6024 },
6025 cx,
6026 );
6027 if capable_lsps.is_empty() {
6028 return Task::ready(Ok(Vec::new()));
6029 }
6030
6031 let language = buffer.read(cx).language().cloned();
6032
6033 // In the future, we should provide project guests with the names of LSP adapters,
6034 // so that they can use the correct LSP adapter when computing labels. For now,
6035 // guests just use the first LSP adapter associated with the buffer's language.
6036 let lsp_adapter = language.as_ref().and_then(|language| {
6037 language_registry
6038 .lsp_adapters(&language.name())
6039 .first()
6040 .cloned()
6041 });
6042
6043 let buffer = buffer.clone();
6044
6045 cx.spawn(async move |this, cx| {
6046 let requests = join_all(
6047 capable_lsps
6048 .into_iter()
6049 .map(|id| {
6050 let request = GetCompletions {
6051 position,
6052 context: context.clone(),
6053 server_id: Some(id),
6054 };
6055 let buffer = buffer.clone();
6056 let language = language.clone();
6057 let lsp_adapter = lsp_adapter.clone();
6058 let upstream_client = upstream_client.clone();
6059 let response = this
6060 .update(cx, |this, cx| {
6061 this.send_lsp_proto_request(
6062 buffer,
6063 upstream_client,
6064 project_id,
6065 request,
6066 cx,
6067 )
6068 })
6069 .log_err();
6070 async move {
6071 let response = response?.await.log_err()?;
6072
6073 let completions = populate_labels_for_completions(
6074 response.completions,
6075 language,
6076 lsp_adapter,
6077 )
6078 .await;
6079
6080 Some(CompletionResponse {
6081 completions,
6082 display_options: CompletionDisplayOptions::default(),
6083 is_incomplete: response.is_incomplete,
6084 })
6085 }
6086 })
6087 .collect::<Vec<_>>(),
6088 );
6089 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6090 })
6091 } else if let Some(local) = self.as_local() {
6092 let snapshot = buffer.read(cx).snapshot();
6093 let offset = position.to_offset(&snapshot);
6094 let scope = snapshot.language_scope_at(offset);
6095 let language = snapshot.language().cloned();
6096 let completion_settings = language_settings(
6097 language.as_ref().map(|language| language.name()),
6098 buffer.read(cx).file(),
6099 cx,
6100 )
6101 .completions
6102 .clone();
6103 if !completion_settings.lsp {
6104 return Task::ready(Ok(Vec::new()));
6105 }
6106
6107 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6108 local
6109 .language_servers_for_buffer(buffer, cx)
6110 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6111 .filter(|(adapter, _)| {
6112 scope
6113 .as_ref()
6114 .map(|scope| scope.language_allowed(&adapter.name))
6115 .unwrap_or(true)
6116 })
6117 .map(|(_, server)| server.server_id())
6118 .collect()
6119 });
6120
6121 let buffer = buffer.clone();
6122 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6123 let lsp_timeout = if lsp_timeout > 0 {
6124 Some(Duration::from_millis(lsp_timeout))
6125 } else {
6126 None
6127 };
6128 cx.spawn(async move |this, cx| {
6129 let mut tasks = Vec::with_capacity(server_ids.len());
6130 this.update(cx, |lsp_store, cx| {
6131 for server_id in server_ids {
6132 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6133 let lsp_timeout = lsp_timeout
6134 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6135 let mut timeout = cx.background_spawn(async move {
6136 match lsp_timeout {
6137 Some(lsp_timeout) => {
6138 lsp_timeout.await;
6139 true
6140 },
6141 None => false,
6142 }
6143 }).fuse();
6144 let mut lsp_request = lsp_store.request_lsp(
6145 buffer.clone(),
6146 LanguageServerToQuery::Other(server_id),
6147 GetCompletions {
6148 position,
6149 context: context.clone(),
6150 server_id: Some(server_id),
6151 },
6152 cx,
6153 ).fuse();
6154 let new_task = cx.background_spawn(async move {
6155 select_biased! {
6156 response = lsp_request => anyhow::Ok(Some(response?)),
6157 timeout_happened = timeout => {
6158 if timeout_happened {
6159 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6160 Ok(None)
6161 } else {
6162 let completions = lsp_request.await?;
6163 Ok(Some(completions))
6164 }
6165 },
6166 }
6167 });
6168 tasks.push((lsp_adapter, new_task));
6169 }
6170 })?;
6171
6172 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6173 let completion_response = task.await.ok()??;
6174 let completions = populate_labels_for_completions(
6175 completion_response.completions,
6176 language.clone(),
6177 lsp_adapter,
6178 )
6179 .await;
6180 Some(CompletionResponse {
6181 completions,
6182 display_options: CompletionDisplayOptions::default(),
6183 is_incomplete: completion_response.is_incomplete,
6184 })
6185 });
6186
6187 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6188
6189 Ok(responses.into_iter().flatten().collect())
6190 })
6191 } else {
6192 Task::ready(Err(anyhow!("No upstream client or local language server")))
6193 }
6194 }
6195
6196 pub fn resolve_completions(
6197 &self,
6198 buffer: Entity<Buffer>,
6199 completion_indices: Vec<usize>,
6200 completions: Rc<RefCell<Box<[Completion]>>>,
6201 cx: &mut Context<Self>,
6202 ) -> Task<Result<bool>> {
6203 let client = self.upstream_client();
6204 let buffer_id = buffer.read(cx).remote_id();
6205 let buffer_snapshot = buffer.read(cx).snapshot();
6206
6207 if !self.check_if_capable_for_proto_request(
6208 &buffer,
6209 GetCompletions::can_resolve_completions,
6210 cx,
6211 ) {
6212 return Task::ready(Ok(false));
6213 }
6214 cx.spawn(async move |lsp_store, cx| {
6215 let mut did_resolve = false;
6216 if let Some((client, project_id)) = client {
6217 for completion_index in completion_indices {
6218 let server_id = {
6219 let completion = &completions.borrow()[completion_index];
6220 completion.source.server_id()
6221 };
6222 if let Some(server_id) = server_id {
6223 if Self::resolve_completion_remote(
6224 project_id,
6225 server_id,
6226 buffer_id,
6227 completions.clone(),
6228 completion_index,
6229 client.clone(),
6230 )
6231 .await
6232 .log_err()
6233 .is_some()
6234 {
6235 did_resolve = true;
6236 }
6237 } else {
6238 resolve_word_completion(
6239 &buffer_snapshot,
6240 &mut completions.borrow_mut()[completion_index],
6241 );
6242 }
6243 }
6244 } else {
6245 for completion_index in completion_indices {
6246 let server_id = {
6247 let completion = &completions.borrow()[completion_index];
6248 completion.source.server_id()
6249 };
6250 if let Some(server_id) = server_id {
6251 let server_and_adapter = lsp_store
6252 .read_with(cx, |lsp_store, _| {
6253 let server = lsp_store.language_server_for_id(server_id)?;
6254 let adapter =
6255 lsp_store.language_server_adapter_for_id(server.server_id())?;
6256 Some((server, adapter))
6257 })
6258 .ok()
6259 .flatten();
6260 let Some((server, adapter)) = server_and_adapter else {
6261 continue;
6262 };
6263
6264 let resolved = Self::resolve_completion_local(
6265 server,
6266 completions.clone(),
6267 completion_index,
6268 )
6269 .await
6270 .log_err()
6271 .is_some();
6272 if resolved {
6273 Self::regenerate_completion_labels(
6274 adapter,
6275 &buffer_snapshot,
6276 completions.clone(),
6277 completion_index,
6278 )
6279 .await
6280 .log_err();
6281 did_resolve = true;
6282 }
6283 } else {
6284 resolve_word_completion(
6285 &buffer_snapshot,
6286 &mut completions.borrow_mut()[completion_index],
6287 );
6288 }
6289 }
6290 }
6291
6292 Ok(did_resolve)
6293 })
6294 }
6295
6296 async fn resolve_completion_local(
6297 server: Arc<lsp::LanguageServer>,
6298 completions: Rc<RefCell<Box<[Completion]>>>,
6299 completion_index: usize,
6300 ) -> Result<()> {
6301 let server_id = server.server_id();
6302 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6303 return Ok(());
6304 }
6305
6306 let request = {
6307 let completion = &completions.borrow()[completion_index];
6308 match &completion.source {
6309 CompletionSource::Lsp {
6310 lsp_completion,
6311 resolved,
6312 server_id: completion_server_id,
6313 ..
6314 } => {
6315 if *resolved {
6316 return Ok(());
6317 }
6318 anyhow::ensure!(
6319 server_id == *completion_server_id,
6320 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6321 );
6322 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6323 }
6324 CompletionSource::BufferWord { .. }
6325 | CompletionSource::Dap { .. }
6326 | CompletionSource::Custom => {
6327 return Ok(());
6328 }
6329 }
6330 };
6331 let resolved_completion = request
6332 .await
6333 .into_response()
6334 .context("resolve completion")?;
6335
6336 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6337 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6338
6339 let mut completions = completions.borrow_mut();
6340 let completion = &mut completions[completion_index];
6341 if let CompletionSource::Lsp {
6342 lsp_completion,
6343 resolved,
6344 server_id: completion_server_id,
6345 ..
6346 } = &mut completion.source
6347 {
6348 if *resolved {
6349 return Ok(());
6350 }
6351 anyhow::ensure!(
6352 server_id == *completion_server_id,
6353 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6354 );
6355 *lsp_completion = Box::new(resolved_completion);
6356 *resolved = true;
6357 }
6358 Ok(())
6359 }
6360
6361 async fn regenerate_completion_labels(
6362 adapter: Arc<CachedLspAdapter>,
6363 snapshot: &BufferSnapshot,
6364 completions: Rc<RefCell<Box<[Completion]>>>,
6365 completion_index: usize,
6366 ) -> Result<()> {
6367 let completion_item = completions.borrow()[completion_index]
6368 .source
6369 .lsp_completion(true)
6370 .map(Cow::into_owned);
6371 if let Some(lsp_documentation) = completion_item
6372 .as_ref()
6373 .and_then(|completion_item| completion_item.documentation.clone())
6374 {
6375 let mut completions = completions.borrow_mut();
6376 let completion = &mut completions[completion_index];
6377 completion.documentation = Some(lsp_documentation.into());
6378 } else {
6379 let mut completions = completions.borrow_mut();
6380 let completion = &mut completions[completion_index];
6381 completion.documentation = Some(CompletionDocumentation::Undocumented);
6382 }
6383
6384 let mut new_label = match completion_item {
6385 Some(completion_item) => {
6386 // 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
6387 // So we have to update the label here anyway...
6388 let language = snapshot.language();
6389 match language {
6390 Some(language) => {
6391 adapter
6392 .labels_for_completions(
6393 std::slice::from_ref(&completion_item),
6394 language,
6395 )
6396 .await?
6397 }
6398 None => Vec::new(),
6399 }
6400 .pop()
6401 .flatten()
6402 .unwrap_or_else(|| {
6403 CodeLabel::fallback_for_completion(
6404 &completion_item,
6405 language.map(|language| language.as_ref()),
6406 )
6407 })
6408 }
6409 None => CodeLabel::plain(
6410 completions.borrow()[completion_index].new_text.clone(),
6411 None,
6412 ),
6413 };
6414 ensure_uniform_list_compatible_label(&mut new_label);
6415
6416 let mut completions = completions.borrow_mut();
6417 let completion = &mut completions[completion_index];
6418 if completion.label.filter_text() == new_label.filter_text() {
6419 completion.label = new_label;
6420 } else {
6421 log::error!(
6422 "Resolved completion changed display label from {} to {}. \
6423 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6424 completion.label.text(),
6425 new_label.text(),
6426 completion.label.filter_text(),
6427 new_label.filter_text()
6428 );
6429 }
6430
6431 Ok(())
6432 }
6433
6434 async fn resolve_completion_remote(
6435 project_id: u64,
6436 server_id: LanguageServerId,
6437 buffer_id: BufferId,
6438 completions: Rc<RefCell<Box<[Completion]>>>,
6439 completion_index: usize,
6440 client: AnyProtoClient,
6441 ) -> Result<()> {
6442 let lsp_completion = {
6443 let completion = &completions.borrow()[completion_index];
6444 match &completion.source {
6445 CompletionSource::Lsp {
6446 lsp_completion,
6447 resolved,
6448 server_id: completion_server_id,
6449 ..
6450 } => {
6451 anyhow::ensure!(
6452 server_id == *completion_server_id,
6453 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6454 );
6455 if *resolved {
6456 return Ok(());
6457 }
6458 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6459 }
6460 CompletionSource::Custom
6461 | CompletionSource::Dap { .. }
6462 | CompletionSource::BufferWord { .. } => {
6463 return Ok(());
6464 }
6465 }
6466 };
6467 let request = proto::ResolveCompletionDocumentation {
6468 project_id,
6469 language_server_id: server_id.0 as u64,
6470 lsp_completion,
6471 buffer_id: buffer_id.into(),
6472 };
6473
6474 let response = client
6475 .request(request)
6476 .await
6477 .context("completion documentation resolve proto request")?;
6478 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6479
6480 let documentation = if response.documentation.is_empty() {
6481 CompletionDocumentation::Undocumented
6482 } else if response.documentation_is_markdown {
6483 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6484 } else if response.documentation.lines().count() <= 1 {
6485 CompletionDocumentation::SingleLine(response.documentation.into())
6486 } else {
6487 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6488 };
6489
6490 let mut completions = completions.borrow_mut();
6491 let completion = &mut completions[completion_index];
6492 completion.documentation = Some(documentation);
6493 if let CompletionSource::Lsp {
6494 insert_range,
6495 lsp_completion,
6496 resolved,
6497 server_id: completion_server_id,
6498 lsp_defaults: _,
6499 } = &mut completion.source
6500 {
6501 let completion_insert_range = response
6502 .old_insert_start
6503 .and_then(deserialize_anchor)
6504 .zip(response.old_insert_end.and_then(deserialize_anchor));
6505 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6506
6507 if *resolved {
6508 return Ok(());
6509 }
6510 anyhow::ensure!(
6511 server_id == *completion_server_id,
6512 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6513 );
6514 *lsp_completion = Box::new(resolved_lsp_completion);
6515 *resolved = true;
6516 }
6517
6518 let replace_range = response
6519 .old_replace_start
6520 .and_then(deserialize_anchor)
6521 .zip(response.old_replace_end.and_then(deserialize_anchor));
6522 if let Some((old_replace_start, old_replace_end)) = replace_range
6523 && !response.new_text.is_empty()
6524 {
6525 completion.new_text = response.new_text;
6526 completion.replace_range = old_replace_start..old_replace_end;
6527 }
6528
6529 Ok(())
6530 }
6531
6532 pub fn apply_additional_edits_for_completion(
6533 &self,
6534 buffer_handle: Entity<Buffer>,
6535 completions: Rc<RefCell<Box<[Completion]>>>,
6536 completion_index: usize,
6537 push_to_history: bool,
6538 cx: &mut Context<Self>,
6539 ) -> Task<Result<Option<Transaction>>> {
6540 if let Some((client, project_id)) = self.upstream_client() {
6541 let buffer = buffer_handle.read(cx);
6542 let buffer_id = buffer.remote_id();
6543 cx.spawn(async move |_, cx| {
6544 let request = {
6545 let completion = completions.borrow()[completion_index].clone();
6546 proto::ApplyCompletionAdditionalEdits {
6547 project_id,
6548 buffer_id: buffer_id.into(),
6549 completion: Some(Self::serialize_completion(&CoreCompletion {
6550 replace_range: completion.replace_range,
6551 new_text: completion.new_text,
6552 source: completion.source,
6553 })),
6554 }
6555 };
6556
6557 if let Some(transaction) = client.request(request).await?.transaction {
6558 let transaction = language::proto::deserialize_transaction(transaction)?;
6559 buffer_handle
6560 .update(cx, |buffer, _| {
6561 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6562 })?
6563 .await?;
6564 if push_to_history {
6565 buffer_handle.update(cx, |buffer, _| {
6566 buffer.push_transaction(transaction.clone(), Instant::now());
6567 buffer.finalize_last_transaction();
6568 })?;
6569 }
6570 Ok(Some(transaction))
6571 } else {
6572 Ok(None)
6573 }
6574 })
6575 } else {
6576 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6577 let completion = &completions.borrow()[completion_index];
6578 let server_id = completion.source.server_id()?;
6579 Some(
6580 self.language_server_for_local_buffer(buffer, server_id, cx)?
6581 .1
6582 .clone(),
6583 )
6584 }) else {
6585 return Task::ready(Ok(None));
6586 };
6587
6588 cx.spawn(async move |this, cx| {
6589 Self::resolve_completion_local(
6590 server.clone(),
6591 completions.clone(),
6592 completion_index,
6593 )
6594 .await
6595 .context("resolving completion")?;
6596 let completion = completions.borrow()[completion_index].clone();
6597 let additional_text_edits = completion
6598 .source
6599 .lsp_completion(true)
6600 .as_ref()
6601 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6602 if let Some(edits) = additional_text_edits {
6603 let edits = this
6604 .update(cx, |this, cx| {
6605 this.as_local_mut().unwrap().edits_from_lsp(
6606 &buffer_handle,
6607 edits,
6608 server.server_id(),
6609 None,
6610 cx,
6611 )
6612 })?
6613 .await?;
6614
6615 buffer_handle.update(cx, |buffer, cx| {
6616 buffer.finalize_last_transaction();
6617 buffer.start_transaction();
6618
6619 for (range, text) in edits {
6620 let primary = &completion.replace_range;
6621
6622 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6623 // and the primary completion is just an insertion (empty range), then this is likely
6624 // an auto-import scenario and should not be considered overlapping
6625 // https://github.com/zed-industries/zed/issues/26136
6626 let is_file_start_auto_import = {
6627 let snapshot = buffer.snapshot();
6628 let primary_start_point = primary.start.to_point(&snapshot);
6629 let range_start_point = range.start.to_point(&snapshot);
6630
6631 let result = primary_start_point.row == 0
6632 && primary_start_point.column == 0
6633 && range_start_point.row == 0
6634 && range_start_point.column == 0;
6635
6636 result
6637 };
6638
6639 let has_overlap = if is_file_start_auto_import {
6640 false
6641 } else {
6642 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6643 && primary.end.cmp(&range.start, buffer).is_ge();
6644 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6645 && range.end.cmp(&primary.end, buffer).is_ge();
6646 let result = start_within || end_within;
6647 result
6648 };
6649
6650 //Skip additional edits which overlap with the primary completion edit
6651 //https://github.com/zed-industries/zed/pull/1871
6652 if !has_overlap {
6653 buffer.edit([(range, text)], None, cx);
6654 }
6655 }
6656
6657 let transaction = if buffer.end_transaction(cx).is_some() {
6658 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6659 if !push_to_history {
6660 buffer.forget_transaction(transaction.id);
6661 }
6662 Some(transaction)
6663 } else {
6664 None
6665 };
6666 Ok(transaction)
6667 })?
6668 } else {
6669 Ok(None)
6670 }
6671 })
6672 }
6673 }
6674
6675 pub fn pull_diagnostics(
6676 &mut self,
6677 buffer: Entity<Buffer>,
6678 cx: &mut Context<Self>,
6679 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6680 let buffer_id = buffer.read(cx).remote_id();
6681
6682 if let Some((client, upstream_project_id)) = self.upstream_client() {
6683 let mut suitable_capabilities = None;
6684 // Are we capable for proto request?
6685 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6686 &buffer,
6687 |capabilities| {
6688 if let Some(caps) = &capabilities.diagnostic_provider {
6689 suitable_capabilities = Some(caps.clone());
6690 true
6691 } else {
6692 false
6693 }
6694 },
6695 cx,
6696 );
6697 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6698 let Some(dynamic_caps) = suitable_capabilities else {
6699 return Task::ready(Ok(None));
6700 };
6701 assert!(any_server_has_diagnostics_provider);
6702
6703 let request = GetDocumentDiagnostics {
6704 previous_result_id: None,
6705 dynamic_caps,
6706 };
6707 let request_task = client.request_lsp(
6708 upstream_project_id,
6709 None,
6710 LSP_REQUEST_TIMEOUT,
6711 cx.background_executor().clone(),
6712 request.to_proto(upstream_project_id, buffer.read(cx)),
6713 );
6714 cx.background_spawn(async move {
6715 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6716 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6717 // Do not attempt to further process the dummy responses here.
6718 let _response = request_task.await?;
6719 Ok(None)
6720 })
6721 } else {
6722 let servers = buffer.update(cx, |buffer, cx| {
6723 self.language_servers_for_local_buffer(buffer, cx)
6724 .map(|(_, server)| server.clone())
6725 .collect::<Vec<_>>()
6726 });
6727
6728 let pull_diagnostics = servers
6729 .into_iter()
6730 .flat_map(|server| {
6731 let result = maybe!({
6732 let local = self.as_local()?;
6733 let server_id = server.server_id();
6734 let providers_with_identifiers = local
6735 .language_server_dynamic_registrations
6736 .get(&server_id)
6737 .into_iter()
6738 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6739 .collect::<Vec<_>>();
6740 Some(
6741 providers_with_identifiers
6742 .into_iter()
6743 .map(|dynamic_caps| {
6744 let result_id = self.result_id(server_id, buffer_id, cx);
6745 self.request_lsp(
6746 buffer.clone(),
6747 LanguageServerToQuery::Other(server_id),
6748 GetDocumentDiagnostics {
6749 previous_result_id: result_id,
6750 dynamic_caps,
6751 },
6752 cx,
6753 )
6754 })
6755 .collect::<Vec<_>>(),
6756 )
6757 });
6758
6759 result.unwrap_or_default()
6760 })
6761 .collect::<Vec<_>>();
6762
6763 cx.background_spawn(async move {
6764 let mut responses = Vec::new();
6765 for diagnostics in join_all(pull_diagnostics).await {
6766 responses.extend(diagnostics?);
6767 }
6768 Ok(Some(responses))
6769 })
6770 }
6771 }
6772
6773 pub fn applicable_inlay_chunks(
6774 &mut self,
6775 buffer: &Entity<Buffer>,
6776 ranges: &[Range<text::Anchor>],
6777 cx: &mut Context<Self>,
6778 ) -> Vec<Range<BufferRow>> {
6779 self.latest_lsp_data(buffer, cx)
6780 .inlay_hints
6781 .applicable_chunks(ranges)
6782 .map(|chunk| chunk.row_range())
6783 .collect()
6784 }
6785
6786 pub fn invalidate_inlay_hints<'a>(
6787 &'a mut self,
6788 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6789 ) {
6790 for buffer_id in for_buffers {
6791 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6792 lsp_data.inlay_hints.clear();
6793 }
6794 }
6795 }
6796
6797 pub fn inlay_hints(
6798 &mut self,
6799 invalidate: InvalidationStrategy,
6800 buffer: Entity<Buffer>,
6801 ranges: Vec<Range<text::Anchor>>,
6802 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6803 cx: &mut Context<Self>,
6804 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6805 let next_hint_id = self.next_hint_id.clone();
6806 let lsp_data = self.latest_lsp_data(&buffer, cx);
6807 let query_version = lsp_data.buffer_version.clone();
6808 let mut lsp_refresh_requested = false;
6809 let for_server = if let InvalidationStrategy::RefreshRequested {
6810 server_id,
6811 request_id,
6812 } = invalidate
6813 {
6814 let invalidated = lsp_data
6815 .inlay_hints
6816 .invalidate_for_server_refresh(server_id, request_id);
6817 lsp_refresh_requested = invalidated;
6818 Some(server_id)
6819 } else {
6820 None
6821 };
6822 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6823 let known_chunks = known_chunks
6824 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6825 .map(|(_, known_chunks)| known_chunks)
6826 .unwrap_or_default();
6827
6828 let mut hint_fetch_tasks = Vec::new();
6829 let mut cached_inlay_hints = None;
6830 let mut ranges_to_query = None;
6831 let applicable_chunks = existing_inlay_hints
6832 .applicable_chunks(ranges.as_slice())
6833 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6834 .collect::<Vec<_>>();
6835 if applicable_chunks.is_empty() {
6836 return HashMap::default();
6837 }
6838
6839 for row_chunk in applicable_chunks {
6840 match (
6841 existing_inlay_hints
6842 .cached_hints(&row_chunk)
6843 .filter(|_| !lsp_refresh_requested)
6844 .cloned(),
6845 existing_inlay_hints
6846 .fetched_hints(&row_chunk)
6847 .as_ref()
6848 .filter(|_| !lsp_refresh_requested)
6849 .cloned(),
6850 ) {
6851 (None, None) => {
6852 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6853 continue;
6854 };
6855 ranges_to_query
6856 .get_or_insert_with(Vec::new)
6857 .push((row_chunk, chunk_range));
6858 }
6859 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6860 (Some(cached_hints), None) => {
6861 for (server_id, cached_hints) in cached_hints {
6862 if for_server.is_none_or(|for_server| for_server == server_id) {
6863 cached_inlay_hints
6864 .get_or_insert_with(HashMap::default)
6865 .entry(row_chunk.row_range())
6866 .or_insert_with(HashMap::default)
6867 .entry(server_id)
6868 .or_insert_with(Vec::new)
6869 .extend(cached_hints);
6870 }
6871 }
6872 }
6873 (Some(cached_hints), Some(fetched_hints)) => {
6874 hint_fetch_tasks.push((row_chunk, fetched_hints));
6875 for (server_id, cached_hints) in cached_hints {
6876 if for_server.is_none_or(|for_server| for_server == server_id) {
6877 cached_inlay_hints
6878 .get_or_insert_with(HashMap::default)
6879 .entry(row_chunk.row_range())
6880 .or_insert_with(HashMap::default)
6881 .entry(server_id)
6882 .or_insert_with(Vec::new)
6883 .extend(cached_hints);
6884 }
6885 }
6886 }
6887 }
6888 }
6889
6890 if hint_fetch_tasks.is_empty()
6891 && ranges_to_query
6892 .as_ref()
6893 .is_none_or(|ranges| ranges.is_empty())
6894 && let Some(cached_inlay_hints) = cached_inlay_hints
6895 {
6896 cached_inlay_hints
6897 .into_iter()
6898 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6899 .collect()
6900 } else {
6901 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6902 let next_hint_id = next_hint_id.clone();
6903 let buffer = buffer.clone();
6904 let query_version = query_version.clone();
6905 let new_inlay_hints = cx
6906 .spawn(async move |lsp_store, cx| {
6907 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6908 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6909 })?;
6910 new_fetch_task
6911 .await
6912 .and_then(|new_hints_by_server| {
6913 lsp_store.update(cx, |lsp_store, cx| {
6914 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6915 let update_cache = lsp_data.buffer_version == query_version;
6916 if new_hints_by_server.is_empty() {
6917 if update_cache {
6918 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6919 }
6920 HashMap::default()
6921 } else {
6922 new_hints_by_server
6923 .into_iter()
6924 .map(|(server_id, new_hints)| {
6925 let new_hints = new_hints
6926 .into_iter()
6927 .map(|new_hint| {
6928 (
6929 InlayId::Hint(next_hint_id.fetch_add(
6930 1,
6931 atomic::Ordering::AcqRel,
6932 )),
6933 new_hint,
6934 )
6935 })
6936 .collect::<Vec<_>>();
6937 if update_cache {
6938 lsp_data.inlay_hints.insert_new_hints(
6939 chunk,
6940 server_id,
6941 new_hints.clone(),
6942 );
6943 }
6944 (server_id, new_hints)
6945 })
6946 .collect()
6947 }
6948 })
6949 })
6950 .map_err(Arc::new)
6951 })
6952 .shared();
6953
6954 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6955 *fetch_task = Some(new_inlay_hints.clone());
6956 hint_fetch_tasks.push((chunk, new_inlay_hints));
6957 }
6958
6959 cached_inlay_hints
6960 .unwrap_or_default()
6961 .into_iter()
6962 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6963 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6964 (
6965 chunk.row_range(),
6966 cx.spawn(async move |_, _| {
6967 hints_fetch.await.map_err(|e| {
6968 if e.error_code() != ErrorCode::Internal {
6969 anyhow!(e.error_code())
6970 } else {
6971 anyhow!("{e:#}")
6972 }
6973 })
6974 }),
6975 )
6976 }))
6977 .collect()
6978 }
6979 }
6980
6981 fn fetch_inlay_hints(
6982 &mut self,
6983 for_server: Option<LanguageServerId>,
6984 buffer: &Entity<Buffer>,
6985 range: Range<Anchor>,
6986 cx: &mut Context<Self>,
6987 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6988 let request = InlayHints {
6989 range: range.clone(),
6990 };
6991 if let Some((upstream_client, project_id)) = self.upstream_client() {
6992 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6993 return Task::ready(Ok(HashMap::default()));
6994 }
6995 let request_task = upstream_client.request_lsp(
6996 project_id,
6997 for_server.map(|id| id.to_proto()),
6998 LSP_REQUEST_TIMEOUT,
6999 cx.background_executor().clone(),
7000 request.to_proto(project_id, buffer.read(cx)),
7001 );
7002 let buffer = buffer.clone();
7003 cx.spawn(async move |weak_lsp_store, cx| {
7004 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7005 return Ok(HashMap::default());
7006 };
7007 let Some(responses) = request_task.await? else {
7008 return Ok(HashMap::default());
7009 };
7010
7011 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7012 let lsp_store = lsp_store.clone();
7013 let buffer = buffer.clone();
7014 let cx = cx.clone();
7015 let request = request.clone();
7016 async move {
7017 (
7018 LanguageServerId::from_proto(response.server_id),
7019 request
7020 .response_from_proto(response.response, lsp_store, buffer, cx)
7021 .await,
7022 )
7023 }
7024 }))
7025 .await;
7026
7027 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7028 let mut has_errors = false;
7029 let inlay_hints = inlay_hints
7030 .into_iter()
7031 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7032 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7033 Err(e) => {
7034 has_errors = true;
7035 log::error!("{e:#}");
7036 None
7037 }
7038 })
7039 .map(|(server_id, mut new_hints)| {
7040 new_hints.retain(|hint| {
7041 hint.position.is_valid(&buffer_snapshot)
7042 && range.start.is_valid(&buffer_snapshot)
7043 && range.end.is_valid(&buffer_snapshot)
7044 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7045 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7046 });
7047 (server_id, new_hints)
7048 })
7049 .collect::<HashMap<_, _>>();
7050 anyhow::ensure!(
7051 !has_errors || !inlay_hints.is_empty(),
7052 "Failed to fetch inlay hints"
7053 );
7054 Ok(inlay_hints)
7055 })
7056 } else {
7057 let inlay_hints_task = match for_server {
7058 Some(server_id) => {
7059 let server_task = self.request_lsp(
7060 buffer.clone(),
7061 LanguageServerToQuery::Other(server_id),
7062 request,
7063 cx,
7064 );
7065 cx.background_spawn(async move {
7066 let mut responses = Vec::new();
7067 match server_task.await {
7068 Ok(response) => responses.push((server_id, response)),
7069 // rust-analyzer likes to error with this when its still loading up
7070 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7071 Err(e) => log::error!(
7072 "Error handling response for inlay hints request: {e:#}"
7073 ),
7074 }
7075 responses
7076 })
7077 }
7078 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7079 };
7080 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7081 cx.background_spawn(async move {
7082 Ok(inlay_hints_task
7083 .await
7084 .into_iter()
7085 .map(|(server_id, mut new_hints)| {
7086 new_hints.retain(|hint| {
7087 hint.position.is_valid(&buffer_snapshot)
7088 && range.start.is_valid(&buffer_snapshot)
7089 && range.end.is_valid(&buffer_snapshot)
7090 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7091 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7092 });
7093 (server_id, new_hints)
7094 })
7095 .collect())
7096 })
7097 }
7098 }
7099
7100 pub fn pull_diagnostics_for_buffer(
7101 &mut self,
7102 buffer: Entity<Buffer>,
7103 cx: &mut Context<Self>,
7104 ) -> Task<anyhow::Result<()>> {
7105 let diagnostics = self.pull_diagnostics(buffer, cx);
7106 cx.spawn(async move |lsp_store, cx| {
7107 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7108 return Ok(());
7109 };
7110 lsp_store.update(cx, |lsp_store, cx| {
7111 if lsp_store.as_local().is_none() {
7112 return;
7113 }
7114
7115 let mut unchanged_buffers = HashSet::default();
7116 let mut changed_buffers = HashSet::default();
7117 let server_diagnostics_updates = diagnostics
7118 .into_iter()
7119 .filter_map(|diagnostics_set| match diagnostics_set {
7120 LspPullDiagnostics::Response {
7121 server_id,
7122 uri,
7123 diagnostics,
7124 } => Some((server_id, uri, diagnostics)),
7125 LspPullDiagnostics::Default => None,
7126 })
7127 .fold(
7128 HashMap::default(),
7129 |mut acc, (server_id, uri, diagnostics)| {
7130 let (result_id, diagnostics) = match diagnostics {
7131 PulledDiagnostics::Unchanged { result_id } => {
7132 unchanged_buffers.insert(uri.clone());
7133 (Some(result_id), Vec::new())
7134 }
7135 PulledDiagnostics::Changed {
7136 result_id,
7137 diagnostics,
7138 } => {
7139 changed_buffers.insert(uri.clone());
7140 (result_id, diagnostics)
7141 }
7142 };
7143 let disk_based_sources = Cow::Owned(
7144 lsp_store
7145 .language_server_adapter_for_id(server_id)
7146 .as_ref()
7147 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7148 .unwrap_or(&[])
7149 .to_vec(),
7150 );
7151 acc.entry(server_id).or_insert_with(Vec::new).push(
7152 DocumentDiagnosticsUpdate {
7153 server_id,
7154 diagnostics: lsp::PublishDiagnosticsParams {
7155 uri,
7156 diagnostics,
7157 version: None,
7158 },
7159 result_id,
7160 disk_based_sources,
7161 },
7162 );
7163 acc
7164 },
7165 );
7166
7167 for diagnostic_updates in server_diagnostics_updates.into_values() {
7168 lsp_store
7169 .merge_lsp_diagnostics(
7170 DiagnosticSourceKind::Pulled,
7171 diagnostic_updates,
7172 |buffer, old_diagnostic, cx| {
7173 File::from_dyn(buffer.file())
7174 .and_then(|file| {
7175 let abs_path = file.as_local()?.abs_path(cx);
7176 lsp::Uri::from_file_path(abs_path).ok()
7177 })
7178 .is_none_or(|buffer_uri| {
7179 unchanged_buffers.contains(&buffer_uri)
7180 || match old_diagnostic.source_kind {
7181 DiagnosticSourceKind::Pulled => {
7182 !changed_buffers.contains(&buffer_uri)
7183 }
7184 DiagnosticSourceKind::Other
7185 | DiagnosticSourceKind::Pushed => true,
7186 }
7187 })
7188 },
7189 cx,
7190 )
7191 .log_err();
7192 }
7193 })
7194 })
7195 }
7196
7197 pub fn document_colors(
7198 &mut self,
7199 known_cache_version: Option<usize>,
7200 buffer: Entity<Buffer>,
7201 cx: &mut Context<Self>,
7202 ) -> Option<DocumentColorTask> {
7203 let version_queried_for = buffer.read(cx).version();
7204 let buffer_id = buffer.read(cx).remote_id();
7205
7206 let current_language_servers = self.as_local().map(|local| {
7207 local
7208 .buffers_opened_in_servers
7209 .get(&buffer_id)
7210 .cloned()
7211 .unwrap_or_default()
7212 });
7213
7214 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7215 if let Some(cached_colors) = &lsp_data.document_colors {
7216 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7217 let has_different_servers =
7218 current_language_servers.is_some_and(|current_language_servers| {
7219 current_language_servers
7220 != cached_colors.colors.keys().copied().collect()
7221 });
7222 if !has_different_servers {
7223 let cache_version = cached_colors.cache_version;
7224 if Some(cache_version) == known_cache_version {
7225 return None;
7226 } else {
7227 return Some(
7228 Task::ready(Ok(DocumentColors {
7229 colors: cached_colors
7230 .colors
7231 .values()
7232 .flatten()
7233 .cloned()
7234 .collect(),
7235 cache_version: Some(cache_version),
7236 }))
7237 .shared(),
7238 );
7239 }
7240 }
7241 }
7242 }
7243 }
7244
7245 let color_lsp_data = self
7246 .latest_lsp_data(&buffer, cx)
7247 .document_colors
7248 .get_or_insert_default();
7249 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7250 && !version_queried_for.changed_since(updating_for)
7251 {
7252 return Some(running_update.clone());
7253 }
7254 let buffer_version_queried_for = version_queried_for.clone();
7255 let new_task = cx
7256 .spawn(async move |lsp_store, cx| {
7257 cx.background_executor()
7258 .timer(Duration::from_millis(30))
7259 .await;
7260 let fetched_colors = lsp_store
7261 .update(cx, |lsp_store, cx| {
7262 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7263 })?
7264 .await
7265 .context("fetching document colors")
7266 .map_err(Arc::new);
7267 let fetched_colors = match fetched_colors {
7268 Ok(fetched_colors) => {
7269 if Some(true)
7270 == buffer
7271 .update(cx, |buffer, _| {
7272 buffer.version() != buffer_version_queried_for
7273 })
7274 .ok()
7275 {
7276 return Ok(DocumentColors::default());
7277 }
7278 fetched_colors
7279 }
7280 Err(e) => {
7281 lsp_store
7282 .update(cx, |lsp_store, _| {
7283 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7284 if let Some(document_colors) = &mut lsp_data.document_colors {
7285 document_colors.colors_update = None;
7286 }
7287 }
7288 })
7289 .ok();
7290 return Err(e);
7291 }
7292 };
7293
7294 lsp_store
7295 .update(cx, |lsp_store, cx| {
7296 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7297 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7298
7299 if let Some(fetched_colors) = fetched_colors {
7300 if lsp_data.buffer_version == buffer_version_queried_for {
7301 lsp_colors.colors.extend(fetched_colors);
7302 lsp_colors.cache_version += 1;
7303 } else if !lsp_data
7304 .buffer_version
7305 .changed_since(&buffer_version_queried_for)
7306 {
7307 lsp_data.buffer_version = buffer_version_queried_for;
7308 lsp_colors.colors = fetched_colors;
7309 lsp_colors.cache_version += 1;
7310 }
7311 }
7312 lsp_colors.colors_update = None;
7313 let colors = lsp_colors
7314 .colors
7315 .values()
7316 .flatten()
7317 .cloned()
7318 .collect::<HashSet<_>>();
7319 DocumentColors {
7320 colors,
7321 cache_version: Some(lsp_colors.cache_version),
7322 }
7323 })
7324 .map_err(Arc::new)
7325 })
7326 .shared();
7327 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7328 Some(new_task)
7329 }
7330
7331 fn fetch_document_colors_for_buffer(
7332 &mut self,
7333 buffer: &Entity<Buffer>,
7334 cx: &mut Context<Self>,
7335 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7336 if let Some((client, project_id)) = self.upstream_client() {
7337 let request = GetDocumentColor {};
7338 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7339 return Task::ready(Ok(None));
7340 }
7341
7342 let request_task = client.request_lsp(
7343 project_id,
7344 None,
7345 LSP_REQUEST_TIMEOUT,
7346 cx.background_executor().clone(),
7347 request.to_proto(project_id, buffer.read(cx)),
7348 );
7349 let buffer = buffer.clone();
7350 cx.spawn(async move |lsp_store, cx| {
7351 let Some(lsp_store) = lsp_store.upgrade() else {
7352 return Ok(None);
7353 };
7354 let colors = join_all(
7355 request_task
7356 .await
7357 .log_err()
7358 .flatten()
7359 .map(|response| response.payload)
7360 .unwrap_or_default()
7361 .into_iter()
7362 .map(|color_response| {
7363 let response = request.response_from_proto(
7364 color_response.response,
7365 lsp_store.clone(),
7366 buffer.clone(),
7367 cx.clone(),
7368 );
7369 async move {
7370 (
7371 LanguageServerId::from_proto(color_response.server_id),
7372 response.await.log_err().unwrap_or_default(),
7373 )
7374 }
7375 }),
7376 )
7377 .await
7378 .into_iter()
7379 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7380 acc.entry(server_id)
7381 .or_insert_with(HashSet::default)
7382 .extend(colors);
7383 acc
7384 });
7385 Ok(Some(colors))
7386 })
7387 } else {
7388 let document_colors_task =
7389 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7390 cx.background_spawn(async move {
7391 Ok(Some(
7392 document_colors_task
7393 .await
7394 .into_iter()
7395 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7396 acc.entry(server_id)
7397 .or_insert_with(HashSet::default)
7398 .extend(colors);
7399 acc
7400 })
7401 .into_iter()
7402 .collect(),
7403 ))
7404 })
7405 }
7406 }
7407
7408 pub fn signature_help<T: ToPointUtf16>(
7409 &mut self,
7410 buffer: &Entity<Buffer>,
7411 position: T,
7412 cx: &mut Context<Self>,
7413 ) -> Task<Option<Vec<SignatureHelp>>> {
7414 let position = position.to_point_utf16(buffer.read(cx));
7415
7416 if let Some((client, upstream_project_id)) = self.upstream_client() {
7417 let request = GetSignatureHelp { position };
7418 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7419 return Task::ready(None);
7420 }
7421 let request_task = client.request_lsp(
7422 upstream_project_id,
7423 None,
7424 LSP_REQUEST_TIMEOUT,
7425 cx.background_executor().clone(),
7426 request.to_proto(upstream_project_id, buffer.read(cx)),
7427 );
7428 let buffer = buffer.clone();
7429 cx.spawn(async move |weak_lsp_store, cx| {
7430 let lsp_store = weak_lsp_store.upgrade()?;
7431 let signatures = join_all(
7432 request_task
7433 .await
7434 .log_err()
7435 .flatten()
7436 .map(|response| response.payload)
7437 .unwrap_or_default()
7438 .into_iter()
7439 .map(|response| {
7440 let response = GetSignatureHelp { position }.response_from_proto(
7441 response.response,
7442 lsp_store.clone(),
7443 buffer.clone(),
7444 cx.clone(),
7445 );
7446 async move { response.await.log_err().flatten() }
7447 }),
7448 )
7449 .await
7450 .into_iter()
7451 .flatten()
7452 .collect();
7453 Some(signatures)
7454 })
7455 } else {
7456 let all_actions_task = self.request_multiple_lsp_locally(
7457 buffer,
7458 Some(position),
7459 GetSignatureHelp { position },
7460 cx,
7461 );
7462 cx.background_spawn(async move {
7463 Some(
7464 all_actions_task
7465 .await
7466 .into_iter()
7467 .flat_map(|(_, actions)| actions)
7468 .collect::<Vec<_>>(),
7469 )
7470 })
7471 }
7472 }
7473
7474 pub fn hover(
7475 &mut self,
7476 buffer: &Entity<Buffer>,
7477 position: PointUtf16,
7478 cx: &mut Context<Self>,
7479 ) -> Task<Option<Vec<Hover>>> {
7480 if let Some((client, upstream_project_id)) = self.upstream_client() {
7481 let request = GetHover { position };
7482 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7483 return Task::ready(None);
7484 }
7485 let request_task = client.request_lsp(
7486 upstream_project_id,
7487 None,
7488 LSP_REQUEST_TIMEOUT,
7489 cx.background_executor().clone(),
7490 request.to_proto(upstream_project_id, buffer.read(cx)),
7491 );
7492 let buffer = buffer.clone();
7493 cx.spawn(async move |weak_lsp_store, cx| {
7494 let lsp_store = weak_lsp_store.upgrade()?;
7495 let hovers = join_all(
7496 request_task
7497 .await
7498 .log_err()
7499 .flatten()
7500 .map(|response| response.payload)
7501 .unwrap_or_default()
7502 .into_iter()
7503 .map(|response| {
7504 let response = GetHover { position }.response_from_proto(
7505 response.response,
7506 lsp_store.clone(),
7507 buffer.clone(),
7508 cx.clone(),
7509 );
7510 async move {
7511 response
7512 .await
7513 .log_err()
7514 .flatten()
7515 .and_then(remove_empty_hover_blocks)
7516 }
7517 }),
7518 )
7519 .await
7520 .into_iter()
7521 .flatten()
7522 .collect();
7523 Some(hovers)
7524 })
7525 } else {
7526 let all_actions_task = self.request_multiple_lsp_locally(
7527 buffer,
7528 Some(position),
7529 GetHover { position },
7530 cx,
7531 );
7532 cx.background_spawn(async move {
7533 Some(
7534 all_actions_task
7535 .await
7536 .into_iter()
7537 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7538 .collect::<Vec<Hover>>(),
7539 )
7540 })
7541 }
7542 }
7543
7544 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7545 let language_registry = self.languages.clone();
7546
7547 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7548 let request = upstream_client.request(proto::GetProjectSymbols {
7549 project_id: *project_id,
7550 query: query.to_string(),
7551 });
7552 cx.foreground_executor().spawn(async move {
7553 let response = request.await?;
7554 let mut symbols = Vec::new();
7555 let core_symbols = response
7556 .symbols
7557 .into_iter()
7558 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7559 .collect::<Vec<_>>();
7560 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7561 .await;
7562 Ok(symbols)
7563 })
7564 } else if let Some(local) = self.as_local() {
7565 struct WorkspaceSymbolsResult {
7566 server_id: LanguageServerId,
7567 lsp_adapter: Arc<CachedLspAdapter>,
7568 worktree: WeakEntity<Worktree>,
7569 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7570 }
7571
7572 let mut requests = Vec::new();
7573 let mut requested_servers = BTreeSet::new();
7574 for (seed, state) in local.language_server_ids.iter() {
7575 let Some(worktree_handle) = self
7576 .worktree_store
7577 .read(cx)
7578 .worktree_for_id(seed.worktree_id, cx)
7579 else {
7580 continue;
7581 };
7582 let worktree = worktree_handle.read(cx);
7583 if !worktree.is_visible() {
7584 continue;
7585 }
7586
7587 if !requested_servers.insert(state.id) {
7588 continue;
7589 }
7590
7591 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7592 Some(LanguageServerState::Running {
7593 adapter, server, ..
7594 }) => (adapter.clone(), server),
7595
7596 _ => continue,
7597 };
7598 let supports_workspace_symbol_request =
7599 match server.capabilities().workspace_symbol_provider {
7600 Some(OneOf::Left(supported)) => supported,
7601 Some(OneOf::Right(_)) => true,
7602 None => false,
7603 };
7604 if !supports_workspace_symbol_request {
7605 continue;
7606 }
7607 let worktree_handle = worktree_handle.clone();
7608 let server_id = server.server_id();
7609 requests.push(
7610 server
7611 .request::<lsp::request::WorkspaceSymbolRequest>(
7612 lsp::WorkspaceSymbolParams {
7613 query: query.to_string(),
7614 ..Default::default()
7615 },
7616 )
7617 .map(move |response| {
7618 let lsp_symbols = response.into_response()
7619 .context("workspace symbols request")
7620 .log_err()
7621 .flatten()
7622 .map(|symbol_response| match symbol_response {
7623 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7624 flat_responses.into_iter().map(|lsp_symbol| {
7625 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7626 }).collect::<Vec<_>>()
7627 }
7628 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7629 nested_responses.into_iter().filter_map(|lsp_symbol| {
7630 let location = match lsp_symbol.location {
7631 OneOf::Left(location) => location,
7632 OneOf::Right(_) => {
7633 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7634 return None
7635 }
7636 };
7637 Some((lsp_symbol.name, lsp_symbol.kind, location))
7638 }).collect::<Vec<_>>()
7639 }
7640 }).unwrap_or_default();
7641
7642 WorkspaceSymbolsResult {
7643 server_id,
7644 lsp_adapter,
7645 worktree: worktree_handle.downgrade(),
7646 lsp_symbols,
7647 }
7648 }),
7649 );
7650 }
7651
7652 cx.spawn(async move |this, cx| {
7653 let responses = futures::future::join_all(requests).await;
7654 let this = match this.upgrade() {
7655 Some(this) => this,
7656 None => return Ok(Vec::new()),
7657 };
7658
7659 let mut symbols = Vec::new();
7660 for result in responses {
7661 let core_symbols = this.update(cx, |this, cx| {
7662 result
7663 .lsp_symbols
7664 .into_iter()
7665 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7666 let abs_path = symbol_location.uri.to_file_path().ok()?;
7667 let source_worktree = result.worktree.upgrade()?;
7668 let source_worktree_id = source_worktree.read(cx).id();
7669
7670 let path = if let Some((tree, rel_path)) =
7671 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7672 {
7673 let worktree_id = tree.read(cx).id();
7674 SymbolLocation::InProject(ProjectPath {
7675 worktree_id,
7676 path: rel_path,
7677 })
7678 } else {
7679 SymbolLocation::OutsideProject {
7680 signature: this.symbol_signature(&abs_path),
7681 abs_path: abs_path.into(),
7682 }
7683 };
7684
7685 Some(CoreSymbol {
7686 source_language_server_id: result.server_id,
7687 language_server_name: result.lsp_adapter.name.clone(),
7688 source_worktree_id,
7689 path,
7690 kind: symbol_kind,
7691 name: symbol_name,
7692 range: range_from_lsp(symbol_location.range),
7693 })
7694 })
7695 .collect()
7696 })?;
7697
7698 populate_labels_for_symbols(
7699 core_symbols,
7700 &language_registry,
7701 Some(result.lsp_adapter),
7702 &mut symbols,
7703 )
7704 .await;
7705 }
7706
7707 Ok(symbols)
7708 })
7709 } else {
7710 Task::ready(Err(anyhow!("No upstream client or local language server")))
7711 }
7712 }
7713
7714 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7715 let mut summary = DiagnosticSummary::default();
7716 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7717 summary.error_count += path_summary.error_count;
7718 summary.warning_count += path_summary.warning_count;
7719 }
7720 summary
7721 }
7722
7723 /// Returns the diagnostic summary for a specific project path.
7724 pub fn diagnostic_summary_for_path(
7725 &self,
7726 project_path: &ProjectPath,
7727 _: &App,
7728 ) -> DiagnosticSummary {
7729 if let Some(summaries) = self
7730 .diagnostic_summaries
7731 .get(&project_path.worktree_id)
7732 .and_then(|map| map.get(&project_path.path))
7733 {
7734 let (error_count, warning_count) = summaries.iter().fold(
7735 (0, 0),
7736 |(error_count, warning_count), (_language_server_id, summary)| {
7737 (
7738 error_count + summary.error_count,
7739 warning_count + summary.warning_count,
7740 )
7741 },
7742 );
7743
7744 DiagnosticSummary {
7745 error_count,
7746 warning_count,
7747 }
7748 } else {
7749 DiagnosticSummary::default()
7750 }
7751 }
7752
7753 pub fn diagnostic_summaries<'a>(
7754 &'a self,
7755 include_ignored: bool,
7756 cx: &'a App,
7757 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7758 self.worktree_store
7759 .read(cx)
7760 .visible_worktrees(cx)
7761 .filter_map(|worktree| {
7762 let worktree = worktree.read(cx);
7763 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7764 })
7765 .flat_map(move |(worktree, summaries)| {
7766 let worktree_id = worktree.id();
7767 summaries
7768 .iter()
7769 .filter(move |(path, _)| {
7770 include_ignored
7771 || worktree
7772 .entry_for_path(path.as_ref())
7773 .is_some_and(|entry| !entry.is_ignored)
7774 })
7775 .flat_map(move |(path, summaries)| {
7776 summaries.iter().map(move |(server_id, summary)| {
7777 (
7778 ProjectPath {
7779 worktree_id,
7780 path: path.clone(),
7781 },
7782 *server_id,
7783 *summary,
7784 )
7785 })
7786 })
7787 })
7788 }
7789
7790 pub fn on_buffer_edited(
7791 &mut self,
7792 buffer: Entity<Buffer>,
7793 cx: &mut Context<Self>,
7794 ) -> Option<()> {
7795 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7796 Some(
7797 self.as_local()?
7798 .language_servers_for_buffer(buffer, cx)
7799 .map(|i| i.1.clone())
7800 .collect(),
7801 )
7802 })?;
7803
7804 let buffer = buffer.read(cx);
7805 let file = File::from_dyn(buffer.file())?;
7806 let abs_path = file.as_local()?.abs_path(cx);
7807 let uri = lsp::Uri::from_file_path(&abs_path)
7808 .ok()
7809 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7810 .log_err()?;
7811 let next_snapshot = buffer.text_snapshot();
7812 for language_server in language_servers {
7813 let language_server = language_server.clone();
7814
7815 let buffer_snapshots = self
7816 .as_local_mut()?
7817 .buffer_snapshots
7818 .get_mut(&buffer.remote_id())
7819 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7820 let previous_snapshot = buffer_snapshots.last()?;
7821
7822 let build_incremental_change = || {
7823 buffer
7824 .edits_since::<Dimensions<PointUtf16, usize>>(
7825 previous_snapshot.snapshot.version(),
7826 )
7827 .map(|edit| {
7828 let edit_start = edit.new.start.0;
7829 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7830 let new_text = next_snapshot
7831 .text_for_range(edit.new.start.1..edit.new.end.1)
7832 .collect();
7833 lsp::TextDocumentContentChangeEvent {
7834 range: Some(lsp::Range::new(
7835 point_to_lsp(edit_start),
7836 point_to_lsp(edit_end),
7837 )),
7838 range_length: None,
7839 text: new_text,
7840 }
7841 })
7842 .collect()
7843 };
7844
7845 let document_sync_kind = language_server
7846 .capabilities()
7847 .text_document_sync
7848 .as_ref()
7849 .and_then(|sync| match sync {
7850 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7851 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7852 });
7853
7854 let content_changes: Vec<_> = match document_sync_kind {
7855 Some(lsp::TextDocumentSyncKind::FULL) => {
7856 vec![lsp::TextDocumentContentChangeEvent {
7857 range: None,
7858 range_length: None,
7859 text: next_snapshot.text(),
7860 }]
7861 }
7862 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7863 _ => {
7864 #[cfg(any(test, feature = "test-support"))]
7865 {
7866 build_incremental_change()
7867 }
7868
7869 #[cfg(not(any(test, feature = "test-support")))]
7870 {
7871 continue;
7872 }
7873 }
7874 };
7875
7876 let next_version = previous_snapshot.version + 1;
7877 buffer_snapshots.push(LspBufferSnapshot {
7878 version: next_version,
7879 snapshot: next_snapshot.clone(),
7880 });
7881
7882 language_server
7883 .notify::<lsp::notification::DidChangeTextDocument>(
7884 lsp::DidChangeTextDocumentParams {
7885 text_document: lsp::VersionedTextDocumentIdentifier::new(
7886 uri.clone(),
7887 next_version,
7888 ),
7889 content_changes,
7890 },
7891 )
7892 .ok();
7893 self.pull_workspace_diagnostics(language_server.server_id());
7894 }
7895
7896 None
7897 }
7898
7899 pub fn on_buffer_saved(
7900 &mut self,
7901 buffer: Entity<Buffer>,
7902 cx: &mut Context<Self>,
7903 ) -> Option<()> {
7904 let file = File::from_dyn(buffer.read(cx).file())?;
7905 let worktree_id = file.worktree_id(cx);
7906 let abs_path = file.as_local()?.abs_path(cx);
7907 let text_document = lsp::TextDocumentIdentifier {
7908 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7909 };
7910 let local = self.as_local()?;
7911
7912 for server in local.language_servers_for_worktree(worktree_id) {
7913 if let Some(include_text) = include_text(server.as_ref()) {
7914 let text = if include_text {
7915 Some(buffer.read(cx).text())
7916 } else {
7917 None
7918 };
7919 server
7920 .notify::<lsp::notification::DidSaveTextDocument>(
7921 lsp::DidSaveTextDocumentParams {
7922 text_document: text_document.clone(),
7923 text,
7924 },
7925 )
7926 .ok();
7927 }
7928 }
7929
7930 let language_servers = buffer.update(cx, |buffer, cx| {
7931 local.language_server_ids_for_buffer(buffer, cx)
7932 });
7933 for language_server_id in language_servers {
7934 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7935 }
7936
7937 None
7938 }
7939
7940 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7941 maybe!(async move {
7942 let mut refreshed_servers = HashSet::default();
7943 let servers = lsp_store
7944 .update(cx, |lsp_store, cx| {
7945 let local = lsp_store.as_local()?;
7946
7947 let servers = local
7948 .language_server_ids
7949 .iter()
7950 .filter_map(|(seed, state)| {
7951 let worktree = lsp_store
7952 .worktree_store
7953 .read(cx)
7954 .worktree_for_id(seed.worktree_id, cx);
7955 let delegate: Arc<dyn LspAdapterDelegate> =
7956 worktree.map(|worktree| {
7957 LocalLspAdapterDelegate::new(
7958 local.languages.clone(),
7959 &local.environment,
7960 cx.weak_entity(),
7961 &worktree,
7962 local.http_client.clone(),
7963 local.fs.clone(),
7964 cx,
7965 )
7966 })?;
7967 let server_id = state.id;
7968
7969 let states = local.language_servers.get(&server_id)?;
7970
7971 match states {
7972 LanguageServerState::Starting { .. } => None,
7973 LanguageServerState::Running {
7974 adapter, server, ..
7975 } => {
7976 let adapter = adapter.clone();
7977 let server = server.clone();
7978 refreshed_servers.insert(server.name());
7979 let toolchain = seed.toolchain.clone();
7980 Some(cx.spawn(async move |_, cx| {
7981 let settings =
7982 LocalLspStore::workspace_configuration_for_adapter(
7983 adapter.adapter.clone(),
7984 &delegate,
7985 toolchain,
7986 None,
7987 cx,
7988 )
7989 .await
7990 .ok()?;
7991 server
7992 .notify::<lsp::notification::DidChangeConfiguration>(
7993 lsp::DidChangeConfigurationParams { settings },
7994 )
7995 .ok()?;
7996 Some(())
7997 }))
7998 }
7999 }
8000 })
8001 .collect::<Vec<_>>();
8002
8003 Some(servers)
8004 })
8005 .ok()
8006 .flatten()?;
8007
8008 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8009 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8010 // to stop and unregister its language server wrapper.
8011 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8012 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8013 let _: Vec<Option<()>> = join_all(servers).await;
8014
8015 Some(())
8016 })
8017 .await;
8018 }
8019
8020 fn maintain_workspace_config(
8021 external_refresh_requests: watch::Receiver<()>,
8022 cx: &mut Context<Self>,
8023 ) -> Task<Result<()>> {
8024 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8025 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8026
8027 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8028 *settings_changed_tx.borrow_mut() = ();
8029 });
8030
8031 let mut joint_future =
8032 futures::stream::select(settings_changed_rx, external_refresh_requests);
8033 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8034 // - 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).
8035 // - 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.
8036 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8037 // - 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,
8038 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8039 cx.spawn(async move |this, cx| {
8040 while let Some(()) = joint_future.next().await {
8041 this.update(cx, |this, cx| {
8042 this.refresh_server_tree(cx);
8043 })
8044 .ok();
8045
8046 Self::refresh_workspace_configurations(&this, cx).await;
8047 }
8048
8049 drop(settings_observation);
8050 anyhow::Ok(())
8051 })
8052 }
8053
8054 pub fn language_servers_for_local_buffer<'a>(
8055 &'a self,
8056 buffer: &Buffer,
8057 cx: &mut App,
8058 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8059 let local = self.as_local();
8060 let language_server_ids = local
8061 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8062 .unwrap_or_default();
8063
8064 language_server_ids
8065 .into_iter()
8066 .filter_map(
8067 move |server_id| match local?.language_servers.get(&server_id)? {
8068 LanguageServerState::Running {
8069 adapter, server, ..
8070 } => Some((adapter, server)),
8071 _ => None,
8072 },
8073 )
8074 }
8075
8076 pub fn language_server_for_local_buffer<'a>(
8077 &'a self,
8078 buffer: &'a Buffer,
8079 server_id: LanguageServerId,
8080 cx: &'a mut App,
8081 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8082 self.as_local()?
8083 .language_servers_for_buffer(buffer, cx)
8084 .find(|(_, s)| s.server_id() == server_id)
8085 }
8086
8087 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8088 self.diagnostic_summaries.remove(&id_to_remove);
8089 if let Some(local) = self.as_local_mut() {
8090 let to_remove = local.remove_worktree(id_to_remove, cx);
8091 for server in to_remove {
8092 self.language_server_statuses.remove(&server);
8093 }
8094 }
8095 }
8096
8097 pub fn shared(
8098 &mut self,
8099 project_id: u64,
8100 downstream_client: AnyProtoClient,
8101 _: &mut Context<Self>,
8102 ) {
8103 self.downstream_client = Some((downstream_client.clone(), project_id));
8104
8105 for (server_id, status) in &self.language_server_statuses {
8106 if let Some(server) = self.language_server_for_id(*server_id) {
8107 downstream_client
8108 .send(proto::StartLanguageServer {
8109 project_id,
8110 server: Some(proto::LanguageServer {
8111 id: server_id.to_proto(),
8112 name: status.name.to_string(),
8113 worktree_id: status.worktree.map(|id| id.to_proto()),
8114 }),
8115 capabilities: serde_json::to_string(&server.capabilities())
8116 .expect("serializing server LSP capabilities"),
8117 })
8118 .log_err();
8119 }
8120 }
8121 }
8122
8123 pub fn disconnected_from_host(&mut self) {
8124 self.downstream_client.take();
8125 }
8126
8127 pub fn disconnected_from_ssh_remote(&mut self) {
8128 if let LspStoreMode::Remote(RemoteLspStore {
8129 upstream_client, ..
8130 }) = &mut self.mode
8131 {
8132 upstream_client.take();
8133 }
8134 }
8135
8136 pub(crate) fn set_language_server_statuses_from_proto(
8137 &mut self,
8138 project: WeakEntity<Project>,
8139 language_servers: Vec<proto::LanguageServer>,
8140 server_capabilities: Vec<String>,
8141 cx: &mut Context<Self>,
8142 ) {
8143 let lsp_logs = cx
8144 .try_global::<GlobalLogStore>()
8145 .map(|lsp_store| lsp_store.0.clone());
8146
8147 self.language_server_statuses = language_servers
8148 .into_iter()
8149 .zip(server_capabilities)
8150 .map(|(server, server_capabilities)| {
8151 let server_id = LanguageServerId(server.id as usize);
8152 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8153 self.lsp_server_capabilities
8154 .insert(server_id, server_capabilities);
8155 }
8156
8157 let name = LanguageServerName::from_proto(server.name);
8158 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8159
8160 if let Some(lsp_logs) = &lsp_logs {
8161 lsp_logs.update(cx, |lsp_logs, cx| {
8162 lsp_logs.add_language_server(
8163 // Only remote clients get their language servers set from proto
8164 LanguageServerKind::Remote {
8165 project: project.clone(),
8166 },
8167 server_id,
8168 Some(name.clone()),
8169 worktree,
8170 None,
8171 cx,
8172 );
8173 });
8174 }
8175
8176 (
8177 server_id,
8178 LanguageServerStatus {
8179 name,
8180 pending_work: Default::default(),
8181 has_pending_diagnostic_updates: false,
8182 progress_tokens: Default::default(),
8183 worktree,
8184 binary: None,
8185 configuration: None,
8186 workspace_folders: BTreeSet::new(),
8187 },
8188 )
8189 })
8190 .collect();
8191 }
8192
8193 #[cfg(test)]
8194 pub fn update_diagnostic_entries(
8195 &mut self,
8196 server_id: LanguageServerId,
8197 abs_path: PathBuf,
8198 result_id: Option<String>,
8199 version: Option<i32>,
8200 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8201 cx: &mut Context<Self>,
8202 ) -> anyhow::Result<()> {
8203 self.merge_diagnostic_entries(
8204 vec![DocumentDiagnosticsUpdate {
8205 diagnostics: DocumentDiagnostics {
8206 diagnostics,
8207 document_abs_path: abs_path,
8208 version,
8209 },
8210 result_id,
8211 server_id,
8212 disk_based_sources: Cow::Borrowed(&[]),
8213 }],
8214 |_, _, _| false,
8215 cx,
8216 )?;
8217 Ok(())
8218 }
8219
8220 pub fn merge_diagnostic_entries<'a>(
8221 &mut self,
8222 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8223 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8224 cx: &mut Context<Self>,
8225 ) -> anyhow::Result<()> {
8226 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8227 let mut updated_diagnostics_paths = HashMap::default();
8228 for mut update in diagnostic_updates {
8229 let abs_path = &update.diagnostics.document_abs_path;
8230 let server_id = update.server_id;
8231 let Some((worktree, relative_path)) =
8232 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8233 else {
8234 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8235 return Ok(());
8236 };
8237
8238 let worktree_id = worktree.read(cx).id();
8239 let project_path = ProjectPath {
8240 worktree_id,
8241 path: relative_path,
8242 };
8243
8244 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8245 let snapshot = buffer_handle.read(cx).snapshot();
8246 let buffer = buffer_handle.read(cx);
8247 let reused_diagnostics = buffer
8248 .buffer_diagnostics(Some(server_id))
8249 .iter()
8250 .filter(|v| merge(buffer, &v.diagnostic, cx))
8251 .map(|v| {
8252 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8253 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8254 DiagnosticEntry {
8255 range: start..end,
8256 diagnostic: v.diagnostic.clone(),
8257 }
8258 })
8259 .collect::<Vec<_>>();
8260
8261 self.as_local_mut()
8262 .context("cannot merge diagnostics on a remote LspStore")?
8263 .update_buffer_diagnostics(
8264 &buffer_handle,
8265 server_id,
8266 update.result_id,
8267 update.diagnostics.version,
8268 update.diagnostics.diagnostics.clone(),
8269 reused_diagnostics.clone(),
8270 cx,
8271 )?;
8272
8273 update.diagnostics.diagnostics.extend(reused_diagnostics);
8274 }
8275
8276 let updated = worktree.update(cx, |worktree, cx| {
8277 self.update_worktree_diagnostics(
8278 worktree.id(),
8279 server_id,
8280 project_path.path.clone(),
8281 update.diagnostics.diagnostics,
8282 cx,
8283 )
8284 })?;
8285 match updated {
8286 ControlFlow::Continue(new_summary) => {
8287 if let Some((project_id, new_summary)) = new_summary {
8288 match &mut diagnostics_summary {
8289 Some(diagnostics_summary) => {
8290 diagnostics_summary
8291 .more_summaries
8292 .push(proto::DiagnosticSummary {
8293 path: project_path.path.as_ref().to_proto(),
8294 language_server_id: server_id.0 as u64,
8295 error_count: new_summary.error_count,
8296 warning_count: new_summary.warning_count,
8297 })
8298 }
8299 None => {
8300 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8301 project_id,
8302 worktree_id: worktree_id.to_proto(),
8303 summary: Some(proto::DiagnosticSummary {
8304 path: project_path.path.as_ref().to_proto(),
8305 language_server_id: server_id.0 as u64,
8306 error_count: new_summary.error_count,
8307 warning_count: new_summary.warning_count,
8308 }),
8309 more_summaries: Vec::new(),
8310 })
8311 }
8312 }
8313 }
8314 updated_diagnostics_paths
8315 .entry(server_id)
8316 .or_insert_with(Vec::new)
8317 .push(project_path);
8318 }
8319 ControlFlow::Break(()) => {}
8320 }
8321 }
8322
8323 if let Some((diagnostics_summary, (downstream_client, _))) =
8324 diagnostics_summary.zip(self.downstream_client.as_ref())
8325 {
8326 downstream_client.send(diagnostics_summary).log_err();
8327 }
8328 for (server_id, paths) in updated_diagnostics_paths {
8329 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8330 }
8331 Ok(())
8332 }
8333
8334 fn update_worktree_diagnostics(
8335 &mut self,
8336 worktree_id: WorktreeId,
8337 server_id: LanguageServerId,
8338 path_in_worktree: Arc<RelPath>,
8339 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8340 _: &mut Context<Worktree>,
8341 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8342 let local = match &mut self.mode {
8343 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8344 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8345 };
8346
8347 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8348 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8349 let summaries_by_server_id = summaries_for_tree
8350 .entry(path_in_worktree.clone())
8351 .or_default();
8352
8353 let old_summary = summaries_by_server_id
8354 .remove(&server_id)
8355 .unwrap_or_default();
8356
8357 let new_summary = DiagnosticSummary::new(&diagnostics);
8358 if new_summary.is_empty() {
8359 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8360 {
8361 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8362 diagnostics_by_server_id.remove(ix);
8363 }
8364 if diagnostics_by_server_id.is_empty() {
8365 diagnostics_for_tree.remove(&path_in_worktree);
8366 }
8367 }
8368 } else {
8369 summaries_by_server_id.insert(server_id, new_summary);
8370 let diagnostics_by_server_id = diagnostics_for_tree
8371 .entry(path_in_worktree.clone())
8372 .or_default();
8373 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8374 Ok(ix) => {
8375 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8376 }
8377 Err(ix) => {
8378 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8379 }
8380 }
8381 }
8382
8383 if !old_summary.is_empty() || !new_summary.is_empty() {
8384 if let Some((_, project_id)) = &self.downstream_client {
8385 Ok(ControlFlow::Continue(Some((
8386 *project_id,
8387 proto::DiagnosticSummary {
8388 path: path_in_worktree.to_proto(),
8389 language_server_id: server_id.0 as u64,
8390 error_count: new_summary.error_count as u32,
8391 warning_count: new_summary.warning_count as u32,
8392 },
8393 ))))
8394 } else {
8395 Ok(ControlFlow::Continue(None))
8396 }
8397 } else {
8398 Ok(ControlFlow::Break(()))
8399 }
8400 }
8401
8402 pub fn open_buffer_for_symbol(
8403 &mut self,
8404 symbol: &Symbol,
8405 cx: &mut Context<Self>,
8406 ) -> Task<Result<Entity<Buffer>>> {
8407 if let Some((client, project_id)) = self.upstream_client() {
8408 let request = client.request(proto::OpenBufferForSymbol {
8409 project_id,
8410 symbol: Some(Self::serialize_symbol(symbol)),
8411 });
8412 cx.spawn(async move |this, cx| {
8413 let response = request.await?;
8414 let buffer_id = BufferId::new(response.buffer_id)?;
8415 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8416 .await
8417 })
8418 } else if let Some(local) = self.as_local() {
8419 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8420 seed.worktree_id == symbol.source_worktree_id
8421 && state.id == symbol.source_language_server_id
8422 && symbol.language_server_name == seed.name
8423 });
8424 if !is_valid {
8425 return Task::ready(Err(anyhow!(
8426 "language server for worktree and language not found"
8427 )));
8428 };
8429
8430 let symbol_abs_path = match &symbol.path {
8431 SymbolLocation::InProject(project_path) => self
8432 .worktree_store
8433 .read(cx)
8434 .absolutize(&project_path, cx)
8435 .context("no such worktree"),
8436 SymbolLocation::OutsideProject {
8437 abs_path,
8438 signature: _,
8439 } => Ok(abs_path.to_path_buf()),
8440 };
8441 let symbol_abs_path = match symbol_abs_path {
8442 Ok(abs_path) => abs_path,
8443 Err(err) => return Task::ready(Err(err)),
8444 };
8445 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8446 uri
8447 } else {
8448 return Task::ready(Err(anyhow!("invalid symbol path")));
8449 };
8450
8451 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8452 } else {
8453 Task::ready(Err(anyhow!("no upstream client or local store")))
8454 }
8455 }
8456
8457 pub(crate) fn open_local_buffer_via_lsp(
8458 &mut self,
8459 abs_path: lsp::Uri,
8460 language_server_id: LanguageServerId,
8461 cx: &mut Context<Self>,
8462 ) -> Task<Result<Entity<Buffer>>> {
8463 cx.spawn(async move |lsp_store, cx| {
8464 // Escape percent-encoded string.
8465 let current_scheme = abs_path.scheme().to_owned();
8466 // Uri is immutable, so we can't modify the scheme
8467
8468 let abs_path = abs_path
8469 .to_file_path()
8470 .map_err(|()| anyhow!("can't convert URI to path"))?;
8471 let p = abs_path.clone();
8472 let yarn_worktree = lsp_store
8473 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8474 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8475 cx.spawn(async move |this, cx| {
8476 let t = this
8477 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8478 .ok()?;
8479 t.await
8480 })
8481 }),
8482 None => Task::ready(None),
8483 })?
8484 .await;
8485 let (worktree_root_target, known_relative_path) =
8486 if let Some((zip_root, relative_path)) = yarn_worktree {
8487 (zip_root, Some(relative_path))
8488 } else {
8489 (Arc::<Path>::from(abs_path.as_path()), None)
8490 };
8491 let (worktree, relative_path) = if let Some(result) =
8492 lsp_store.update(cx, |lsp_store, cx| {
8493 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8494 worktree_store.find_worktree(&worktree_root_target, cx)
8495 })
8496 })? {
8497 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8498 (result.0, relative_path)
8499 } else {
8500 let worktree = lsp_store
8501 .update(cx, |lsp_store, cx| {
8502 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8503 worktree_store.create_worktree(&worktree_root_target, false, cx)
8504 })
8505 })?
8506 .await?;
8507 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8508 lsp_store
8509 .update(cx, |lsp_store, cx| {
8510 if let Some(local) = lsp_store.as_local_mut() {
8511 local.register_language_server_for_invisible_worktree(
8512 &worktree,
8513 language_server_id,
8514 cx,
8515 )
8516 }
8517 })
8518 .ok();
8519 }
8520 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8521 let relative_path = if let Some(known_path) = known_relative_path {
8522 known_path
8523 } else {
8524 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8525 .into_arc()
8526 };
8527 (worktree, relative_path)
8528 };
8529 let project_path = ProjectPath {
8530 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8531 path: relative_path,
8532 };
8533 lsp_store
8534 .update(cx, |lsp_store, cx| {
8535 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8536 buffer_store.open_buffer(project_path, cx)
8537 })
8538 })?
8539 .await
8540 })
8541 }
8542
8543 fn request_multiple_lsp_locally<P, R>(
8544 &mut self,
8545 buffer: &Entity<Buffer>,
8546 position: Option<P>,
8547 request: R,
8548 cx: &mut Context<Self>,
8549 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8550 where
8551 P: ToOffset,
8552 R: LspCommand + Clone,
8553 <R::LspRequest as lsp::request::Request>::Result: Send,
8554 <R::LspRequest as lsp::request::Request>::Params: Send,
8555 {
8556 let Some(local) = self.as_local() else {
8557 return Task::ready(Vec::new());
8558 };
8559
8560 let snapshot = buffer.read(cx).snapshot();
8561 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8562
8563 let server_ids = buffer.update(cx, |buffer, cx| {
8564 local
8565 .language_servers_for_buffer(buffer, cx)
8566 .filter(|(adapter, _)| {
8567 scope
8568 .as_ref()
8569 .map(|scope| scope.language_allowed(&adapter.name))
8570 .unwrap_or(true)
8571 })
8572 .map(|(_, server)| server.server_id())
8573 .filter(|server_id| {
8574 self.as_local().is_none_or(|local| {
8575 local
8576 .buffers_opened_in_servers
8577 .get(&snapshot.remote_id())
8578 .is_some_and(|servers| servers.contains(server_id))
8579 })
8580 })
8581 .collect::<Vec<_>>()
8582 });
8583
8584 let mut response_results = server_ids
8585 .into_iter()
8586 .map(|server_id| {
8587 let task = self.request_lsp(
8588 buffer.clone(),
8589 LanguageServerToQuery::Other(server_id),
8590 request.clone(),
8591 cx,
8592 );
8593 async move { (server_id, task.await) }
8594 })
8595 .collect::<FuturesUnordered<_>>();
8596
8597 cx.background_spawn(async move {
8598 let mut responses = Vec::with_capacity(response_results.len());
8599 while let Some((server_id, response_result)) = response_results.next().await {
8600 match response_result {
8601 Ok(response) => responses.push((server_id, response)),
8602 // rust-analyzer likes to error with this when its still loading up
8603 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8604 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8605 }
8606 }
8607 responses
8608 })
8609 }
8610
8611 async fn handle_lsp_get_completions(
8612 this: Entity<Self>,
8613 envelope: TypedEnvelope<proto::GetCompletions>,
8614 mut cx: AsyncApp,
8615 ) -> Result<proto::GetCompletionsResponse> {
8616 let sender_id = envelope.original_sender_id().unwrap_or_default();
8617
8618 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8619 let buffer_handle = this.update(&mut cx, |this, cx| {
8620 this.buffer_store.read(cx).get_existing(buffer_id)
8621 })??;
8622 let request = GetCompletions::from_proto(
8623 envelope.payload,
8624 this.clone(),
8625 buffer_handle.clone(),
8626 cx.clone(),
8627 )
8628 .await?;
8629
8630 let server_to_query = match request.server_id {
8631 Some(server_id) => LanguageServerToQuery::Other(server_id),
8632 None => LanguageServerToQuery::FirstCapable,
8633 };
8634
8635 let response = this
8636 .update(&mut cx, |this, cx| {
8637 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8638 })?
8639 .await?;
8640 this.update(&mut cx, |this, cx| {
8641 Ok(GetCompletions::response_to_proto(
8642 response,
8643 this,
8644 sender_id,
8645 &buffer_handle.read(cx).version(),
8646 cx,
8647 ))
8648 })?
8649 }
8650
8651 async fn handle_lsp_command<T: LspCommand>(
8652 this: Entity<Self>,
8653 envelope: TypedEnvelope<T::ProtoRequest>,
8654 mut cx: AsyncApp,
8655 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8656 where
8657 <T::LspRequest as lsp::request::Request>::Params: Send,
8658 <T::LspRequest as lsp::request::Request>::Result: Send,
8659 {
8660 let sender_id = envelope.original_sender_id().unwrap_or_default();
8661 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8662 let buffer_handle = this.update(&mut cx, |this, cx| {
8663 this.buffer_store.read(cx).get_existing(buffer_id)
8664 })??;
8665 let request = T::from_proto(
8666 envelope.payload,
8667 this.clone(),
8668 buffer_handle.clone(),
8669 cx.clone(),
8670 )
8671 .await?;
8672 let response = this
8673 .update(&mut cx, |this, cx| {
8674 this.request_lsp(
8675 buffer_handle.clone(),
8676 LanguageServerToQuery::FirstCapable,
8677 request,
8678 cx,
8679 )
8680 })?
8681 .await?;
8682 this.update(&mut cx, |this, cx| {
8683 Ok(T::response_to_proto(
8684 response,
8685 this,
8686 sender_id,
8687 &buffer_handle.read(cx).version(),
8688 cx,
8689 ))
8690 })?
8691 }
8692
8693 async fn handle_lsp_query(
8694 lsp_store: Entity<Self>,
8695 envelope: TypedEnvelope<proto::LspQuery>,
8696 mut cx: AsyncApp,
8697 ) -> Result<proto::Ack> {
8698 use proto::lsp_query::Request;
8699 let sender_id = envelope.original_sender_id().unwrap_or_default();
8700 let lsp_query = envelope.payload;
8701 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8702 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8703 match lsp_query.request.context("invalid LSP query request")? {
8704 Request::GetReferences(get_references) => {
8705 let position = get_references.position.clone().and_then(deserialize_anchor);
8706 Self::query_lsp_locally::<GetReferences>(
8707 lsp_store,
8708 server_id,
8709 sender_id,
8710 lsp_request_id,
8711 get_references,
8712 position,
8713 &mut cx,
8714 )
8715 .await?;
8716 }
8717 Request::GetDocumentColor(get_document_color) => {
8718 Self::query_lsp_locally::<GetDocumentColor>(
8719 lsp_store,
8720 server_id,
8721 sender_id,
8722 lsp_request_id,
8723 get_document_color,
8724 None,
8725 &mut cx,
8726 )
8727 .await?;
8728 }
8729 Request::GetHover(get_hover) => {
8730 let position = get_hover.position.clone().and_then(deserialize_anchor);
8731 Self::query_lsp_locally::<GetHover>(
8732 lsp_store,
8733 server_id,
8734 sender_id,
8735 lsp_request_id,
8736 get_hover,
8737 position,
8738 &mut cx,
8739 )
8740 .await?;
8741 }
8742 Request::GetCodeActions(get_code_actions) => {
8743 Self::query_lsp_locally::<GetCodeActions>(
8744 lsp_store,
8745 server_id,
8746 sender_id,
8747 lsp_request_id,
8748 get_code_actions,
8749 None,
8750 &mut cx,
8751 )
8752 .await?;
8753 }
8754 Request::GetSignatureHelp(get_signature_help) => {
8755 let position = get_signature_help
8756 .position
8757 .clone()
8758 .and_then(deserialize_anchor);
8759 Self::query_lsp_locally::<GetSignatureHelp>(
8760 lsp_store,
8761 server_id,
8762 sender_id,
8763 lsp_request_id,
8764 get_signature_help,
8765 position,
8766 &mut cx,
8767 )
8768 .await?;
8769 }
8770 Request::GetCodeLens(get_code_lens) => {
8771 Self::query_lsp_locally::<GetCodeLens>(
8772 lsp_store,
8773 server_id,
8774 sender_id,
8775 lsp_request_id,
8776 get_code_lens,
8777 None,
8778 &mut cx,
8779 )
8780 .await?;
8781 }
8782 Request::GetDefinition(get_definition) => {
8783 let position = get_definition.position.clone().and_then(deserialize_anchor);
8784 Self::query_lsp_locally::<GetDefinitions>(
8785 lsp_store,
8786 server_id,
8787 sender_id,
8788 lsp_request_id,
8789 get_definition,
8790 position,
8791 &mut cx,
8792 )
8793 .await?;
8794 }
8795 Request::GetDeclaration(get_declaration) => {
8796 let position = get_declaration
8797 .position
8798 .clone()
8799 .and_then(deserialize_anchor);
8800 Self::query_lsp_locally::<GetDeclarations>(
8801 lsp_store,
8802 server_id,
8803 sender_id,
8804 lsp_request_id,
8805 get_declaration,
8806 position,
8807 &mut cx,
8808 )
8809 .await?;
8810 }
8811 Request::GetTypeDefinition(get_type_definition) => {
8812 let position = get_type_definition
8813 .position
8814 .clone()
8815 .and_then(deserialize_anchor);
8816 Self::query_lsp_locally::<GetTypeDefinitions>(
8817 lsp_store,
8818 server_id,
8819 sender_id,
8820 lsp_request_id,
8821 get_type_definition,
8822 position,
8823 &mut cx,
8824 )
8825 .await?;
8826 }
8827 Request::GetImplementation(get_implementation) => {
8828 let position = get_implementation
8829 .position
8830 .clone()
8831 .and_then(deserialize_anchor);
8832 Self::query_lsp_locally::<GetImplementations>(
8833 lsp_store,
8834 server_id,
8835 sender_id,
8836 lsp_request_id,
8837 get_implementation,
8838 position,
8839 &mut cx,
8840 )
8841 .await?;
8842 }
8843 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8844 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8845 let version = deserialize_version(get_document_diagnostics.buffer_version());
8846 let buffer = lsp_store.update(&mut cx, |this, cx| {
8847 this.buffer_store.read(cx).get_existing(buffer_id)
8848 })??;
8849 buffer
8850 .update(&mut cx, |buffer, _| {
8851 buffer.wait_for_version(version.clone())
8852 })?
8853 .await?;
8854 lsp_store.update(&mut cx, |lsp_store, cx| {
8855 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8856 let key = LspKey {
8857 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8858 server_queried: server_id,
8859 };
8860 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8861 ) {
8862 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8863 lsp_requests.clear();
8864 };
8865 }
8866
8867 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8868 existing_queries.insert(
8869 lsp_request_id,
8870 cx.spawn(async move |lsp_store, cx| {
8871 let diagnostics_pull = lsp_store
8872 .update(cx, |lsp_store, cx| {
8873 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8874 })
8875 .ok();
8876 if let Some(diagnostics_pull) = diagnostics_pull {
8877 match diagnostics_pull.await {
8878 Ok(()) => {}
8879 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8880 };
8881 }
8882 }),
8883 );
8884 })?;
8885 }
8886 Request::InlayHints(inlay_hints) => {
8887 let query_start = inlay_hints
8888 .start
8889 .clone()
8890 .and_then(deserialize_anchor)
8891 .context("invalid inlay hints range start")?;
8892 let query_end = inlay_hints
8893 .end
8894 .clone()
8895 .and_then(deserialize_anchor)
8896 .context("invalid inlay hints range end")?;
8897 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8898 &lsp_store,
8899 server_id,
8900 lsp_request_id,
8901 &inlay_hints,
8902 query_start..query_end,
8903 &mut cx,
8904 )
8905 .await
8906 .context("preparing inlay hints request")?;
8907 Self::query_lsp_locally::<InlayHints>(
8908 lsp_store,
8909 server_id,
8910 sender_id,
8911 lsp_request_id,
8912 inlay_hints,
8913 None,
8914 &mut cx,
8915 )
8916 .await
8917 .context("querying for inlay hints")?
8918 }
8919 }
8920 Ok(proto::Ack {})
8921 }
8922
8923 async fn handle_lsp_query_response(
8924 lsp_store: Entity<Self>,
8925 envelope: TypedEnvelope<proto::LspQueryResponse>,
8926 cx: AsyncApp,
8927 ) -> Result<()> {
8928 lsp_store.read_with(&cx, |lsp_store, _| {
8929 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8930 upstream_client.handle_lsp_response(envelope.clone());
8931 }
8932 })?;
8933 Ok(())
8934 }
8935
8936 async fn handle_apply_code_action(
8937 this: Entity<Self>,
8938 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8939 mut cx: AsyncApp,
8940 ) -> Result<proto::ApplyCodeActionResponse> {
8941 let sender_id = envelope.original_sender_id().unwrap_or_default();
8942 let action =
8943 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8944 let apply_code_action = this.update(&mut cx, |this, cx| {
8945 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8946 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8947 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8948 })??;
8949
8950 let project_transaction = apply_code_action.await?;
8951 let project_transaction = this.update(&mut cx, |this, cx| {
8952 this.buffer_store.update(cx, |buffer_store, cx| {
8953 buffer_store.serialize_project_transaction_for_peer(
8954 project_transaction,
8955 sender_id,
8956 cx,
8957 )
8958 })
8959 })?;
8960 Ok(proto::ApplyCodeActionResponse {
8961 transaction: Some(project_transaction),
8962 })
8963 }
8964
8965 async fn handle_register_buffer_with_language_servers(
8966 this: Entity<Self>,
8967 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8968 mut cx: AsyncApp,
8969 ) -> Result<proto::Ack> {
8970 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8971 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8972 this.update(&mut cx, |this, cx| {
8973 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8974 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8975 project_id: upstream_project_id,
8976 buffer_id: buffer_id.to_proto(),
8977 only_servers: envelope.payload.only_servers,
8978 });
8979 }
8980
8981 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8982 anyhow::bail!("buffer is not open");
8983 };
8984
8985 let handle = this.register_buffer_with_language_servers(
8986 &buffer,
8987 envelope
8988 .payload
8989 .only_servers
8990 .into_iter()
8991 .filter_map(|selector| {
8992 Some(match selector.selector? {
8993 proto::language_server_selector::Selector::ServerId(server_id) => {
8994 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8995 }
8996 proto::language_server_selector::Selector::Name(name) => {
8997 LanguageServerSelector::Name(LanguageServerName(
8998 SharedString::from(name),
8999 ))
9000 }
9001 })
9002 })
9003 .collect(),
9004 false,
9005 cx,
9006 );
9007 this.buffer_store().update(cx, |buffer_store, _| {
9008 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9009 });
9010
9011 Ok(())
9012 })??;
9013 Ok(proto::Ack {})
9014 }
9015
9016 async fn handle_rename_project_entry(
9017 this: Entity<Self>,
9018 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9019 mut cx: AsyncApp,
9020 ) -> Result<proto::ProjectEntryResponse> {
9021 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9022 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9023 let new_path =
9024 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9025
9026 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9027 .update(&mut cx, |this, cx| {
9028 let (worktree, entry) = this
9029 .worktree_store
9030 .read(cx)
9031 .worktree_and_entry_for_id(entry_id, cx)?;
9032 let new_worktree = this
9033 .worktree_store
9034 .read(cx)
9035 .worktree_for_id(new_worktree_id, cx)?;
9036 Some((
9037 this.worktree_store.clone(),
9038 worktree,
9039 new_worktree,
9040 entry.clone(),
9041 ))
9042 })?
9043 .context("worktree not found")?;
9044 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9045 (worktree.absolutize(&old_entry.path), worktree.id())
9046 })?;
9047 let new_abs_path =
9048 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9049
9050 let _transaction = Self::will_rename_entry(
9051 this.downgrade(),
9052 old_worktree_id,
9053 &old_abs_path,
9054 &new_abs_path,
9055 old_entry.is_dir(),
9056 cx.clone(),
9057 )
9058 .await;
9059 let response = WorktreeStore::handle_rename_project_entry(
9060 worktree_store,
9061 envelope.payload,
9062 cx.clone(),
9063 )
9064 .await;
9065 this.read_with(&cx, |this, _| {
9066 this.did_rename_entry(
9067 old_worktree_id,
9068 &old_abs_path,
9069 &new_abs_path,
9070 old_entry.is_dir(),
9071 );
9072 })
9073 .ok();
9074 response
9075 }
9076
9077 async fn handle_update_diagnostic_summary(
9078 this: Entity<Self>,
9079 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9080 mut cx: AsyncApp,
9081 ) -> Result<()> {
9082 this.update(&mut cx, |lsp_store, cx| {
9083 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9084 let mut updated_diagnostics_paths = HashMap::default();
9085 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9086 for message_summary in envelope
9087 .payload
9088 .summary
9089 .into_iter()
9090 .chain(envelope.payload.more_summaries)
9091 {
9092 let project_path = ProjectPath {
9093 worktree_id,
9094 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9095 };
9096 let path = project_path.path.clone();
9097 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9098 let summary = DiagnosticSummary {
9099 error_count: message_summary.error_count as usize,
9100 warning_count: message_summary.warning_count as usize,
9101 };
9102
9103 if summary.is_empty() {
9104 if let Some(worktree_summaries) =
9105 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9106 && let Some(summaries) = worktree_summaries.get_mut(&path)
9107 {
9108 summaries.remove(&server_id);
9109 if summaries.is_empty() {
9110 worktree_summaries.remove(&path);
9111 }
9112 }
9113 } else {
9114 lsp_store
9115 .diagnostic_summaries
9116 .entry(worktree_id)
9117 .or_default()
9118 .entry(path)
9119 .or_default()
9120 .insert(server_id, summary);
9121 }
9122
9123 if let Some((_, project_id)) = &lsp_store.downstream_client {
9124 match &mut diagnostics_summary {
9125 Some(diagnostics_summary) => {
9126 diagnostics_summary
9127 .more_summaries
9128 .push(proto::DiagnosticSummary {
9129 path: project_path.path.as_ref().to_proto(),
9130 language_server_id: server_id.0 as u64,
9131 error_count: summary.error_count as u32,
9132 warning_count: summary.warning_count as u32,
9133 })
9134 }
9135 None => {
9136 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9137 project_id: *project_id,
9138 worktree_id: worktree_id.to_proto(),
9139 summary: Some(proto::DiagnosticSummary {
9140 path: project_path.path.as_ref().to_proto(),
9141 language_server_id: server_id.0 as u64,
9142 error_count: summary.error_count as u32,
9143 warning_count: summary.warning_count as u32,
9144 }),
9145 more_summaries: Vec::new(),
9146 })
9147 }
9148 }
9149 }
9150 updated_diagnostics_paths
9151 .entry(server_id)
9152 .or_insert_with(Vec::new)
9153 .push(project_path);
9154 }
9155
9156 if let Some((diagnostics_summary, (downstream_client, _))) =
9157 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9158 {
9159 downstream_client.send(diagnostics_summary).log_err();
9160 }
9161 for (server_id, paths) in updated_diagnostics_paths {
9162 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9163 }
9164 Ok(())
9165 })?
9166 }
9167
9168 async fn handle_start_language_server(
9169 lsp_store: Entity<Self>,
9170 envelope: TypedEnvelope<proto::StartLanguageServer>,
9171 mut cx: AsyncApp,
9172 ) -> Result<()> {
9173 let server = envelope.payload.server.context("invalid server")?;
9174 let server_capabilities =
9175 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9176 .with_context(|| {
9177 format!(
9178 "incorrect server capabilities {}",
9179 envelope.payload.capabilities
9180 )
9181 })?;
9182 lsp_store.update(&mut cx, |lsp_store, cx| {
9183 let server_id = LanguageServerId(server.id as usize);
9184 let server_name = LanguageServerName::from_proto(server.name.clone());
9185 lsp_store
9186 .lsp_server_capabilities
9187 .insert(server_id, server_capabilities);
9188 lsp_store.language_server_statuses.insert(
9189 server_id,
9190 LanguageServerStatus {
9191 name: server_name.clone(),
9192 pending_work: Default::default(),
9193 has_pending_diagnostic_updates: false,
9194 progress_tokens: Default::default(),
9195 worktree: server.worktree_id.map(WorktreeId::from_proto),
9196 binary: None,
9197 configuration: None,
9198 workspace_folders: BTreeSet::new(),
9199 },
9200 );
9201 cx.emit(LspStoreEvent::LanguageServerAdded(
9202 server_id,
9203 server_name,
9204 server.worktree_id.map(WorktreeId::from_proto),
9205 ));
9206 cx.notify();
9207 })?;
9208 Ok(())
9209 }
9210
9211 async fn handle_update_language_server(
9212 lsp_store: Entity<Self>,
9213 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9214 mut cx: AsyncApp,
9215 ) -> Result<()> {
9216 lsp_store.update(&mut cx, |lsp_store, cx| {
9217 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9218
9219 match envelope.payload.variant.context("invalid variant")? {
9220 proto::update_language_server::Variant::WorkStart(payload) => {
9221 lsp_store.on_lsp_work_start(
9222 language_server_id,
9223 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9224 .context("invalid progress token value")?,
9225 LanguageServerProgress {
9226 title: payload.title,
9227 is_disk_based_diagnostics_progress: false,
9228 is_cancellable: payload.is_cancellable.unwrap_or(false),
9229 message: payload.message,
9230 percentage: payload.percentage.map(|p| p as usize),
9231 last_update_at: cx.background_executor().now(),
9232 },
9233 cx,
9234 );
9235 }
9236 proto::update_language_server::Variant::WorkProgress(payload) => {
9237 lsp_store.on_lsp_work_progress(
9238 language_server_id,
9239 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9240 .context("invalid progress token value")?,
9241 LanguageServerProgress {
9242 title: None,
9243 is_disk_based_diagnostics_progress: false,
9244 is_cancellable: payload.is_cancellable.unwrap_or(false),
9245 message: payload.message,
9246 percentage: payload.percentage.map(|p| p as usize),
9247 last_update_at: cx.background_executor().now(),
9248 },
9249 cx,
9250 );
9251 }
9252
9253 proto::update_language_server::Variant::WorkEnd(payload) => {
9254 lsp_store.on_lsp_work_end(
9255 language_server_id,
9256 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9257 .context("invalid progress token value")?,
9258 cx,
9259 );
9260 }
9261
9262 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9263 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9264 }
9265
9266 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9267 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9268 }
9269
9270 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9271 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9272 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9273 cx.emit(LspStoreEvent::LanguageServerUpdate {
9274 language_server_id,
9275 name: envelope
9276 .payload
9277 .server_name
9278 .map(SharedString::new)
9279 .map(LanguageServerName),
9280 message: non_lsp,
9281 });
9282 }
9283 }
9284
9285 Ok(())
9286 })?
9287 }
9288
9289 async fn handle_language_server_log(
9290 this: Entity<Self>,
9291 envelope: TypedEnvelope<proto::LanguageServerLog>,
9292 mut cx: AsyncApp,
9293 ) -> Result<()> {
9294 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9295 let log_type = envelope
9296 .payload
9297 .log_type
9298 .map(LanguageServerLogType::from_proto)
9299 .context("invalid language server log type")?;
9300
9301 let message = envelope.payload.message;
9302
9303 this.update(&mut cx, |_, cx| {
9304 cx.emit(LspStoreEvent::LanguageServerLog(
9305 language_server_id,
9306 log_type,
9307 message,
9308 ));
9309 })
9310 }
9311
9312 async fn handle_lsp_ext_cancel_flycheck(
9313 lsp_store: Entity<Self>,
9314 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9315 cx: AsyncApp,
9316 ) -> Result<proto::Ack> {
9317 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9318 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9319 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9320 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9321 } else {
9322 None
9323 }
9324 })?;
9325 if let Some(task) = task {
9326 task.context("handling lsp ext cancel flycheck")?;
9327 }
9328
9329 Ok(proto::Ack {})
9330 }
9331
9332 async fn handle_lsp_ext_run_flycheck(
9333 lsp_store: Entity<Self>,
9334 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9335 mut cx: AsyncApp,
9336 ) -> Result<proto::Ack> {
9337 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9338 lsp_store.update(&mut cx, |lsp_store, cx| {
9339 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9340 let text_document = if envelope.payload.current_file_only {
9341 let buffer_id = envelope
9342 .payload
9343 .buffer_id
9344 .map(|id| BufferId::new(id))
9345 .transpose()?;
9346 buffer_id
9347 .and_then(|buffer_id| {
9348 lsp_store
9349 .buffer_store()
9350 .read(cx)
9351 .get(buffer_id)
9352 .and_then(|buffer| {
9353 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9354 })
9355 .map(|path| make_text_document_identifier(&path))
9356 })
9357 .transpose()?
9358 } else {
9359 None
9360 };
9361 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9362 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9363 )?;
9364 }
9365 anyhow::Ok(())
9366 })??;
9367
9368 Ok(proto::Ack {})
9369 }
9370
9371 async fn handle_lsp_ext_clear_flycheck(
9372 lsp_store: Entity<Self>,
9373 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9374 cx: AsyncApp,
9375 ) -> Result<proto::Ack> {
9376 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9377 lsp_store
9378 .read_with(&cx, |lsp_store, _| {
9379 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9380 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9381 } else {
9382 None
9383 }
9384 })
9385 .context("handling lsp ext clear flycheck")?;
9386
9387 Ok(proto::Ack {})
9388 }
9389
9390 pub fn disk_based_diagnostics_started(
9391 &mut self,
9392 language_server_id: LanguageServerId,
9393 cx: &mut Context<Self>,
9394 ) {
9395 if let Some(language_server_status) =
9396 self.language_server_statuses.get_mut(&language_server_id)
9397 {
9398 language_server_status.has_pending_diagnostic_updates = true;
9399 }
9400
9401 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9402 cx.emit(LspStoreEvent::LanguageServerUpdate {
9403 language_server_id,
9404 name: self
9405 .language_server_adapter_for_id(language_server_id)
9406 .map(|adapter| adapter.name()),
9407 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9408 Default::default(),
9409 ),
9410 })
9411 }
9412
9413 pub fn disk_based_diagnostics_finished(
9414 &mut self,
9415 language_server_id: LanguageServerId,
9416 cx: &mut Context<Self>,
9417 ) {
9418 if let Some(language_server_status) =
9419 self.language_server_statuses.get_mut(&language_server_id)
9420 {
9421 language_server_status.has_pending_diagnostic_updates = false;
9422 }
9423
9424 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9425 cx.emit(LspStoreEvent::LanguageServerUpdate {
9426 language_server_id,
9427 name: self
9428 .language_server_adapter_for_id(language_server_id)
9429 .map(|adapter| adapter.name()),
9430 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9431 Default::default(),
9432 ),
9433 })
9434 }
9435
9436 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9437 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9438 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9439 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9440 // the language server might take some time to publish diagnostics.
9441 fn simulate_disk_based_diagnostics_events_if_needed(
9442 &mut self,
9443 language_server_id: LanguageServerId,
9444 cx: &mut Context<Self>,
9445 ) {
9446 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9447
9448 let Some(LanguageServerState::Running {
9449 simulate_disk_based_diagnostics_completion,
9450 adapter,
9451 ..
9452 }) = self
9453 .as_local_mut()
9454 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9455 else {
9456 return;
9457 };
9458
9459 if adapter.disk_based_diagnostics_progress_token.is_some() {
9460 return;
9461 }
9462
9463 let prev_task =
9464 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9465 cx.background_executor()
9466 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9467 .await;
9468
9469 this.update(cx, |this, cx| {
9470 this.disk_based_diagnostics_finished(language_server_id, cx);
9471
9472 if let Some(LanguageServerState::Running {
9473 simulate_disk_based_diagnostics_completion,
9474 ..
9475 }) = this.as_local_mut().and_then(|local_store| {
9476 local_store.language_servers.get_mut(&language_server_id)
9477 }) {
9478 *simulate_disk_based_diagnostics_completion = None;
9479 }
9480 })
9481 .ok();
9482 }));
9483
9484 if prev_task.is_none() {
9485 self.disk_based_diagnostics_started(language_server_id, cx);
9486 }
9487 }
9488
9489 pub fn language_server_statuses(
9490 &self,
9491 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9492 self.language_server_statuses
9493 .iter()
9494 .map(|(key, value)| (*key, value))
9495 }
9496
9497 pub(super) fn did_rename_entry(
9498 &self,
9499 worktree_id: WorktreeId,
9500 old_path: &Path,
9501 new_path: &Path,
9502 is_dir: bool,
9503 ) {
9504 maybe!({
9505 let local_store = self.as_local()?;
9506
9507 let old_uri = lsp::Uri::from_file_path(old_path)
9508 .ok()
9509 .map(|uri| uri.to_string())?;
9510 let new_uri = lsp::Uri::from_file_path(new_path)
9511 .ok()
9512 .map(|uri| uri.to_string())?;
9513
9514 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9515 let Some(filter) = local_store
9516 .language_server_paths_watched_for_rename
9517 .get(&language_server.server_id())
9518 else {
9519 continue;
9520 };
9521
9522 if filter.should_send_did_rename(&old_uri, is_dir) {
9523 language_server
9524 .notify::<DidRenameFiles>(RenameFilesParams {
9525 files: vec![FileRename {
9526 old_uri: old_uri.clone(),
9527 new_uri: new_uri.clone(),
9528 }],
9529 })
9530 .ok();
9531 }
9532 }
9533 Some(())
9534 });
9535 }
9536
9537 pub(super) fn will_rename_entry(
9538 this: WeakEntity<Self>,
9539 worktree_id: WorktreeId,
9540 old_path: &Path,
9541 new_path: &Path,
9542 is_dir: bool,
9543 cx: AsyncApp,
9544 ) -> Task<ProjectTransaction> {
9545 let old_uri = lsp::Uri::from_file_path(old_path)
9546 .ok()
9547 .map(|uri| uri.to_string());
9548 let new_uri = lsp::Uri::from_file_path(new_path)
9549 .ok()
9550 .map(|uri| uri.to_string());
9551 cx.spawn(async move |cx| {
9552 let mut tasks = vec![];
9553 this.update(cx, |this, cx| {
9554 let local_store = this.as_local()?;
9555 let old_uri = old_uri?;
9556 let new_uri = new_uri?;
9557 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9558 let Some(filter) = local_store
9559 .language_server_paths_watched_for_rename
9560 .get(&language_server.server_id())
9561 else {
9562 continue;
9563 };
9564
9565 if filter.should_send_will_rename(&old_uri, is_dir) {
9566 let apply_edit = cx.spawn({
9567 let old_uri = old_uri.clone();
9568 let new_uri = new_uri.clone();
9569 let language_server = language_server.clone();
9570 async move |this, cx| {
9571 let edit = language_server
9572 .request::<WillRenameFiles>(RenameFilesParams {
9573 files: vec![FileRename { old_uri, new_uri }],
9574 })
9575 .await
9576 .into_response()
9577 .context("will rename files")
9578 .log_err()
9579 .flatten()?;
9580
9581 let transaction = LocalLspStore::deserialize_workspace_edit(
9582 this.upgrade()?,
9583 edit,
9584 false,
9585 language_server.clone(),
9586 cx,
9587 )
9588 .await
9589 .ok()?;
9590 Some(transaction)
9591 }
9592 });
9593 tasks.push(apply_edit);
9594 }
9595 }
9596 Some(())
9597 })
9598 .ok()
9599 .flatten();
9600 let mut merged_transaction = ProjectTransaction::default();
9601 for task in tasks {
9602 // Await on tasks sequentially so that the order of application of edits is deterministic
9603 // (at least with regards to the order of registration of language servers)
9604 if let Some(transaction) = task.await {
9605 for (buffer, buffer_transaction) in transaction.0 {
9606 merged_transaction.0.insert(buffer, buffer_transaction);
9607 }
9608 }
9609 }
9610 merged_transaction
9611 })
9612 }
9613
9614 fn lsp_notify_abs_paths_changed(
9615 &mut self,
9616 server_id: LanguageServerId,
9617 changes: Vec<PathEvent>,
9618 ) {
9619 maybe!({
9620 let server = self.language_server_for_id(server_id)?;
9621 let changes = changes
9622 .into_iter()
9623 .filter_map(|event| {
9624 let typ = match event.kind? {
9625 PathEventKind::Created => lsp::FileChangeType::CREATED,
9626 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9627 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9628 };
9629 Some(lsp::FileEvent {
9630 uri: file_path_to_lsp_url(&event.path).log_err()?,
9631 typ,
9632 })
9633 })
9634 .collect::<Vec<_>>();
9635 if !changes.is_empty() {
9636 server
9637 .notify::<lsp::notification::DidChangeWatchedFiles>(
9638 lsp::DidChangeWatchedFilesParams { changes },
9639 )
9640 .ok();
9641 }
9642 Some(())
9643 });
9644 }
9645
9646 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9647 self.as_local()?.language_server_for_id(id)
9648 }
9649
9650 fn on_lsp_progress(
9651 &mut self,
9652 progress_params: lsp::ProgressParams,
9653 language_server_id: LanguageServerId,
9654 disk_based_diagnostics_progress_token: Option<String>,
9655 cx: &mut Context<Self>,
9656 ) {
9657 match progress_params.value {
9658 lsp::ProgressParamsValue::WorkDone(progress) => {
9659 self.handle_work_done_progress(
9660 progress,
9661 language_server_id,
9662 disk_based_diagnostics_progress_token,
9663 ProgressToken::from_lsp(progress_params.token),
9664 cx,
9665 );
9666 }
9667 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9668 let identifier = match progress_params.token {
9669 lsp::NumberOrString::Number(_) => None,
9670 lsp::NumberOrString::String(token) => token
9671 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9672 .map(|(_, id)| id.to_owned()),
9673 };
9674 if let Some(LanguageServerState::Running {
9675 workspace_diagnostics_refresh_tasks,
9676 ..
9677 }) = self
9678 .as_local_mut()
9679 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9680 && let Some(workspace_diagnostics) =
9681 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9682 {
9683 workspace_diagnostics.progress_tx.try_send(()).ok();
9684 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9685 }
9686 }
9687 }
9688 }
9689
9690 fn handle_work_done_progress(
9691 &mut self,
9692 progress: lsp::WorkDoneProgress,
9693 language_server_id: LanguageServerId,
9694 disk_based_diagnostics_progress_token: Option<String>,
9695 token: ProgressToken,
9696 cx: &mut Context<Self>,
9697 ) {
9698 let language_server_status =
9699 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9700 status
9701 } else {
9702 return;
9703 };
9704
9705 if !language_server_status.progress_tokens.contains(&token) {
9706 return;
9707 }
9708
9709 let is_disk_based_diagnostics_progress =
9710 if let (Some(disk_based_token), ProgressToken::String(token)) =
9711 (&disk_based_diagnostics_progress_token, &token)
9712 {
9713 token.starts_with(disk_based_token)
9714 } else {
9715 false
9716 };
9717
9718 match progress {
9719 lsp::WorkDoneProgress::Begin(report) => {
9720 if is_disk_based_diagnostics_progress {
9721 self.disk_based_diagnostics_started(language_server_id, cx);
9722 }
9723 self.on_lsp_work_start(
9724 language_server_id,
9725 token.clone(),
9726 LanguageServerProgress {
9727 title: Some(report.title),
9728 is_disk_based_diagnostics_progress,
9729 is_cancellable: report.cancellable.unwrap_or(false),
9730 message: report.message.clone(),
9731 percentage: report.percentage.map(|p| p as usize),
9732 last_update_at: cx.background_executor().now(),
9733 },
9734 cx,
9735 );
9736 }
9737 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9738 language_server_id,
9739 token,
9740 LanguageServerProgress {
9741 title: None,
9742 is_disk_based_diagnostics_progress,
9743 is_cancellable: report.cancellable.unwrap_or(false),
9744 message: report.message,
9745 percentage: report.percentage.map(|p| p as usize),
9746 last_update_at: cx.background_executor().now(),
9747 },
9748 cx,
9749 ),
9750 lsp::WorkDoneProgress::End(_) => {
9751 language_server_status.progress_tokens.remove(&token);
9752 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9753 if is_disk_based_diagnostics_progress {
9754 self.disk_based_diagnostics_finished(language_server_id, cx);
9755 }
9756 }
9757 }
9758 }
9759
9760 fn on_lsp_work_start(
9761 &mut self,
9762 language_server_id: LanguageServerId,
9763 token: ProgressToken,
9764 progress: LanguageServerProgress,
9765 cx: &mut Context<Self>,
9766 ) {
9767 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9768 status.pending_work.insert(token.clone(), progress.clone());
9769 cx.notify();
9770 }
9771 cx.emit(LspStoreEvent::LanguageServerUpdate {
9772 language_server_id,
9773 name: self
9774 .language_server_adapter_for_id(language_server_id)
9775 .map(|adapter| adapter.name()),
9776 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9777 token: Some(token.to_proto()),
9778 title: progress.title,
9779 message: progress.message,
9780 percentage: progress.percentage.map(|p| p as u32),
9781 is_cancellable: Some(progress.is_cancellable),
9782 }),
9783 })
9784 }
9785
9786 fn on_lsp_work_progress(
9787 &mut self,
9788 language_server_id: LanguageServerId,
9789 token: ProgressToken,
9790 progress: LanguageServerProgress,
9791 cx: &mut Context<Self>,
9792 ) {
9793 let mut did_update = false;
9794 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9795 match status.pending_work.entry(token.clone()) {
9796 btree_map::Entry::Vacant(entry) => {
9797 entry.insert(progress.clone());
9798 did_update = true;
9799 }
9800 btree_map::Entry::Occupied(mut entry) => {
9801 let entry = entry.get_mut();
9802 if (progress.last_update_at - entry.last_update_at)
9803 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9804 {
9805 entry.last_update_at = progress.last_update_at;
9806 if progress.message.is_some() {
9807 entry.message = progress.message.clone();
9808 }
9809 if progress.percentage.is_some() {
9810 entry.percentage = progress.percentage;
9811 }
9812 if progress.is_cancellable != entry.is_cancellable {
9813 entry.is_cancellable = progress.is_cancellable;
9814 }
9815 did_update = true;
9816 }
9817 }
9818 }
9819 }
9820
9821 if did_update {
9822 cx.emit(LspStoreEvent::LanguageServerUpdate {
9823 language_server_id,
9824 name: self
9825 .language_server_adapter_for_id(language_server_id)
9826 .map(|adapter| adapter.name()),
9827 message: proto::update_language_server::Variant::WorkProgress(
9828 proto::LspWorkProgress {
9829 token: Some(token.to_proto()),
9830 message: progress.message,
9831 percentage: progress.percentage.map(|p| p as u32),
9832 is_cancellable: Some(progress.is_cancellable),
9833 },
9834 ),
9835 })
9836 }
9837 }
9838
9839 fn on_lsp_work_end(
9840 &mut self,
9841 language_server_id: LanguageServerId,
9842 token: ProgressToken,
9843 cx: &mut Context<Self>,
9844 ) {
9845 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9846 if let Some(work) = status.pending_work.remove(&token)
9847 && !work.is_disk_based_diagnostics_progress
9848 {
9849 cx.emit(LspStoreEvent::RefreshInlayHints {
9850 server_id: language_server_id,
9851 request_id: None,
9852 });
9853 }
9854 cx.notify();
9855 }
9856
9857 cx.emit(LspStoreEvent::LanguageServerUpdate {
9858 language_server_id,
9859 name: self
9860 .language_server_adapter_for_id(language_server_id)
9861 .map(|adapter| adapter.name()),
9862 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9863 token: Some(token.to_proto()),
9864 }),
9865 })
9866 }
9867
9868 pub async fn handle_resolve_completion_documentation(
9869 this: Entity<Self>,
9870 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9871 mut cx: AsyncApp,
9872 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9873 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9874
9875 let completion = this
9876 .read_with(&cx, |this, cx| {
9877 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9878 let server = this
9879 .language_server_for_id(id)
9880 .with_context(|| format!("No language server {id}"))?;
9881
9882 anyhow::Ok(cx.background_spawn(async move {
9883 let can_resolve = server
9884 .capabilities()
9885 .completion_provider
9886 .as_ref()
9887 .and_then(|options| options.resolve_provider)
9888 .unwrap_or(false);
9889 if can_resolve {
9890 server
9891 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9892 .await
9893 .into_response()
9894 .context("resolve completion item")
9895 } else {
9896 anyhow::Ok(lsp_completion)
9897 }
9898 }))
9899 })??
9900 .await?;
9901
9902 let mut documentation_is_markdown = false;
9903 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9904 let documentation = match completion.documentation {
9905 Some(lsp::Documentation::String(text)) => text,
9906
9907 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9908 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9909 value
9910 }
9911
9912 _ => String::new(),
9913 };
9914
9915 // If we have a new buffer_id, that means we're talking to a new client
9916 // and want to check for new text_edits in the completion too.
9917 let mut old_replace_start = None;
9918 let mut old_replace_end = None;
9919 let mut old_insert_start = None;
9920 let mut old_insert_end = None;
9921 let mut new_text = String::default();
9922 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9923 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9924 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9925 anyhow::Ok(buffer.read(cx).snapshot())
9926 })??;
9927
9928 if let Some(text_edit) = completion.text_edit.as_ref() {
9929 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9930
9931 if let Some(mut edit) = edit {
9932 LineEnding::normalize(&mut edit.new_text);
9933
9934 new_text = edit.new_text;
9935 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9936 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9937 if let Some(insert_range) = edit.insert_range {
9938 old_insert_start = Some(serialize_anchor(&insert_range.start));
9939 old_insert_end = Some(serialize_anchor(&insert_range.end));
9940 }
9941 }
9942 }
9943 }
9944
9945 Ok(proto::ResolveCompletionDocumentationResponse {
9946 documentation,
9947 documentation_is_markdown,
9948 old_replace_start,
9949 old_replace_end,
9950 new_text,
9951 lsp_completion,
9952 old_insert_start,
9953 old_insert_end,
9954 })
9955 }
9956
9957 async fn handle_on_type_formatting(
9958 this: Entity<Self>,
9959 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9960 mut cx: AsyncApp,
9961 ) -> Result<proto::OnTypeFormattingResponse> {
9962 let on_type_formatting = this.update(&mut cx, |this, cx| {
9963 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9964 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9965 let position = envelope
9966 .payload
9967 .position
9968 .and_then(deserialize_anchor)
9969 .context("invalid position")?;
9970 anyhow::Ok(this.apply_on_type_formatting(
9971 buffer,
9972 position,
9973 envelope.payload.trigger.clone(),
9974 cx,
9975 ))
9976 })??;
9977
9978 let transaction = on_type_formatting
9979 .await?
9980 .as_ref()
9981 .map(language::proto::serialize_transaction);
9982 Ok(proto::OnTypeFormattingResponse { transaction })
9983 }
9984
9985 async fn handle_refresh_inlay_hints(
9986 lsp_store: Entity<Self>,
9987 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9988 mut cx: AsyncApp,
9989 ) -> Result<proto::Ack> {
9990 lsp_store.update(&mut cx, |_, cx| {
9991 cx.emit(LspStoreEvent::RefreshInlayHints {
9992 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
9993 request_id: envelope.payload.request_id.map(|id| id as usize),
9994 });
9995 })?;
9996 Ok(proto::Ack {})
9997 }
9998
9999 async fn handle_pull_workspace_diagnostics(
10000 lsp_store: Entity<Self>,
10001 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10002 mut cx: AsyncApp,
10003 ) -> Result<proto::Ack> {
10004 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10005 lsp_store.update(&mut cx, |lsp_store, _| {
10006 lsp_store.pull_workspace_diagnostics(server_id);
10007 })?;
10008 Ok(proto::Ack {})
10009 }
10010
10011 async fn handle_get_color_presentation(
10012 lsp_store: Entity<Self>,
10013 envelope: TypedEnvelope<proto::GetColorPresentation>,
10014 mut cx: AsyncApp,
10015 ) -> Result<proto::GetColorPresentationResponse> {
10016 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10017 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10018 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10019 })??;
10020
10021 let color = envelope
10022 .payload
10023 .color
10024 .context("invalid color resolve request")?;
10025 let start = color
10026 .lsp_range_start
10027 .context("invalid color resolve request")?;
10028 let end = color
10029 .lsp_range_end
10030 .context("invalid color resolve request")?;
10031
10032 let color = DocumentColor {
10033 lsp_range: lsp::Range {
10034 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10035 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10036 },
10037 color: lsp::Color {
10038 red: color.red,
10039 green: color.green,
10040 blue: color.blue,
10041 alpha: color.alpha,
10042 },
10043 resolved: false,
10044 color_presentations: Vec::new(),
10045 };
10046 let resolved_color = lsp_store
10047 .update(&mut cx, |lsp_store, cx| {
10048 lsp_store.resolve_color_presentation(
10049 color,
10050 buffer.clone(),
10051 LanguageServerId(envelope.payload.server_id as usize),
10052 cx,
10053 )
10054 })?
10055 .await
10056 .context("resolving color presentation")?;
10057
10058 Ok(proto::GetColorPresentationResponse {
10059 presentations: resolved_color
10060 .color_presentations
10061 .into_iter()
10062 .map(|presentation| proto::ColorPresentation {
10063 label: presentation.label.to_string(),
10064 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10065 additional_text_edits: presentation
10066 .additional_text_edits
10067 .into_iter()
10068 .map(serialize_lsp_edit)
10069 .collect(),
10070 })
10071 .collect(),
10072 })
10073 }
10074
10075 async fn handle_resolve_inlay_hint(
10076 lsp_store: Entity<Self>,
10077 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10078 mut cx: AsyncApp,
10079 ) -> Result<proto::ResolveInlayHintResponse> {
10080 let proto_hint = envelope
10081 .payload
10082 .hint
10083 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10084 let hint = InlayHints::proto_to_project_hint(proto_hint)
10085 .context("resolved proto inlay hint conversion")?;
10086 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10087 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10088 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10089 })??;
10090 let response_hint = lsp_store
10091 .update(&mut cx, |lsp_store, cx| {
10092 lsp_store.resolve_inlay_hint(
10093 hint,
10094 buffer,
10095 LanguageServerId(envelope.payload.language_server_id as usize),
10096 cx,
10097 )
10098 })?
10099 .await
10100 .context("inlay hints fetch")?;
10101 Ok(proto::ResolveInlayHintResponse {
10102 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10103 })
10104 }
10105
10106 async fn handle_refresh_code_lens(
10107 this: Entity<Self>,
10108 _: TypedEnvelope<proto::RefreshCodeLens>,
10109 mut cx: AsyncApp,
10110 ) -> Result<proto::Ack> {
10111 this.update(&mut cx, |_, cx| {
10112 cx.emit(LspStoreEvent::RefreshCodeLens);
10113 })?;
10114 Ok(proto::Ack {})
10115 }
10116
10117 async fn handle_open_buffer_for_symbol(
10118 this: Entity<Self>,
10119 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10120 mut cx: AsyncApp,
10121 ) -> Result<proto::OpenBufferForSymbolResponse> {
10122 let peer_id = envelope.original_sender_id().unwrap_or_default();
10123 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10124 let symbol = Self::deserialize_symbol(symbol)?;
10125 this.read_with(&cx, |this, _| {
10126 if let SymbolLocation::OutsideProject {
10127 abs_path,
10128 signature,
10129 } = &symbol.path
10130 {
10131 let new_signature = this.symbol_signature(&abs_path);
10132 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10133 }
10134 Ok(())
10135 })??;
10136 let buffer = this
10137 .update(&mut cx, |this, cx| {
10138 this.open_buffer_for_symbol(
10139 &Symbol {
10140 language_server_name: symbol.language_server_name,
10141 source_worktree_id: symbol.source_worktree_id,
10142 source_language_server_id: symbol.source_language_server_id,
10143 path: symbol.path,
10144 name: symbol.name,
10145 kind: symbol.kind,
10146 range: symbol.range,
10147 label: CodeLabel::default(),
10148 },
10149 cx,
10150 )
10151 })?
10152 .await?;
10153
10154 this.update(&mut cx, |this, cx| {
10155 let is_private = buffer
10156 .read(cx)
10157 .file()
10158 .map(|f| f.is_private())
10159 .unwrap_or_default();
10160 if is_private {
10161 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10162 } else {
10163 this.buffer_store
10164 .update(cx, |buffer_store, cx| {
10165 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10166 })
10167 .detach_and_log_err(cx);
10168 let buffer_id = buffer.read(cx).remote_id().to_proto();
10169 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10170 }
10171 })?
10172 }
10173
10174 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10175 let mut hasher = Sha256::new();
10176 hasher.update(abs_path.to_string_lossy().as_bytes());
10177 hasher.update(self.nonce.to_be_bytes());
10178 hasher.finalize().as_slice().try_into().unwrap()
10179 }
10180
10181 pub async fn handle_get_project_symbols(
10182 this: Entity<Self>,
10183 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10184 mut cx: AsyncApp,
10185 ) -> Result<proto::GetProjectSymbolsResponse> {
10186 let symbols = this
10187 .update(&mut cx, |this, cx| {
10188 this.symbols(&envelope.payload.query, cx)
10189 })?
10190 .await?;
10191
10192 Ok(proto::GetProjectSymbolsResponse {
10193 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10194 })
10195 }
10196
10197 pub async fn handle_restart_language_servers(
10198 this: Entity<Self>,
10199 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10200 mut cx: AsyncApp,
10201 ) -> Result<proto::Ack> {
10202 this.update(&mut cx, |lsp_store, cx| {
10203 let buffers =
10204 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10205 lsp_store.restart_language_servers_for_buffers(
10206 buffers,
10207 envelope
10208 .payload
10209 .only_servers
10210 .into_iter()
10211 .filter_map(|selector| {
10212 Some(match selector.selector? {
10213 proto::language_server_selector::Selector::ServerId(server_id) => {
10214 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10215 }
10216 proto::language_server_selector::Selector::Name(name) => {
10217 LanguageServerSelector::Name(LanguageServerName(
10218 SharedString::from(name),
10219 ))
10220 }
10221 })
10222 })
10223 .collect(),
10224 cx,
10225 );
10226 })?;
10227
10228 Ok(proto::Ack {})
10229 }
10230
10231 pub async fn handle_stop_language_servers(
10232 lsp_store: Entity<Self>,
10233 envelope: TypedEnvelope<proto::StopLanguageServers>,
10234 mut cx: AsyncApp,
10235 ) -> Result<proto::Ack> {
10236 lsp_store.update(&mut cx, |lsp_store, cx| {
10237 if envelope.payload.all
10238 && envelope.payload.also_servers.is_empty()
10239 && envelope.payload.buffer_ids.is_empty()
10240 {
10241 lsp_store.stop_all_language_servers(cx);
10242 } else {
10243 let buffers =
10244 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10245 lsp_store
10246 .stop_language_servers_for_buffers(
10247 buffers,
10248 envelope
10249 .payload
10250 .also_servers
10251 .into_iter()
10252 .filter_map(|selector| {
10253 Some(match selector.selector? {
10254 proto::language_server_selector::Selector::ServerId(
10255 server_id,
10256 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10257 server_id,
10258 )),
10259 proto::language_server_selector::Selector::Name(name) => {
10260 LanguageServerSelector::Name(LanguageServerName(
10261 SharedString::from(name),
10262 ))
10263 }
10264 })
10265 })
10266 .collect(),
10267 cx,
10268 )
10269 .detach_and_log_err(cx);
10270 }
10271 })?;
10272
10273 Ok(proto::Ack {})
10274 }
10275
10276 pub async fn handle_cancel_language_server_work(
10277 lsp_store: Entity<Self>,
10278 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10279 mut cx: AsyncApp,
10280 ) -> Result<proto::Ack> {
10281 lsp_store.update(&mut cx, |lsp_store, cx| {
10282 if let Some(work) = envelope.payload.work {
10283 match work {
10284 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10285 let buffers =
10286 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10287 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10288 }
10289 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10290 let server_id = LanguageServerId::from_proto(work.language_server_id);
10291 let token = work
10292 .token
10293 .map(|token| {
10294 ProgressToken::from_proto(token)
10295 .context("invalid work progress token")
10296 })
10297 .transpose()?;
10298 lsp_store.cancel_language_server_work(server_id, token, cx);
10299 }
10300 }
10301 }
10302 anyhow::Ok(())
10303 })??;
10304
10305 Ok(proto::Ack {})
10306 }
10307
10308 fn buffer_ids_to_buffers(
10309 &mut self,
10310 buffer_ids: impl Iterator<Item = u64>,
10311 cx: &mut Context<Self>,
10312 ) -> Vec<Entity<Buffer>> {
10313 buffer_ids
10314 .into_iter()
10315 .flat_map(|buffer_id| {
10316 self.buffer_store
10317 .read(cx)
10318 .get(BufferId::new(buffer_id).log_err()?)
10319 })
10320 .collect::<Vec<_>>()
10321 }
10322
10323 async fn handle_apply_additional_edits_for_completion(
10324 this: Entity<Self>,
10325 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10326 mut cx: AsyncApp,
10327 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10328 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10329 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10330 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10331 let completion = Self::deserialize_completion(
10332 envelope.payload.completion.context("invalid completion")?,
10333 )?;
10334 anyhow::Ok((buffer, completion))
10335 })??;
10336
10337 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10338 this.apply_additional_edits_for_completion(
10339 buffer,
10340 Rc::new(RefCell::new(Box::new([Completion {
10341 replace_range: completion.replace_range,
10342 new_text: completion.new_text,
10343 source: completion.source,
10344 documentation: None,
10345 label: CodeLabel::default(),
10346 match_start: None,
10347 snippet_deduplication_key: None,
10348 insert_text_mode: None,
10349 icon_path: None,
10350 confirm: None,
10351 }]))),
10352 0,
10353 false,
10354 cx,
10355 )
10356 })?;
10357
10358 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10359 transaction: apply_additional_edits
10360 .await?
10361 .as_ref()
10362 .map(language::proto::serialize_transaction),
10363 })
10364 }
10365
10366 pub fn last_formatting_failure(&self) -> Option<&str> {
10367 self.last_formatting_failure.as_deref()
10368 }
10369
10370 pub fn reset_last_formatting_failure(&mut self) {
10371 self.last_formatting_failure = None;
10372 }
10373
10374 pub fn environment_for_buffer(
10375 &self,
10376 buffer: &Entity<Buffer>,
10377 cx: &mut Context<Self>,
10378 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10379 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10380 environment.update(cx, |env, cx| {
10381 env.buffer_environment(buffer, &self.worktree_store, cx)
10382 })
10383 } else {
10384 Task::ready(None).shared()
10385 }
10386 }
10387
10388 pub fn format(
10389 &mut self,
10390 buffers: HashSet<Entity<Buffer>>,
10391 target: LspFormatTarget,
10392 push_to_history: bool,
10393 trigger: FormatTrigger,
10394 cx: &mut Context<Self>,
10395 ) -> Task<anyhow::Result<ProjectTransaction>> {
10396 let logger = zlog::scoped!("format");
10397 if self.as_local().is_some() {
10398 zlog::trace!(logger => "Formatting locally");
10399 let logger = zlog::scoped!(logger => "local");
10400 let buffers = buffers
10401 .into_iter()
10402 .map(|buffer_handle| {
10403 let buffer = buffer_handle.read(cx);
10404 let buffer_abs_path = File::from_dyn(buffer.file())
10405 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10406
10407 (buffer_handle, buffer_abs_path, buffer.remote_id())
10408 })
10409 .collect::<Vec<_>>();
10410
10411 cx.spawn(async move |lsp_store, cx| {
10412 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10413
10414 for (handle, abs_path, id) in buffers {
10415 let env = lsp_store
10416 .update(cx, |lsp_store, cx| {
10417 lsp_store.environment_for_buffer(&handle, cx)
10418 })?
10419 .await;
10420
10421 let ranges = match &target {
10422 LspFormatTarget::Buffers => None,
10423 LspFormatTarget::Ranges(ranges) => {
10424 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10425 }
10426 };
10427
10428 formattable_buffers.push(FormattableBuffer {
10429 handle,
10430 abs_path,
10431 env,
10432 ranges,
10433 });
10434 }
10435 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10436
10437 let format_timer = zlog::time!(logger => "Formatting buffers");
10438 let result = LocalLspStore::format_locally(
10439 lsp_store.clone(),
10440 formattable_buffers,
10441 push_to_history,
10442 trigger,
10443 logger,
10444 cx,
10445 )
10446 .await;
10447 format_timer.end();
10448
10449 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10450
10451 lsp_store.update(cx, |lsp_store, _| {
10452 lsp_store.update_last_formatting_failure(&result);
10453 })?;
10454
10455 result
10456 })
10457 } else if let Some((client, project_id)) = self.upstream_client() {
10458 zlog::trace!(logger => "Formatting remotely");
10459 let logger = zlog::scoped!(logger => "remote");
10460 // Don't support formatting ranges via remote
10461 match target {
10462 LspFormatTarget::Buffers => {}
10463 LspFormatTarget::Ranges(_) => {
10464 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10465 return Task::ready(Ok(ProjectTransaction::default()));
10466 }
10467 }
10468
10469 let buffer_store = self.buffer_store();
10470 cx.spawn(async move |lsp_store, cx| {
10471 zlog::trace!(logger => "Sending remote format request");
10472 let request_timer = zlog::time!(logger => "remote format request");
10473 let result = client
10474 .request(proto::FormatBuffers {
10475 project_id,
10476 trigger: trigger as i32,
10477 buffer_ids: buffers
10478 .iter()
10479 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10480 .collect::<Result<_>>()?,
10481 })
10482 .await
10483 .and_then(|result| result.transaction.context("missing transaction"));
10484 request_timer.end();
10485
10486 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10487
10488 lsp_store.update(cx, |lsp_store, _| {
10489 lsp_store.update_last_formatting_failure(&result);
10490 })?;
10491
10492 let transaction_response = result?;
10493 let _timer = zlog::time!(logger => "deserializing project transaction");
10494 buffer_store
10495 .update(cx, |buffer_store, cx| {
10496 buffer_store.deserialize_project_transaction(
10497 transaction_response,
10498 push_to_history,
10499 cx,
10500 )
10501 })?
10502 .await
10503 })
10504 } else {
10505 zlog::trace!(logger => "Not formatting");
10506 Task::ready(Ok(ProjectTransaction::default()))
10507 }
10508 }
10509
10510 async fn handle_format_buffers(
10511 this: Entity<Self>,
10512 envelope: TypedEnvelope<proto::FormatBuffers>,
10513 mut cx: AsyncApp,
10514 ) -> Result<proto::FormatBuffersResponse> {
10515 let sender_id = envelope.original_sender_id().unwrap_or_default();
10516 let format = this.update(&mut cx, |this, cx| {
10517 let mut buffers = HashSet::default();
10518 for buffer_id in &envelope.payload.buffer_ids {
10519 let buffer_id = BufferId::new(*buffer_id)?;
10520 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10521 }
10522 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10523 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10524 })??;
10525
10526 let project_transaction = format.await?;
10527 let project_transaction = this.update(&mut cx, |this, cx| {
10528 this.buffer_store.update(cx, |buffer_store, cx| {
10529 buffer_store.serialize_project_transaction_for_peer(
10530 project_transaction,
10531 sender_id,
10532 cx,
10533 )
10534 })
10535 })?;
10536 Ok(proto::FormatBuffersResponse {
10537 transaction: Some(project_transaction),
10538 })
10539 }
10540
10541 async fn handle_apply_code_action_kind(
10542 this: Entity<Self>,
10543 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10544 mut cx: AsyncApp,
10545 ) -> Result<proto::ApplyCodeActionKindResponse> {
10546 let sender_id = envelope.original_sender_id().unwrap_or_default();
10547 let format = this.update(&mut cx, |this, cx| {
10548 let mut buffers = HashSet::default();
10549 for buffer_id in &envelope.payload.buffer_ids {
10550 let buffer_id = BufferId::new(*buffer_id)?;
10551 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10552 }
10553 let kind = match envelope.payload.kind.as_str() {
10554 "" => CodeActionKind::EMPTY,
10555 "quickfix" => CodeActionKind::QUICKFIX,
10556 "refactor" => CodeActionKind::REFACTOR,
10557 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10558 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10559 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10560 "source" => CodeActionKind::SOURCE,
10561 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10562 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10563 _ => anyhow::bail!(
10564 "Invalid code action kind {}",
10565 envelope.payload.kind.as_str()
10566 ),
10567 };
10568 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10569 })??;
10570
10571 let project_transaction = format.await?;
10572 let project_transaction = this.update(&mut cx, |this, cx| {
10573 this.buffer_store.update(cx, |buffer_store, cx| {
10574 buffer_store.serialize_project_transaction_for_peer(
10575 project_transaction,
10576 sender_id,
10577 cx,
10578 )
10579 })
10580 })?;
10581 Ok(proto::ApplyCodeActionKindResponse {
10582 transaction: Some(project_transaction),
10583 })
10584 }
10585
10586 async fn shutdown_language_server(
10587 server_state: Option<LanguageServerState>,
10588 name: LanguageServerName,
10589 cx: &mut AsyncApp,
10590 ) {
10591 let server = match server_state {
10592 Some(LanguageServerState::Starting { startup, .. }) => {
10593 let mut timer = cx
10594 .background_executor()
10595 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10596 .fuse();
10597
10598 select! {
10599 server = startup.fuse() => server,
10600 () = timer => {
10601 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10602 None
10603 },
10604 }
10605 }
10606
10607 Some(LanguageServerState::Running { server, .. }) => Some(server),
10608
10609 None => None,
10610 };
10611
10612 if let Some(server) = server
10613 && let Some(shutdown) = server.shutdown()
10614 {
10615 shutdown.await;
10616 }
10617 }
10618
10619 // Returns a list of all of the worktrees which no longer have a language server and the root path
10620 // for the stopped server
10621 fn stop_local_language_server(
10622 &mut self,
10623 server_id: LanguageServerId,
10624 cx: &mut Context<Self>,
10625 ) -> Task<()> {
10626 let local = match &mut self.mode {
10627 LspStoreMode::Local(local) => local,
10628 _ => {
10629 return Task::ready(());
10630 }
10631 };
10632
10633 // Remove this server ID from all entries in the given worktree.
10634 local
10635 .language_server_ids
10636 .retain(|_, state| state.id != server_id);
10637 self.buffer_store.update(cx, |buffer_store, cx| {
10638 for buffer in buffer_store.buffers() {
10639 buffer.update(cx, |buffer, cx| {
10640 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10641 buffer.set_completion_triggers(server_id, Default::default(), cx);
10642 });
10643 }
10644 });
10645
10646 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10647 summaries.retain(|path, summaries_by_server_id| {
10648 if summaries_by_server_id.remove(&server_id).is_some() {
10649 if let Some((client, project_id)) = self.downstream_client.clone() {
10650 client
10651 .send(proto::UpdateDiagnosticSummary {
10652 project_id,
10653 worktree_id: worktree_id.to_proto(),
10654 summary: Some(proto::DiagnosticSummary {
10655 path: path.as_ref().to_proto(),
10656 language_server_id: server_id.0 as u64,
10657 error_count: 0,
10658 warning_count: 0,
10659 }),
10660 more_summaries: Vec::new(),
10661 })
10662 .log_err();
10663 }
10664 !summaries_by_server_id.is_empty()
10665 } else {
10666 true
10667 }
10668 });
10669 }
10670
10671 let local = self.as_local_mut().unwrap();
10672 for diagnostics in local.diagnostics.values_mut() {
10673 diagnostics.retain(|_, diagnostics_by_server_id| {
10674 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10675 diagnostics_by_server_id.remove(ix);
10676 !diagnostics_by_server_id.is_empty()
10677 } else {
10678 true
10679 }
10680 });
10681 }
10682 local.language_server_watched_paths.remove(&server_id);
10683
10684 let server_state = local.language_servers.remove(&server_id);
10685 self.cleanup_lsp_data(server_id);
10686 let name = self
10687 .language_server_statuses
10688 .remove(&server_id)
10689 .map(|status| status.name)
10690 .or_else(|| {
10691 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10692 Some(adapter.name())
10693 } else {
10694 None
10695 }
10696 });
10697
10698 if let Some(name) = name {
10699 log::info!("stopping language server {name}");
10700 self.languages
10701 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10702 cx.notify();
10703
10704 return cx.spawn(async move |lsp_store, cx| {
10705 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10706 lsp_store
10707 .update(cx, |lsp_store, cx| {
10708 lsp_store
10709 .languages
10710 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10711 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10712 cx.notify();
10713 })
10714 .ok();
10715 });
10716 }
10717
10718 if server_state.is_some() {
10719 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10720 }
10721 Task::ready(())
10722 }
10723
10724 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10725 if let Some((client, project_id)) = self.upstream_client() {
10726 let request = client.request(proto::StopLanguageServers {
10727 project_id,
10728 buffer_ids: Vec::new(),
10729 also_servers: Vec::new(),
10730 all: true,
10731 });
10732 cx.background_spawn(request).detach_and_log_err(cx);
10733 } else {
10734 let Some(local) = self.as_local_mut() else {
10735 return;
10736 };
10737 let language_servers_to_stop = local
10738 .language_server_ids
10739 .values()
10740 .map(|state| state.id)
10741 .collect();
10742 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10743 let tasks = language_servers_to_stop
10744 .into_iter()
10745 .map(|server| self.stop_local_language_server(server, cx))
10746 .collect::<Vec<_>>();
10747 cx.background_spawn(async move {
10748 futures::future::join_all(tasks).await;
10749 })
10750 .detach();
10751 }
10752 }
10753
10754 pub fn restart_language_servers_for_buffers(
10755 &mut self,
10756 buffers: Vec<Entity<Buffer>>,
10757 only_restart_servers: HashSet<LanguageServerSelector>,
10758 cx: &mut Context<Self>,
10759 ) {
10760 if let Some((client, project_id)) = self.upstream_client() {
10761 let request = client.request(proto::RestartLanguageServers {
10762 project_id,
10763 buffer_ids: buffers
10764 .into_iter()
10765 .map(|b| b.read(cx).remote_id().to_proto())
10766 .collect(),
10767 only_servers: only_restart_servers
10768 .into_iter()
10769 .map(|selector| {
10770 let selector = match selector {
10771 LanguageServerSelector::Id(language_server_id) => {
10772 proto::language_server_selector::Selector::ServerId(
10773 language_server_id.to_proto(),
10774 )
10775 }
10776 LanguageServerSelector::Name(language_server_name) => {
10777 proto::language_server_selector::Selector::Name(
10778 language_server_name.to_string(),
10779 )
10780 }
10781 };
10782 proto::LanguageServerSelector {
10783 selector: Some(selector),
10784 }
10785 })
10786 .collect(),
10787 all: false,
10788 });
10789 cx.background_spawn(request).detach_and_log_err(cx);
10790 } else {
10791 let stop_task = if only_restart_servers.is_empty() {
10792 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10793 } else {
10794 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10795 };
10796 cx.spawn(async move |lsp_store, cx| {
10797 stop_task.await;
10798 lsp_store
10799 .update(cx, |lsp_store, cx| {
10800 for buffer in buffers {
10801 lsp_store.register_buffer_with_language_servers(
10802 &buffer,
10803 only_restart_servers.clone(),
10804 true,
10805 cx,
10806 );
10807 }
10808 })
10809 .ok()
10810 })
10811 .detach();
10812 }
10813 }
10814
10815 pub fn stop_language_servers_for_buffers(
10816 &mut self,
10817 buffers: Vec<Entity<Buffer>>,
10818 also_stop_servers: HashSet<LanguageServerSelector>,
10819 cx: &mut Context<Self>,
10820 ) -> Task<Result<()>> {
10821 if let Some((client, project_id)) = self.upstream_client() {
10822 let request = client.request(proto::StopLanguageServers {
10823 project_id,
10824 buffer_ids: buffers
10825 .into_iter()
10826 .map(|b| b.read(cx).remote_id().to_proto())
10827 .collect(),
10828 also_servers: also_stop_servers
10829 .into_iter()
10830 .map(|selector| {
10831 let selector = match selector {
10832 LanguageServerSelector::Id(language_server_id) => {
10833 proto::language_server_selector::Selector::ServerId(
10834 language_server_id.to_proto(),
10835 )
10836 }
10837 LanguageServerSelector::Name(language_server_name) => {
10838 proto::language_server_selector::Selector::Name(
10839 language_server_name.to_string(),
10840 )
10841 }
10842 };
10843 proto::LanguageServerSelector {
10844 selector: Some(selector),
10845 }
10846 })
10847 .collect(),
10848 all: false,
10849 });
10850 cx.background_spawn(async move {
10851 let _ = request.await?;
10852 Ok(())
10853 })
10854 } else {
10855 let task =
10856 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10857 cx.background_spawn(async move {
10858 task.await;
10859 Ok(())
10860 })
10861 }
10862 }
10863
10864 fn stop_local_language_servers_for_buffers(
10865 &mut self,
10866 buffers: &[Entity<Buffer>],
10867 also_stop_servers: HashSet<LanguageServerSelector>,
10868 cx: &mut Context<Self>,
10869 ) -> Task<()> {
10870 let Some(local) = self.as_local_mut() else {
10871 return Task::ready(());
10872 };
10873 let mut language_server_names_to_stop = BTreeSet::default();
10874 let mut language_servers_to_stop = also_stop_servers
10875 .into_iter()
10876 .flat_map(|selector| match selector {
10877 LanguageServerSelector::Id(id) => Some(id),
10878 LanguageServerSelector::Name(name) => {
10879 language_server_names_to_stop.insert(name);
10880 None
10881 }
10882 })
10883 .collect::<BTreeSet<_>>();
10884
10885 let mut covered_worktrees = HashSet::default();
10886 for buffer in buffers {
10887 buffer.update(cx, |buffer, cx| {
10888 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10889 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10890 && covered_worktrees.insert(worktree_id)
10891 {
10892 language_server_names_to_stop.retain(|name| {
10893 let old_ids_count = language_servers_to_stop.len();
10894 let all_language_servers_with_this_name = local
10895 .language_server_ids
10896 .iter()
10897 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10898 language_servers_to_stop.extend(all_language_servers_with_this_name);
10899 old_ids_count == language_servers_to_stop.len()
10900 });
10901 }
10902 });
10903 }
10904 for name in language_server_names_to_stop {
10905 language_servers_to_stop.extend(
10906 local
10907 .language_server_ids
10908 .iter()
10909 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10910 );
10911 }
10912
10913 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10914 let tasks = language_servers_to_stop
10915 .into_iter()
10916 .map(|server| self.stop_local_language_server(server, cx))
10917 .collect::<Vec<_>>();
10918
10919 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10920 }
10921
10922 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10923 let (worktree, relative_path) =
10924 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10925
10926 let project_path = ProjectPath {
10927 worktree_id: worktree.read(cx).id(),
10928 path: relative_path,
10929 };
10930
10931 Some(
10932 self.buffer_store()
10933 .read(cx)
10934 .get_by_path(&project_path)?
10935 .read(cx),
10936 )
10937 }
10938
10939 #[cfg(any(test, feature = "test-support"))]
10940 pub fn update_diagnostics(
10941 &mut self,
10942 server_id: LanguageServerId,
10943 diagnostics: lsp::PublishDiagnosticsParams,
10944 result_id: Option<String>,
10945 source_kind: DiagnosticSourceKind,
10946 disk_based_sources: &[String],
10947 cx: &mut Context<Self>,
10948 ) -> Result<()> {
10949 self.merge_lsp_diagnostics(
10950 source_kind,
10951 vec![DocumentDiagnosticsUpdate {
10952 diagnostics,
10953 result_id,
10954 server_id,
10955 disk_based_sources: Cow::Borrowed(disk_based_sources),
10956 }],
10957 |_, _, _| false,
10958 cx,
10959 )
10960 }
10961
10962 pub fn merge_lsp_diagnostics(
10963 &mut self,
10964 source_kind: DiagnosticSourceKind,
10965 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10966 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10967 cx: &mut Context<Self>,
10968 ) -> Result<()> {
10969 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10970 let updates = lsp_diagnostics
10971 .into_iter()
10972 .filter_map(|update| {
10973 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10974 Some(DocumentDiagnosticsUpdate {
10975 diagnostics: self.lsp_to_document_diagnostics(
10976 abs_path,
10977 source_kind,
10978 update.server_id,
10979 update.diagnostics,
10980 &update.disk_based_sources,
10981 ),
10982 result_id: update.result_id,
10983 server_id: update.server_id,
10984 disk_based_sources: update.disk_based_sources,
10985 })
10986 })
10987 .collect();
10988 self.merge_diagnostic_entries(updates, merge, cx)?;
10989 Ok(())
10990 }
10991
10992 fn lsp_to_document_diagnostics(
10993 &mut self,
10994 document_abs_path: PathBuf,
10995 source_kind: DiagnosticSourceKind,
10996 server_id: LanguageServerId,
10997 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10998 disk_based_sources: &[String],
10999 ) -> DocumentDiagnostics {
11000 let mut diagnostics = Vec::default();
11001 let mut primary_diagnostic_group_ids = HashMap::default();
11002 let mut sources_by_group_id = HashMap::default();
11003 let mut supporting_diagnostics = HashMap::default();
11004
11005 let adapter = self.language_server_adapter_for_id(server_id);
11006
11007 // Ensure that primary diagnostics are always the most severe
11008 lsp_diagnostics
11009 .diagnostics
11010 .sort_by_key(|item| item.severity);
11011
11012 for diagnostic in &lsp_diagnostics.diagnostics {
11013 let source = diagnostic.source.as_ref();
11014 let range = range_from_lsp(diagnostic.range);
11015 let is_supporting = diagnostic
11016 .related_information
11017 .as_ref()
11018 .is_some_and(|infos| {
11019 infos.iter().any(|info| {
11020 primary_diagnostic_group_ids.contains_key(&(
11021 source,
11022 diagnostic.code.clone(),
11023 range_from_lsp(info.location.range),
11024 ))
11025 })
11026 });
11027
11028 let is_unnecessary = diagnostic
11029 .tags
11030 .as_ref()
11031 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11032
11033 let underline = self
11034 .language_server_adapter_for_id(server_id)
11035 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11036
11037 if is_supporting {
11038 supporting_diagnostics.insert(
11039 (source, diagnostic.code.clone(), range),
11040 (diagnostic.severity, is_unnecessary),
11041 );
11042 } else {
11043 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11044 let is_disk_based =
11045 source.is_some_and(|source| disk_based_sources.contains(source));
11046
11047 sources_by_group_id.insert(group_id, source);
11048 primary_diagnostic_group_ids
11049 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11050
11051 diagnostics.push(DiagnosticEntry {
11052 range,
11053 diagnostic: Diagnostic {
11054 source: diagnostic.source.clone(),
11055 source_kind,
11056 code: diagnostic.code.clone(),
11057 code_description: diagnostic
11058 .code_description
11059 .as_ref()
11060 .and_then(|d| d.href.clone()),
11061 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11062 markdown: adapter.as_ref().and_then(|adapter| {
11063 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11064 }),
11065 message: diagnostic.message.trim().to_string(),
11066 group_id,
11067 is_primary: true,
11068 is_disk_based,
11069 is_unnecessary,
11070 underline,
11071 data: diagnostic.data.clone(),
11072 },
11073 });
11074 if let Some(infos) = &diagnostic.related_information {
11075 for info in infos {
11076 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11077 let range = range_from_lsp(info.location.range);
11078 diagnostics.push(DiagnosticEntry {
11079 range,
11080 diagnostic: Diagnostic {
11081 source: diagnostic.source.clone(),
11082 source_kind,
11083 code: diagnostic.code.clone(),
11084 code_description: diagnostic
11085 .code_description
11086 .as_ref()
11087 .and_then(|d| d.href.clone()),
11088 severity: DiagnosticSeverity::INFORMATION,
11089 markdown: adapter.as_ref().and_then(|adapter| {
11090 adapter.diagnostic_message_to_markdown(&info.message)
11091 }),
11092 message: info.message.trim().to_string(),
11093 group_id,
11094 is_primary: false,
11095 is_disk_based,
11096 is_unnecessary: false,
11097 underline,
11098 data: diagnostic.data.clone(),
11099 },
11100 });
11101 }
11102 }
11103 }
11104 }
11105 }
11106
11107 for entry in &mut diagnostics {
11108 let diagnostic = &mut entry.diagnostic;
11109 if !diagnostic.is_primary {
11110 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11111 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11112 source,
11113 diagnostic.code.clone(),
11114 entry.range.clone(),
11115 )) {
11116 if let Some(severity) = severity {
11117 diagnostic.severity = severity;
11118 }
11119 diagnostic.is_unnecessary = is_unnecessary;
11120 }
11121 }
11122 }
11123
11124 DocumentDiagnostics {
11125 diagnostics,
11126 document_abs_path,
11127 version: lsp_diagnostics.version,
11128 }
11129 }
11130
11131 fn insert_newly_running_language_server(
11132 &mut self,
11133 adapter: Arc<CachedLspAdapter>,
11134 language_server: Arc<LanguageServer>,
11135 server_id: LanguageServerId,
11136 key: LanguageServerSeed,
11137 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11138 cx: &mut Context<Self>,
11139 ) {
11140 let Some(local) = self.as_local_mut() else {
11141 return;
11142 };
11143 // If the language server for this key doesn't match the server id, don't store the
11144 // server. Which will cause it to be dropped, killing the process
11145 if local
11146 .language_server_ids
11147 .get(&key)
11148 .map(|state| state.id != server_id)
11149 .unwrap_or(false)
11150 {
11151 return;
11152 }
11153
11154 // Update language_servers collection with Running variant of LanguageServerState
11155 // indicating that the server is up and running and ready
11156 let workspace_folders = workspace_folders.lock().clone();
11157 language_server.set_workspace_folders(workspace_folders);
11158
11159 let workspace_diagnostics_refresh_tasks = language_server
11160 .capabilities()
11161 .diagnostic_provider
11162 .and_then(|provider| {
11163 local
11164 .language_server_dynamic_registrations
11165 .entry(server_id)
11166 .or_default()
11167 .diagnostics
11168 .entry(None)
11169 .or_insert(provider.clone());
11170 let workspace_refresher =
11171 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11172
11173 Some((None, workspace_refresher))
11174 })
11175 .into_iter()
11176 .collect();
11177 local.language_servers.insert(
11178 server_id,
11179 LanguageServerState::Running {
11180 workspace_diagnostics_refresh_tasks,
11181 adapter: adapter.clone(),
11182 server: language_server.clone(),
11183 simulate_disk_based_diagnostics_completion: None,
11184 },
11185 );
11186 local
11187 .languages
11188 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11189 if let Some(file_ops_caps) = language_server
11190 .capabilities()
11191 .workspace
11192 .as_ref()
11193 .and_then(|ws| ws.file_operations.as_ref())
11194 {
11195 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11196 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11197 if did_rename_caps.or(will_rename_caps).is_some() {
11198 let watcher = RenamePathsWatchedForServer::default()
11199 .with_did_rename_patterns(did_rename_caps)
11200 .with_will_rename_patterns(will_rename_caps);
11201 local
11202 .language_server_paths_watched_for_rename
11203 .insert(server_id, watcher);
11204 }
11205 }
11206
11207 self.language_server_statuses.insert(
11208 server_id,
11209 LanguageServerStatus {
11210 name: language_server.name(),
11211 pending_work: Default::default(),
11212 has_pending_diagnostic_updates: false,
11213 progress_tokens: Default::default(),
11214 worktree: Some(key.worktree_id),
11215 binary: Some(language_server.binary().clone()),
11216 configuration: Some(language_server.configuration().clone()),
11217 workspace_folders: language_server.workspace_folders(),
11218 },
11219 );
11220
11221 cx.emit(LspStoreEvent::LanguageServerAdded(
11222 server_id,
11223 language_server.name(),
11224 Some(key.worktree_id),
11225 ));
11226
11227 let server_capabilities = language_server.capabilities();
11228 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11229 downstream_client
11230 .send(proto::StartLanguageServer {
11231 project_id: *project_id,
11232 server: Some(proto::LanguageServer {
11233 id: server_id.to_proto(),
11234 name: language_server.name().to_string(),
11235 worktree_id: Some(key.worktree_id.to_proto()),
11236 }),
11237 capabilities: serde_json::to_string(&server_capabilities)
11238 .expect("serializing server LSP capabilities"),
11239 })
11240 .log_err();
11241 }
11242 self.lsp_server_capabilities
11243 .insert(server_id, server_capabilities);
11244
11245 // Tell the language server about every open buffer in the worktree that matches the language.
11246 // Also check for buffers in worktrees that reused this server
11247 let mut worktrees_using_server = vec![key.worktree_id];
11248 if let Some(local) = self.as_local() {
11249 // Find all worktrees that have this server in their language server tree
11250 for (worktree_id, servers) in &local.lsp_tree.instances {
11251 if *worktree_id != key.worktree_id {
11252 for server_map in servers.roots.values() {
11253 if server_map
11254 .values()
11255 .any(|(node, _)| node.id() == Some(server_id))
11256 {
11257 worktrees_using_server.push(*worktree_id);
11258 }
11259 }
11260 }
11261 }
11262 }
11263
11264 let mut buffer_paths_registered = Vec::new();
11265 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11266 let mut lsp_adapters = HashMap::default();
11267 for buffer_handle in buffer_store.buffers() {
11268 let buffer = buffer_handle.read(cx);
11269 let file = match File::from_dyn(buffer.file()) {
11270 Some(file) => file,
11271 None => continue,
11272 };
11273 let language = match buffer.language() {
11274 Some(language) => language,
11275 None => continue,
11276 };
11277
11278 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11279 || !lsp_adapters
11280 .entry(language.name())
11281 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11282 .iter()
11283 .any(|a| a.name == key.name)
11284 {
11285 continue;
11286 }
11287 // didOpen
11288 let file = match file.as_local() {
11289 Some(file) => file,
11290 None => continue,
11291 };
11292
11293 let local = self.as_local_mut().unwrap();
11294
11295 let buffer_id = buffer.remote_id();
11296 if local.registered_buffers.contains_key(&buffer_id) {
11297 let versions = local
11298 .buffer_snapshots
11299 .entry(buffer_id)
11300 .or_default()
11301 .entry(server_id)
11302 .and_modify(|_| {
11303 assert!(
11304 false,
11305 "There should not be an existing snapshot for a newly inserted buffer"
11306 )
11307 })
11308 .or_insert_with(|| {
11309 vec![LspBufferSnapshot {
11310 version: 0,
11311 snapshot: buffer.text_snapshot(),
11312 }]
11313 });
11314
11315 let snapshot = versions.last().unwrap();
11316 let version = snapshot.version;
11317 let initial_snapshot = &snapshot.snapshot;
11318 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11319 language_server.register_buffer(
11320 uri,
11321 adapter.language_id(&language.name()),
11322 version,
11323 initial_snapshot.text(),
11324 );
11325 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11326 local
11327 .buffers_opened_in_servers
11328 .entry(buffer_id)
11329 .or_default()
11330 .insert(server_id);
11331 }
11332 buffer_handle.update(cx, |buffer, cx| {
11333 buffer.set_completion_triggers(
11334 server_id,
11335 language_server
11336 .capabilities()
11337 .completion_provider
11338 .as_ref()
11339 .and_then(|provider| {
11340 provider
11341 .trigger_characters
11342 .as_ref()
11343 .map(|characters| characters.iter().cloned().collect())
11344 })
11345 .unwrap_or_default(),
11346 cx,
11347 )
11348 });
11349 }
11350 });
11351
11352 for (buffer_id, abs_path) in buffer_paths_registered {
11353 cx.emit(LspStoreEvent::LanguageServerUpdate {
11354 language_server_id: server_id,
11355 name: Some(adapter.name()),
11356 message: proto::update_language_server::Variant::RegisteredForBuffer(
11357 proto::RegisteredForBuffer {
11358 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11359 buffer_id: buffer_id.to_proto(),
11360 },
11361 ),
11362 });
11363 }
11364
11365 cx.notify();
11366 }
11367
11368 pub fn language_servers_running_disk_based_diagnostics(
11369 &self,
11370 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11371 self.language_server_statuses
11372 .iter()
11373 .filter_map(|(id, status)| {
11374 if status.has_pending_diagnostic_updates {
11375 Some(*id)
11376 } else {
11377 None
11378 }
11379 })
11380 }
11381
11382 pub(crate) fn cancel_language_server_work_for_buffers(
11383 &mut self,
11384 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11385 cx: &mut Context<Self>,
11386 ) {
11387 if let Some((client, project_id)) = self.upstream_client() {
11388 let request = client.request(proto::CancelLanguageServerWork {
11389 project_id,
11390 work: Some(proto::cancel_language_server_work::Work::Buffers(
11391 proto::cancel_language_server_work::Buffers {
11392 buffer_ids: buffers
11393 .into_iter()
11394 .map(|b| b.read(cx).remote_id().to_proto())
11395 .collect(),
11396 },
11397 )),
11398 });
11399 cx.background_spawn(request).detach_and_log_err(cx);
11400 } else if let Some(local) = self.as_local() {
11401 let servers = buffers
11402 .into_iter()
11403 .flat_map(|buffer| {
11404 buffer.update(cx, |buffer, cx| {
11405 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11406 })
11407 })
11408 .collect::<HashSet<_>>();
11409 for server_id in servers {
11410 self.cancel_language_server_work(server_id, None, cx);
11411 }
11412 }
11413 }
11414
11415 pub(crate) fn cancel_language_server_work(
11416 &mut self,
11417 server_id: LanguageServerId,
11418 token_to_cancel: Option<ProgressToken>,
11419 cx: &mut Context<Self>,
11420 ) {
11421 if let Some(local) = self.as_local() {
11422 let status = self.language_server_statuses.get(&server_id);
11423 let server = local.language_servers.get(&server_id);
11424 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11425 {
11426 for (token, progress) in &status.pending_work {
11427 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11428 && token != token_to_cancel
11429 {
11430 continue;
11431 }
11432 if progress.is_cancellable {
11433 server
11434 .notify::<lsp::notification::WorkDoneProgressCancel>(
11435 WorkDoneProgressCancelParams {
11436 token: token.to_lsp(),
11437 },
11438 )
11439 .ok();
11440 }
11441 }
11442 }
11443 } else if let Some((client, project_id)) = self.upstream_client() {
11444 let request = client.request(proto::CancelLanguageServerWork {
11445 project_id,
11446 work: Some(
11447 proto::cancel_language_server_work::Work::LanguageServerWork(
11448 proto::cancel_language_server_work::LanguageServerWork {
11449 language_server_id: server_id.to_proto(),
11450 token: token_to_cancel.map(|token| token.to_proto()),
11451 },
11452 ),
11453 ),
11454 });
11455 cx.background_spawn(request).detach_and_log_err(cx);
11456 }
11457 }
11458
11459 fn register_supplementary_language_server(
11460 &mut self,
11461 id: LanguageServerId,
11462 name: LanguageServerName,
11463 server: Arc<LanguageServer>,
11464 cx: &mut Context<Self>,
11465 ) {
11466 if let Some(local) = self.as_local_mut() {
11467 local
11468 .supplementary_language_servers
11469 .insert(id, (name.clone(), server));
11470 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11471 }
11472 }
11473
11474 fn unregister_supplementary_language_server(
11475 &mut self,
11476 id: LanguageServerId,
11477 cx: &mut Context<Self>,
11478 ) {
11479 if let Some(local) = self.as_local_mut() {
11480 local.supplementary_language_servers.remove(&id);
11481 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11482 }
11483 }
11484
11485 pub(crate) fn supplementary_language_servers(
11486 &self,
11487 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11488 self.as_local().into_iter().flat_map(|local| {
11489 local
11490 .supplementary_language_servers
11491 .iter()
11492 .map(|(id, (name, _))| (*id, name.clone()))
11493 })
11494 }
11495
11496 pub fn language_server_adapter_for_id(
11497 &self,
11498 id: LanguageServerId,
11499 ) -> Option<Arc<CachedLspAdapter>> {
11500 self.as_local()
11501 .and_then(|local| local.language_servers.get(&id))
11502 .and_then(|language_server_state| match language_server_state {
11503 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11504 _ => None,
11505 })
11506 }
11507
11508 pub(super) fn update_local_worktree_language_servers(
11509 &mut self,
11510 worktree_handle: &Entity<Worktree>,
11511 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11512 cx: &mut Context<Self>,
11513 ) {
11514 if changes.is_empty() {
11515 return;
11516 }
11517
11518 let Some(local) = self.as_local() else { return };
11519
11520 local.prettier_store.update(cx, |prettier_store, cx| {
11521 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11522 });
11523
11524 let worktree_id = worktree_handle.read(cx).id();
11525 let mut language_server_ids = local
11526 .language_server_ids
11527 .iter()
11528 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11529 .collect::<Vec<_>>();
11530 language_server_ids.sort();
11531 language_server_ids.dedup();
11532
11533 // let abs_path = worktree_handle.read(cx).abs_path();
11534 for server_id in &language_server_ids {
11535 if let Some(LanguageServerState::Running { server, .. }) =
11536 local.language_servers.get(server_id)
11537 && let Some(watched_paths) = local
11538 .language_server_watched_paths
11539 .get(server_id)
11540 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11541 {
11542 let params = lsp::DidChangeWatchedFilesParams {
11543 changes: changes
11544 .iter()
11545 .filter_map(|(path, _, change)| {
11546 if !watched_paths.is_match(path.as_std_path()) {
11547 return None;
11548 }
11549 let typ = match change {
11550 PathChange::Loaded => return None,
11551 PathChange::Added => lsp::FileChangeType::CREATED,
11552 PathChange::Removed => lsp::FileChangeType::DELETED,
11553 PathChange::Updated => lsp::FileChangeType::CHANGED,
11554 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11555 };
11556 let uri = lsp::Uri::from_file_path(
11557 worktree_handle.read(cx).absolutize(&path),
11558 )
11559 .ok()?;
11560 Some(lsp::FileEvent { uri, typ })
11561 })
11562 .collect(),
11563 };
11564 if !params.changes.is_empty() {
11565 server
11566 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11567 .ok();
11568 }
11569 }
11570 }
11571 for (path, _, _) in changes {
11572 if let Some(file_name) = path.file_name()
11573 && local.watched_manifest_filenames.contains(file_name)
11574 {
11575 self.request_workspace_config_refresh();
11576 break;
11577 }
11578 }
11579 }
11580
11581 pub fn wait_for_remote_buffer(
11582 &mut self,
11583 id: BufferId,
11584 cx: &mut Context<Self>,
11585 ) -> Task<Result<Entity<Buffer>>> {
11586 self.buffer_store.update(cx, |buffer_store, cx| {
11587 buffer_store.wait_for_remote_buffer(id, cx)
11588 })
11589 }
11590
11591 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11592 let mut result = proto::Symbol {
11593 language_server_name: symbol.language_server_name.0.to_string(),
11594 source_worktree_id: symbol.source_worktree_id.to_proto(),
11595 language_server_id: symbol.source_language_server_id.to_proto(),
11596 name: symbol.name.clone(),
11597 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11598 start: Some(proto::PointUtf16 {
11599 row: symbol.range.start.0.row,
11600 column: symbol.range.start.0.column,
11601 }),
11602 end: Some(proto::PointUtf16 {
11603 row: symbol.range.end.0.row,
11604 column: symbol.range.end.0.column,
11605 }),
11606 worktree_id: Default::default(),
11607 path: Default::default(),
11608 signature: Default::default(),
11609 };
11610 match &symbol.path {
11611 SymbolLocation::InProject(path) => {
11612 result.worktree_id = path.worktree_id.to_proto();
11613 result.path = path.path.to_proto();
11614 }
11615 SymbolLocation::OutsideProject {
11616 abs_path,
11617 signature,
11618 } => {
11619 result.path = abs_path.to_string_lossy().into_owned();
11620 result.signature = signature.to_vec();
11621 }
11622 }
11623 result
11624 }
11625
11626 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11627 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11628 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11629 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11630
11631 let path = if serialized_symbol.signature.is_empty() {
11632 SymbolLocation::InProject(ProjectPath {
11633 worktree_id,
11634 path: RelPath::from_proto(&serialized_symbol.path)
11635 .context("invalid symbol path")?,
11636 })
11637 } else {
11638 SymbolLocation::OutsideProject {
11639 abs_path: Path::new(&serialized_symbol.path).into(),
11640 signature: serialized_symbol
11641 .signature
11642 .try_into()
11643 .map_err(|_| anyhow!("invalid signature"))?,
11644 }
11645 };
11646
11647 let start = serialized_symbol.start.context("invalid start")?;
11648 let end = serialized_symbol.end.context("invalid end")?;
11649 Ok(CoreSymbol {
11650 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11651 source_worktree_id,
11652 source_language_server_id: LanguageServerId::from_proto(
11653 serialized_symbol.language_server_id,
11654 ),
11655 path,
11656 name: serialized_symbol.name,
11657 range: Unclipped(PointUtf16::new(start.row, start.column))
11658 ..Unclipped(PointUtf16::new(end.row, end.column)),
11659 kind,
11660 })
11661 }
11662
11663 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11664 let mut serialized_completion = proto::Completion {
11665 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11666 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11667 new_text: completion.new_text.clone(),
11668 ..proto::Completion::default()
11669 };
11670 match &completion.source {
11671 CompletionSource::Lsp {
11672 insert_range,
11673 server_id,
11674 lsp_completion,
11675 lsp_defaults,
11676 resolved,
11677 } => {
11678 let (old_insert_start, old_insert_end) = insert_range
11679 .as_ref()
11680 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11681 .unzip();
11682
11683 serialized_completion.old_insert_start = old_insert_start;
11684 serialized_completion.old_insert_end = old_insert_end;
11685 serialized_completion.source = proto::completion::Source::Lsp as i32;
11686 serialized_completion.server_id = server_id.0 as u64;
11687 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11688 serialized_completion.lsp_defaults = lsp_defaults
11689 .as_deref()
11690 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11691 serialized_completion.resolved = *resolved;
11692 }
11693 CompletionSource::BufferWord {
11694 word_range,
11695 resolved,
11696 } => {
11697 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11698 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11699 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11700 serialized_completion.resolved = *resolved;
11701 }
11702 CompletionSource::Custom => {
11703 serialized_completion.source = proto::completion::Source::Custom as i32;
11704 serialized_completion.resolved = true;
11705 }
11706 CompletionSource::Dap { sort_text } => {
11707 serialized_completion.source = proto::completion::Source::Dap as i32;
11708 serialized_completion.sort_text = Some(sort_text.clone());
11709 }
11710 }
11711
11712 serialized_completion
11713 }
11714
11715 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11716 let old_replace_start = completion
11717 .old_replace_start
11718 .and_then(deserialize_anchor)
11719 .context("invalid old start")?;
11720 let old_replace_end = completion
11721 .old_replace_end
11722 .and_then(deserialize_anchor)
11723 .context("invalid old end")?;
11724 let insert_range = {
11725 match completion.old_insert_start.zip(completion.old_insert_end) {
11726 Some((start, end)) => {
11727 let start = deserialize_anchor(start).context("invalid insert old start")?;
11728 let end = deserialize_anchor(end).context("invalid insert old end")?;
11729 Some(start..end)
11730 }
11731 None => None,
11732 }
11733 };
11734 Ok(CoreCompletion {
11735 replace_range: old_replace_start..old_replace_end,
11736 new_text: completion.new_text,
11737 source: match proto::completion::Source::from_i32(completion.source) {
11738 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11739 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11740 insert_range,
11741 server_id: LanguageServerId::from_proto(completion.server_id),
11742 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11743 lsp_defaults: completion
11744 .lsp_defaults
11745 .as_deref()
11746 .map(serde_json::from_slice)
11747 .transpose()?,
11748 resolved: completion.resolved,
11749 },
11750 Some(proto::completion::Source::BufferWord) => {
11751 let word_range = completion
11752 .buffer_word_start
11753 .and_then(deserialize_anchor)
11754 .context("invalid buffer word start")?
11755 ..completion
11756 .buffer_word_end
11757 .and_then(deserialize_anchor)
11758 .context("invalid buffer word end")?;
11759 CompletionSource::BufferWord {
11760 word_range,
11761 resolved: completion.resolved,
11762 }
11763 }
11764 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11765 sort_text: completion
11766 .sort_text
11767 .context("expected sort text to exist")?,
11768 },
11769 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11770 },
11771 })
11772 }
11773
11774 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11775 let (kind, lsp_action) = match &action.lsp_action {
11776 LspAction::Action(code_action) => (
11777 proto::code_action::Kind::Action as i32,
11778 serde_json::to_vec(code_action).unwrap(),
11779 ),
11780 LspAction::Command(command) => (
11781 proto::code_action::Kind::Command as i32,
11782 serde_json::to_vec(command).unwrap(),
11783 ),
11784 LspAction::CodeLens(code_lens) => (
11785 proto::code_action::Kind::CodeLens as i32,
11786 serde_json::to_vec(code_lens).unwrap(),
11787 ),
11788 };
11789
11790 proto::CodeAction {
11791 server_id: action.server_id.0 as u64,
11792 start: Some(serialize_anchor(&action.range.start)),
11793 end: Some(serialize_anchor(&action.range.end)),
11794 lsp_action,
11795 kind,
11796 resolved: action.resolved,
11797 }
11798 }
11799
11800 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11801 let start = action
11802 .start
11803 .and_then(deserialize_anchor)
11804 .context("invalid start")?;
11805 let end = action
11806 .end
11807 .and_then(deserialize_anchor)
11808 .context("invalid end")?;
11809 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11810 Some(proto::code_action::Kind::Action) => {
11811 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11812 }
11813 Some(proto::code_action::Kind::Command) => {
11814 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11815 }
11816 Some(proto::code_action::Kind::CodeLens) => {
11817 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11818 }
11819 None => anyhow::bail!("Unknown action kind {}", action.kind),
11820 };
11821 Ok(CodeAction {
11822 server_id: LanguageServerId(action.server_id as usize),
11823 range: start..end,
11824 resolved: action.resolved,
11825 lsp_action,
11826 })
11827 }
11828
11829 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11830 match &formatting_result {
11831 Ok(_) => self.last_formatting_failure = None,
11832 Err(error) => {
11833 let error_string = format!("{error:#}");
11834 log::error!("Formatting failed: {error_string}");
11835 self.last_formatting_failure
11836 .replace(error_string.lines().join(" "));
11837 }
11838 }
11839 }
11840
11841 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11842 self.lsp_server_capabilities.remove(&for_server);
11843 for lsp_data in self.lsp_data.values_mut() {
11844 lsp_data.remove_server_data(for_server);
11845 }
11846 if let Some(local) = self.as_local_mut() {
11847 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11848 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11849 buffer_servers.remove(&for_server);
11850 }
11851 }
11852 }
11853
11854 pub fn result_id(
11855 &self,
11856 server_id: LanguageServerId,
11857 buffer_id: BufferId,
11858 cx: &App,
11859 ) -> Option<String> {
11860 let abs_path = self
11861 .buffer_store
11862 .read(cx)
11863 .get(buffer_id)
11864 .and_then(|b| File::from_dyn(b.read(cx).file()))
11865 .map(|f| f.abs_path(cx))?;
11866 self.as_local()?
11867 .buffer_pull_diagnostics_result_ids
11868 .get(&server_id)?
11869 .get(&abs_path)?
11870 .clone()
11871 }
11872
11873 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11874 let Some(local) = self.as_local() else {
11875 return HashMap::default();
11876 };
11877 local
11878 .buffer_pull_diagnostics_result_ids
11879 .get(&server_id)
11880 .into_iter()
11881 .flatten()
11882 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11883 .collect()
11884 }
11885
11886 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11887 if let Some(LanguageServerState::Running {
11888 workspace_diagnostics_refresh_tasks,
11889 ..
11890 }) = self
11891 .as_local_mut()
11892 .and_then(|local| local.language_servers.get_mut(&server_id))
11893 {
11894 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11895 diagnostics.refresh_tx.try_send(()).ok();
11896 }
11897 }
11898 }
11899
11900 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11901 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11902 return;
11903 };
11904 let Some(local) = self.as_local_mut() else {
11905 return;
11906 };
11907
11908 for server_id in buffer.update(cx, |buffer, cx| {
11909 local.language_server_ids_for_buffer(buffer, cx)
11910 }) {
11911 if let Some(LanguageServerState::Running {
11912 workspace_diagnostics_refresh_tasks,
11913 ..
11914 }) = local.language_servers.get_mut(&server_id)
11915 {
11916 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11917 diagnostics.refresh_tx.try_send(()).ok();
11918 }
11919 }
11920 }
11921 }
11922
11923 fn apply_workspace_diagnostic_report(
11924 &mut self,
11925 server_id: LanguageServerId,
11926 report: lsp::WorkspaceDiagnosticReportResult,
11927 cx: &mut Context<Self>,
11928 ) {
11929 let workspace_diagnostics =
11930 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11931 let mut unchanged_buffers = HashSet::default();
11932 let mut changed_buffers = HashSet::default();
11933 let workspace_diagnostics_updates = workspace_diagnostics
11934 .into_iter()
11935 .filter_map(
11936 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11937 LspPullDiagnostics::Response {
11938 server_id,
11939 uri,
11940 diagnostics,
11941 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11942 LspPullDiagnostics::Default => None,
11943 },
11944 )
11945 .fold(
11946 HashMap::default(),
11947 |mut acc, (server_id, uri, diagnostics, version)| {
11948 let (result_id, diagnostics) = match diagnostics {
11949 PulledDiagnostics::Unchanged { result_id } => {
11950 unchanged_buffers.insert(uri.clone());
11951 (Some(result_id), Vec::new())
11952 }
11953 PulledDiagnostics::Changed {
11954 result_id,
11955 diagnostics,
11956 } => {
11957 changed_buffers.insert(uri.clone());
11958 (result_id, diagnostics)
11959 }
11960 };
11961 let disk_based_sources = Cow::Owned(
11962 self.language_server_adapter_for_id(server_id)
11963 .as_ref()
11964 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11965 .unwrap_or(&[])
11966 .to_vec(),
11967 );
11968 acc.entry(server_id)
11969 .or_insert_with(Vec::new)
11970 .push(DocumentDiagnosticsUpdate {
11971 server_id,
11972 diagnostics: lsp::PublishDiagnosticsParams {
11973 uri,
11974 diagnostics,
11975 version,
11976 },
11977 result_id,
11978 disk_based_sources,
11979 });
11980 acc
11981 },
11982 );
11983
11984 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11985 self.merge_lsp_diagnostics(
11986 DiagnosticSourceKind::Pulled,
11987 diagnostic_updates,
11988 |buffer, old_diagnostic, cx| {
11989 File::from_dyn(buffer.file())
11990 .and_then(|file| {
11991 let abs_path = file.as_local()?.abs_path(cx);
11992 lsp::Uri::from_file_path(abs_path).ok()
11993 })
11994 .is_none_or(|buffer_uri| {
11995 unchanged_buffers.contains(&buffer_uri)
11996 || match old_diagnostic.source_kind {
11997 DiagnosticSourceKind::Pulled => {
11998 !changed_buffers.contains(&buffer_uri)
11999 }
12000 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
12001 true
12002 }
12003 }
12004 })
12005 },
12006 cx,
12007 )
12008 .log_err();
12009 }
12010 }
12011
12012 fn register_server_capabilities(
12013 &mut self,
12014 server_id: LanguageServerId,
12015 params: lsp::RegistrationParams,
12016 cx: &mut Context<Self>,
12017 ) -> anyhow::Result<()> {
12018 let server = self
12019 .language_server_for_id(server_id)
12020 .with_context(|| format!("no server {server_id} found"))?;
12021 for reg in params.registrations {
12022 match reg.method.as_str() {
12023 "workspace/didChangeWatchedFiles" => {
12024 if let Some(options) = reg.register_options {
12025 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12026 let caps = serde_json::from_value(options)?;
12027 local_lsp_store
12028 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12029 true
12030 } else {
12031 false
12032 };
12033 if notify {
12034 notify_server_capabilities_updated(&server, cx);
12035 }
12036 }
12037 }
12038 "workspace/didChangeConfiguration" => {
12039 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12040 }
12041 "workspace/didChangeWorkspaceFolders" => {
12042 // In this case register options is an empty object, we can ignore it
12043 let caps = lsp::WorkspaceFoldersServerCapabilities {
12044 supported: Some(true),
12045 change_notifications: Some(OneOf::Right(reg.id)),
12046 };
12047 server.update_capabilities(|capabilities| {
12048 capabilities
12049 .workspace
12050 .get_or_insert_default()
12051 .workspace_folders = Some(caps);
12052 });
12053 notify_server_capabilities_updated(&server, cx);
12054 }
12055 "workspace/symbol" => {
12056 let options = parse_register_capabilities(reg)?;
12057 server.update_capabilities(|capabilities| {
12058 capabilities.workspace_symbol_provider = Some(options);
12059 });
12060 notify_server_capabilities_updated(&server, cx);
12061 }
12062 "workspace/fileOperations" => {
12063 if let Some(options) = reg.register_options {
12064 let caps = serde_json::from_value(options)?;
12065 server.update_capabilities(|capabilities| {
12066 capabilities
12067 .workspace
12068 .get_or_insert_default()
12069 .file_operations = Some(caps);
12070 });
12071 notify_server_capabilities_updated(&server, cx);
12072 }
12073 }
12074 "workspace/executeCommand" => {
12075 if let Some(options) = reg.register_options {
12076 let options = serde_json::from_value(options)?;
12077 server.update_capabilities(|capabilities| {
12078 capabilities.execute_command_provider = Some(options);
12079 });
12080 notify_server_capabilities_updated(&server, cx);
12081 }
12082 }
12083 "textDocument/rangeFormatting" => {
12084 let options = parse_register_capabilities(reg)?;
12085 server.update_capabilities(|capabilities| {
12086 capabilities.document_range_formatting_provider = Some(options);
12087 });
12088 notify_server_capabilities_updated(&server, cx);
12089 }
12090 "textDocument/onTypeFormatting" => {
12091 if let Some(options) = reg
12092 .register_options
12093 .map(serde_json::from_value)
12094 .transpose()?
12095 {
12096 server.update_capabilities(|capabilities| {
12097 capabilities.document_on_type_formatting_provider = Some(options);
12098 });
12099 notify_server_capabilities_updated(&server, cx);
12100 }
12101 }
12102 "textDocument/formatting" => {
12103 let options = parse_register_capabilities(reg)?;
12104 server.update_capabilities(|capabilities| {
12105 capabilities.document_formatting_provider = Some(options);
12106 });
12107 notify_server_capabilities_updated(&server, cx);
12108 }
12109 "textDocument/rename" => {
12110 let options = parse_register_capabilities(reg)?;
12111 server.update_capabilities(|capabilities| {
12112 capabilities.rename_provider = Some(options);
12113 });
12114 notify_server_capabilities_updated(&server, cx);
12115 }
12116 "textDocument/inlayHint" => {
12117 let options = parse_register_capabilities(reg)?;
12118 server.update_capabilities(|capabilities| {
12119 capabilities.inlay_hint_provider = Some(options);
12120 });
12121 notify_server_capabilities_updated(&server, cx);
12122 }
12123 "textDocument/documentSymbol" => {
12124 let options = parse_register_capabilities(reg)?;
12125 server.update_capabilities(|capabilities| {
12126 capabilities.document_symbol_provider = Some(options);
12127 });
12128 notify_server_capabilities_updated(&server, cx);
12129 }
12130 "textDocument/codeAction" => {
12131 let options = parse_register_capabilities(reg)?;
12132 let provider = match options {
12133 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12134 OneOf::Right(caps) => caps,
12135 };
12136 server.update_capabilities(|capabilities| {
12137 capabilities.code_action_provider = Some(provider);
12138 });
12139 notify_server_capabilities_updated(&server, cx);
12140 }
12141 "textDocument/definition" => {
12142 let options = parse_register_capabilities(reg)?;
12143 server.update_capabilities(|capabilities| {
12144 capabilities.definition_provider = Some(options);
12145 });
12146 notify_server_capabilities_updated(&server, cx);
12147 }
12148 "textDocument/completion" => {
12149 if let Some(caps) = reg
12150 .register_options
12151 .map(serde_json::from_value::<CompletionOptions>)
12152 .transpose()?
12153 {
12154 server.update_capabilities(|capabilities| {
12155 capabilities.completion_provider = Some(caps.clone());
12156 });
12157
12158 if let Some(local) = self.as_local() {
12159 let mut buffers_with_language_server = Vec::new();
12160 for handle in self.buffer_store.read(cx).buffers() {
12161 let buffer_id = handle.read(cx).remote_id();
12162 if local
12163 .buffers_opened_in_servers
12164 .get(&buffer_id)
12165 .filter(|s| s.contains(&server_id))
12166 .is_some()
12167 {
12168 buffers_with_language_server.push(handle);
12169 }
12170 }
12171 let triggers = caps
12172 .trigger_characters
12173 .unwrap_or_default()
12174 .into_iter()
12175 .collect::<BTreeSet<_>>();
12176 for handle in buffers_with_language_server {
12177 let triggers = triggers.clone();
12178 let _ = handle.update(cx, move |buffer, cx| {
12179 buffer.set_completion_triggers(server_id, triggers, cx);
12180 });
12181 }
12182 }
12183 notify_server_capabilities_updated(&server, cx);
12184 }
12185 }
12186 "textDocument/hover" => {
12187 let options = parse_register_capabilities(reg)?;
12188 let provider = match options {
12189 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12190 OneOf::Right(caps) => caps,
12191 };
12192 server.update_capabilities(|capabilities| {
12193 capabilities.hover_provider = Some(provider);
12194 });
12195 notify_server_capabilities_updated(&server, cx);
12196 }
12197 "textDocument/signatureHelp" => {
12198 if let Some(caps) = reg
12199 .register_options
12200 .map(serde_json::from_value)
12201 .transpose()?
12202 {
12203 server.update_capabilities(|capabilities| {
12204 capabilities.signature_help_provider = Some(caps);
12205 });
12206 notify_server_capabilities_updated(&server, cx);
12207 }
12208 }
12209 "textDocument/didChange" => {
12210 if let Some(sync_kind) = reg
12211 .register_options
12212 .and_then(|opts| opts.get("syncKind").cloned())
12213 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12214 .transpose()?
12215 {
12216 server.update_capabilities(|capabilities| {
12217 let mut sync_options =
12218 Self::take_text_document_sync_options(capabilities);
12219 sync_options.change = Some(sync_kind);
12220 capabilities.text_document_sync =
12221 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12222 });
12223 notify_server_capabilities_updated(&server, cx);
12224 }
12225 }
12226 "textDocument/didSave" => {
12227 if let Some(include_text) = reg
12228 .register_options
12229 .map(|opts| {
12230 let transpose = opts
12231 .get("includeText")
12232 .cloned()
12233 .map(serde_json::from_value::<Option<bool>>)
12234 .transpose();
12235 match transpose {
12236 Ok(value) => Ok(value.flatten()),
12237 Err(e) => Err(e),
12238 }
12239 })
12240 .transpose()?
12241 {
12242 server.update_capabilities(|capabilities| {
12243 let mut sync_options =
12244 Self::take_text_document_sync_options(capabilities);
12245 sync_options.save =
12246 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12247 include_text,
12248 }));
12249 capabilities.text_document_sync =
12250 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12251 });
12252 notify_server_capabilities_updated(&server, cx);
12253 }
12254 }
12255 "textDocument/codeLens" => {
12256 if let Some(caps) = reg
12257 .register_options
12258 .map(serde_json::from_value)
12259 .transpose()?
12260 {
12261 server.update_capabilities(|capabilities| {
12262 capabilities.code_lens_provider = Some(caps);
12263 });
12264 notify_server_capabilities_updated(&server, cx);
12265 }
12266 }
12267 "textDocument/diagnostic" => {
12268 if let Some(caps) = reg
12269 .register_options
12270 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12271 .transpose()?
12272 {
12273 let local = self
12274 .as_local_mut()
12275 .context("Expected LSP Store to be local")?;
12276 let state = local
12277 .language_servers
12278 .get_mut(&server_id)
12279 .context("Could not obtain Language Servers state")?;
12280 local
12281 .language_server_dynamic_registrations
12282 .entry(server_id)
12283 .or_default()
12284 .diagnostics
12285 .insert(Some(reg.id.clone()), caps.clone());
12286
12287 if let LanguageServerState::Running {
12288 workspace_diagnostics_refresh_tasks,
12289 ..
12290 } = state
12291 && let Some(task) = lsp_workspace_diagnostics_refresh(
12292 Some(reg.id.clone()),
12293 caps.clone(),
12294 server.clone(),
12295 cx,
12296 )
12297 {
12298 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12299 }
12300
12301 let mut did_update_caps = false;
12302 server.update_capabilities(|capabilities| {
12303 if capabilities.diagnostic_provider.as_ref().is_none_or(
12304 |current_caps| {
12305 let supports_workspace_diagnostics =
12306 |capabilities: &DiagnosticServerCapabilities| {
12307 match capabilities {
12308 DiagnosticServerCapabilities::Options(
12309 diagnostic_options,
12310 ) => diagnostic_options.workspace_diagnostics,
12311 DiagnosticServerCapabilities::RegistrationOptions(
12312 diagnostic_registration_options,
12313 ) => {
12314 diagnostic_registration_options
12315 .diagnostic_options
12316 .workspace_diagnostics
12317 }
12318 }
12319 };
12320 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12321 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12322 // as it'll think that they're not supported.
12323 // If we did not support any workspace diagnostics up to this point but now do, let's update.
12324 !supports_workspace_diagnostics(current_caps)
12325 & supports_workspace_diagnostics(&caps)
12326 },
12327 ) {
12328 did_update_caps = true;
12329 capabilities.diagnostic_provider = Some(caps);
12330 }
12331 });
12332 if did_update_caps {
12333 notify_server_capabilities_updated(&server, cx);
12334 }
12335 }
12336 }
12337 "textDocument/documentColor" => {
12338 let options = parse_register_capabilities(reg)?;
12339 let provider = match options {
12340 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12341 OneOf::Right(caps) => caps,
12342 };
12343 server.update_capabilities(|capabilities| {
12344 capabilities.color_provider = Some(provider);
12345 });
12346 notify_server_capabilities_updated(&server, cx);
12347 }
12348 _ => log::warn!("unhandled capability registration: {reg:?}"),
12349 }
12350 }
12351
12352 Ok(())
12353 }
12354
12355 fn unregister_server_capabilities(
12356 &mut self,
12357 server_id: LanguageServerId,
12358 params: lsp::UnregistrationParams,
12359 cx: &mut Context<Self>,
12360 ) -> anyhow::Result<()> {
12361 let server = self
12362 .language_server_for_id(server_id)
12363 .with_context(|| format!("no server {server_id} found"))?;
12364 for unreg in params.unregisterations.iter() {
12365 match unreg.method.as_str() {
12366 "workspace/didChangeWatchedFiles" => {
12367 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12368 local_lsp_store
12369 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12370 true
12371 } else {
12372 false
12373 };
12374 if notify {
12375 notify_server_capabilities_updated(&server, cx);
12376 }
12377 }
12378 "workspace/didChangeConfiguration" => {
12379 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12380 }
12381 "workspace/didChangeWorkspaceFolders" => {
12382 server.update_capabilities(|capabilities| {
12383 capabilities
12384 .workspace
12385 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12386 workspace_folders: None,
12387 file_operations: None,
12388 })
12389 .workspace_folders = None;
12390 });
12391 notify_server_capabilities_updated(&server, cx);
12392 }
12393 "workspace/symbol" => {
12394 server.update_capabilities(|capabilities| {
12395 capabilities.workspace_symbol_provider = None
12396 });
12397 notify_server_capabilities_updated(&server, cx);
12398 }
12399 "workspace/fileOperations" => {
12400 server.update_capabilities(|capabilities| {
12401 capabilities
12402 .workspace
12403 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12404 workspace_folders: None,
12405 file_operations: None,
12406 })
12407 .file_operations = None;
12408 });
12409 notify_server_capabilities_updated(&server, cx);
12410 }
12411 "workspace/executeCommand" => {
12412 server.update_capabilities(|capabilities| {
12413 capabilities.execute_command_provider = None;
12414 });
12415 notify_server_capabilities_updated(&server, cx);
12416 }
12417 "textDocument/rangeFormatting" => {
12418 server.update_capabilities(|capabilities| {
12419 capabilities.document_range_formatting_provider = None
12420 });
12421 notify_server_capabilities_updated(&server, cx);
12422 }
12423 "textDocument/onTypeFormatting" => {
12424 server.update_capabilities(|capabilities| {
12425 capabilities.document_on_type_formatting_provider = None;
12426 });
12427 notify_server_capabilities_updated(&server, cx);
12428 }
12429 "textDocument/formatting" => {
12430 server.update_capabilities(|capabilities| {
12431 capabilities.document_formatting_provider = None;
12432 });
12433 notify_server_capabilities_updated(&server, cx);
12434 }
12435 "textDocument/rename" => {
12436 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12437 notify_server_capabilities_updated(&server, cx);
12438 }
12439 "textDocument/codeAction" => {
12440 server.update_capabilities(|capabilities| {
12441 capabilities.code_action_provider = None;
12442 });
12443 notify_server_capabilities_updated(&server, cx);
12444 }
12445 "textDocument/definition" => {
12446 server.update_capabilities(|capabilities| {
12447 capabilities.definition_provider = None;
12448 });
12449 notify_server_capabilities_updated(&server, cx);
12450 }
12451 "textDocument/completion" => {
12452 server.update_capabilities(|capabilities| {
12453 capabilities.completion_provider = None;
12454 });
12455 notify_server_capabilities_updated(&server, cx);
12456 }
12457 "textDocument/hover" => {
12458 server.update_capabilities(|capabilities| {
12459 capabilities.hover_provider = None;
12460 });
12461 notify_server_capabilities_updated(&server, cx);
12462 }
12463 "textDocument/signatureHelp" => {
12464 server.update_capabilities(|capabilities| {
12465 capabilities.signature_help_provider = None;
12466 });
12467 notify_server_capabilities_updated(&server, cx);
12468 }
12469 "textDocument/didChange" => {
12470 server.update_capabilities(|capabilities| {
12471 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12472 sync_options.change = None;
12473 capabilities.text_document_sync =
12474 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12475 });
12476 notify_server_capabilities_updated(&server, cx);
12477 }
12478 "textDocument/didSave" => {
12479 server.update_capabilities(|capabilities| {
12480 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12481 sync_options.save = None;
12482 capabilities.text_document_sync =
12483 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12484 });
12485 notify_server_capabilities_updated(&server, cx);
12486 }
12487 "textDocument/codeLens" => {
12488 server.update_capabilities(|capabilities| {
12489 capabilities.code_lens_provider = None;
12490 });
12491 notify_server_capabilities_updated(&server, cx);
12492 }
12493 "textDocument/diagnostic" => {
12494 let local = self
12495 .as_local_mut()
12496 .context("Expected LSP Store to be local")?;
12497
12498 let state = local
12499 .language_servers
12500 .get_mut(&server_id)
12501 .context("Could not obtain Language Servers state")?;
12502 let options = local
12503 .language_server_dynamic_registrations
12504 .get_mut(&server_id)
12505 .with_context(|| {
12506 format!("Expected dynamic registration to exist for server {server_id}")
12507 })?.diagnostics
12508 .remove(&Some(unreg.id.clone()))
12509 .with_context(|| format!(
12510 "Attempted to unregister non-existent diagnostic registration with ID {}",
12511 unreg.id)
12512 )?;
12513
12514 let mut has_any_diagnostic_providers_still = true;
12515 if let Some(identifier) = diagnostic_identifier(&options)
12516 && let LanguageServerState::Running {
12517 workspace_diagnostics_refresh_tasks,
12518 ..
12519 } = state
12520 {
12521 workspace_diagnostics_refresh_tasks.remove(&identifier);
12522 has_any_diagnostic_providers_still =
12523 !workspace_diagnostics_refresh_tasks.is_empty();
12524 }
12525
12526 if !has_any_diagnostic_providers_still {
12527 server.update_capabilities(|capabilities| {
12528 debug_assert!(capabilities.diagnostic_provider.is_some());
12529 capabilities.diagnostic_provider = None;
12530 });
12531 }
12532
12533 notify_server_capabilities_updated(&server, cx);
12534 }
12535 "textDocument/documentColor" => {
12536 server.update_capabilities(|capabilities| {
12537 capabilities.color_provider = None;
12538 });
12539 notify_server_capabilities_updated(&server, cx);
12540 }
12541 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12542 }
12543 }
12544
12545 Ok(())
12546 }
12547
12548 async fn deduplicate_range_based_lsp_requests<T>(
12549 lsp_store: &Entity<Self>,
12550 server_id: Option<LanguageServerId>,
12551 lsp_request_id: LspRequestId,
12552 proto_request: &T::ProtoRequest,
12553 range: Range<Anchor>,
12554 cx: &mut AsyncApp,
12555 ) -> Result<()>
12556 where
12557 T: LspCommand,
12558 T::ProtoRequest: proto::LspRequestMessage,
12559 {
12560 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12561 let version = deserialize_version(proto_request.buffer_version());
12562 let buffer = lsp_store.update(cx, |this, cx| {
12563 this.buffer_store.read(cx).get_existing(buffer_id)
12564 })??;
12565 buffer
12566 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12567 .await?;
12568 lsp_store.update(cx, |lsp_store, cx| {
12569 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12570 let chunks_queried_for = lsp_data
12571 .inlay_hints
12572 .applicable_chunks(&[range])
12573 .collect::<Vec<_>>();
12574 match chunks_queried_for.as_slice() {
12575 &[chunk] => {
12576 let key = LspKey {
12577 request_type: TypeId::of::<T>(),
12578 server_queried: server_id,
12579 };
12580 let previous_request = lsp_data
12581 .chunk_lsp_requests
12582 .entry(key)
12583 .or_default()
12584 .insert(chunk, lsp_request_id);
12585 if let Some((previous_request, running_requests)) =
12586 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12587 {
12588 running_requests.remove(&previous_request);
12589 }
12590 }
12591 _ambiguous_chunks => {
12592 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12593 // there, a buffer version-based check will be performed and outdated requests discarded.
12594 }
12595 }
12596 anyhow::Ok(())
12597 })??;
12598
12599 Ok(())
12600 }
12601
12602 async fn query_lsp_locally<T>(
12603 lsp_store: Entity<Self>,
12604 for_server_id: Option<LanguageServerId>,
12605 sender_id: proto::PeerId,
12606 lsp_request_id: LspRequestId,
12607 proto_request: T::ProtoRequest,
12608 position: Option<Anchor>,
12609 cx: &mut AsyncApp,
12610 ) -> Result<()>
12611 where
12612 T: LspCommand + Clone,
12613 T::ProtoRequest: proto::LspRequestMessage,
12614 <T::ProtoRequest as proto::RequestMessage>::Response:
12615 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12616 {
12617 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12618 let version = deserialize_version(proto_request.buffer_version());
12619 let buffer = lsp_store.update(cx, |this, cx| {
12620 this.buffer_store.read(cx).get_existing(buffer_id)
12621 })??;
12622 buffer
12623 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12624 .await?;
12625 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12626 let request =
12627 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12628 let key = LspKey {
12629 request_type: TypeId::of::<T>(),
12630 server_queried: for_server_id,
12631 };
12632 lsp_store.update(cx, |lsp_store, cx| {
12633 let request_task = match for_server_id {
12634 Some(server_id) => {
12635 let server_task = lsp_store.request_lsp(
12636 buffer.clone(),
12637 LanguageServerToQuery::Other(server_id),
12638 request.clone(),
12639 cx,
12640 );
12641 cx.background_spawn(async move {
12642 let mut responses = Vec::new();
12643 match server_task.await {
12644 Ok(response) => responses.push((server_id, response)),
12645 // rust-analyzer likes to error with this when its still loading up
12646 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12647 Err(e) => log::error!(
12648 "Error handling response for request {request:?}: {e:#}"
12649 ),
12650 }
12651 responses
12652 })
12653 }
12654 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12655 };
12656 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12657 if T::ProtoRequest::stop_previous_requests() {
12658 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12659 lsp_requests.clear();
12660 }
12661 }
12662 lsp_data.lsp_requests.entry(key).or_default().insert(
12663 lsp_request_id,
12664 cx.spawn(async move |lsp_store, cx| {
12665 let response = request_task.await;
12666 lsp_store
12667 .update(cx, |lsp_store, cx| {
12668 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12669 {
12670 let response = response
12671 .into_iter()
12672 .map(|(server_id, response)| {
12673 (
12674 server_id.to_proto(),
12675 T::response_to_proto(
12676 response,
12677 lsp_store,
12678 sender_id,
12679 &buffer_version,
12680 cx,
12681 )
12682 .into(),
12683 )
12684 })
12685 .collect::<HashMap<_, _>>();
12686 match client.send_lsp_response::<T::ProtoRequest>(
12687 project_id,
12688 lsp_request_id,
12689 response,
12690 ) {
12691 Ok(()) => {}
12692 Err(e) => {
12693 log::error!("Failed to send LSP response: {e:#}",)
12694 }
12695 }
12696 }
12697 })
12698 .ok();
12699 }),
12700 );
12701 })?;
12702 Ok(())
12703 }
12704
12705 fn take_text_document_sync_options(
12706 capabilities: &mut lsp::ServerCapabilities,
12707 ) -> lsp::TextDocumentSyncOptions {
12708 match capabilities.text_document_sync.take() {
12709 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12710 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12711 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12712 sync_options.change = Some(sync_kind);
12713 sync_options
12714 }
12715 None => lsp::TextDocumentSyncOptions::default(),
12716 }
12717 }
12718
12719 #[cfg(any(test, feature = "test-support"))]
12720 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12721 Some(
12722 self.lsp_data
12723 .get_mut(&buffer_id)?
12724 .code_lens
12725 .take()?
12726 .update
12727 .take()?
12728 .1,
12729 )
12730 }
12731
12732 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12733 self.downstream_client.clone()
12734 }
12735
12736 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12737 self.worktree_store.clone()
12738 }
12739
12740 /// Gets what's stored in the LSP data for the given buffer.
12741 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12742 self.lsp_data.get_mut(&buffer_id)
12743 }
12744
12745 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12746 /// new [`BufferLspData`] will be created to replace the previous state.
12747 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12748 let (buffer_id, buffer_version) =
12749 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12750 let lsp_data = self
12751 .lsp_data
12752 .entry(buffer_id)
12753 .or_insert_with(|| BufferLspData::new(buffer, cx));
12754 if buffer_version.changed_since(&lsp_data.buffer_version) {
12755 *lsp_data = BufferLspData::new(buffer, cx);
12756 }
12757 lsp_data
12758 }
12759}
12760
12761// Registration with registerOptions as null, should fallback to true.
12762// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12763fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12764 reg: lsp::Registration,
12765) -> Result<OneOf<bool, T>> {
12766 Ok(match reg.register_options {
12767 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12768 None => OneOf::Left(true),
12769 })
12770}
12771
12772fn subscribe_to_binary_statuses(
12773 languages: &Arc<LanguageRegistry>,
12774 cx: &mut Context<'_, LspStore>,
12775) -> Task<()> {
12776 let mut server_statuses = languages.language_server_binary_statuses();
12777 cx.spawn(async move |lsp_store, cx| {
12778 while let Some((server_name, binary_status)) = server_statuses.next().await {
12779 if lsp_store
12780 .update(cx, |_, cx| {
12781 let mut message = None;
12782 let binary_status = match binary_status {
12783 BinaryStatus::None => proto::ServerBinaryStatus::None,
12784 BinaryStatus::CheckingForUpdate => {
12785 proto::ServerBinaryStatus::CheckingForUpdate
12786 }
12787 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12788 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12789 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12790 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12791 BinaryStatus::Failed { error } => {
12792 message = Some(error);
12793 proto::ServerBinaryStatus::Failed
12794 }
12795 };
12796 cx.emit(LspStoreEvent::LanguageServerUpdate {
12797 // Binary updates are about the binary that might not have any language server id at that point.
12798 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12799 language_server_id: LanguageServerId(0),
12800 name: Some(server_name),
12801 message: proto::update_language_server::Variant::StatusUpdate(
12802 proto::StatusUpdate {
12803 message,
12804 status: Some(proto::status_update::Status::Binary(
12805 binary_status as i32,
12806 )),
12807 },
12808 ),
12809 });
12810 })
12811 .is_err()
12812 {
12813 break;
12814 }
12815 }
12816 })
12817}
12818
12819fn lsp_workspace_diagnostics_refresh(
12820 registration_id: Option<String>,
12821 options: DiagnosticServerCapabilities,
12822 server: Arc<LanguageServer>,
12823 cx: &mut Context<'_, LspStore>,
12824) -> Option<WorkspaceRefreshTask> {
12825 let identifier = diagnostic_identifier(&options)?;
12826
12827 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12828 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12829 refresh_tx.try_send(()).ok();
12830
12831 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12832 let mut attempts = 0;
12833 let max_attempts = 50;
12834 let mut requests = 0;
12835
12836 loop {
12837 let Some(()) = refresh_rx.recv().await else {
12838 return;
12839 };
12840
12841 'request: loop {
12842 requests += 1;
12843 if attempts > max_attempts {
12844 log::error!(
12845 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12846 );
12847 return;
12848 }
12849 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12850 cx.background_executor()
12851 .timer(Duration::from_millis(backoff_millis))
12852 .await;
12853 attempts += 1;
12854
12855 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12856 lsp_store
12857 .all_result_ids(server.server_id())
12858 .into_iter()
12859 .filter_map(|(abs_path, result_id)| {
12860 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12861 Some(lsp::PreviousResultId {
12862 uri,
12863 value: result_id,
12864 })
12865 })
12866 .collect()
12867 }) else {
12868 return;
12869 };
12870
12871 let token = if let Some(identifier) = ®istration_id {
12872 format!(
12873 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12874 server.server_id(),
12875 )
12876 } else {
12877 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12878 };
12879
12880 progress_rx.try_recv().ok();
12881 let timer =
12882 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12883 let progress = pin!(progress_rx.recv().fuse());
12884 let response_result = server
12885 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12886 lsp::WorkspaceDiagnosticParams {
12887 previous_result_ids,
12888 identifier: identifier.clone(),
12889 work_done_progress_params: Default::default(),
12890 partial_result_params: lsp::PartialResultParams {
12891 partial_result_token: Some(lsp::ProgressToken::String(token)),
12892 },
12893 },
12894 select(timer, progress).then(|either| match either {
12895 Either::Left((message, ..)) => ready(message).left_future(),
12896 Either::Right(..) => pending::<String>().right_future(),
12897 }),
12898 )
12899 .await;
12900
12901 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12902 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12903 match response_result {
12904 ConnectionResult::Timeout => {
12905 log::error!("Timeout during workspace diagnostics pull");
12906 continue 'request;
12907 }
12908 ConnectionResult::ConnectionReset => {
12909 log::error!("Server closed a workspace diagnostics pull request");
12910 continue 'request;
12911 }
12912 ConnectionResult::Result(Err(e)) => {
12913 log::error!("Error during workspace diagnostics pull: {e:#}");
12914 break 'request;
12915 }
12916 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12917 attempts = 0;
12918 if lsp_store
12919 .update(cx, |lsp_store, cx| {
12920 lsp_store.apply_workspace_diagnostic_report(
12921 server.server_id(),
12922 pulled_diagnostics,
12923 cx,
12924 )
12925 })
12926 .is_err()
12927 {
12928 return;
12929 }
12930 break 'request;
12931 }
12932 }
12933 }
12934 }
12935 });
12936
12937 Some(WorkspaceRefreshTask {
12938 refresh_tx,
12939 progress_tx,
12940 task: workspace_query_language_server,
12941 })
12942}
12943
12944fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12945 match &options {
12946 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12947 if !diagnostic_options.workspace_diagnostics {
12948 return None;
12949 }
12950 Some(diagnostic_options.identifier.clone())
12951 }
12952 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12953 let diagnostic_options = ®istration_options.diagnostic_options;
12954 if !diagnostic_options.workspace_diagnostics {
12955 return None;
12956 }
12957 Some(diagnostic_options.identifier.clone())
12958 }
12959 }
12960}
12961
12962fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12963 let CompletionSource::BufferWord {
12964 word_range,
12965 resolved,
12966 } = &mut completion.source
12967 else {
12968 return;
12969 };
12970 if *resolved {
12971 return;
12972 }
12973
12974 if completion.new_text
12975 != snapshot
12976 .text_for_range(word_range.clone())
12977 .collect::<String>()
12978 {
12979 return;
12980 }
12981
12982 let mut offset = 0;
12983 for chunk in snapshot.chunks(word_range.clone(), true) {
12984 let end_offset = offset + chunk.text.len();
12985 if let Some(highlight_id) = chunk.syntax_highlight_id {
12986 completion
12987 .label
12988 .runs
12989 .push((offset..end_offset, highlight_id));
12990 }
12991 offset = end_offset;
12992 }
12993 *resolved = true;
12994}
12995
12996impl EventEmitter<LspStoreEvent> for LspStore {}
12997
12998fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12999 hover
13000 .contents
13001 .retain(|hover_block| !hover_block.text.trim().is_empty());
13002 if hover.contents.is_empty() {
13003 None
13004 } else {
13005 Some(hover)
13006 }
13007}
13008
13009async fn populate_labels_for_completions(
13010 new_completions: Vec<CoreCompletion>,
13011 language: Option<Arc<Language>>,
13012 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13013) -> Vec<Completion> {
13014 let lsp_completions = new_completions
13015 .iter()
13016 .filter_map(|new_completion| {
13017 new_completion
13018 .source
13019 .lsp_completion(true)
13020 .map(|lsp_completion| lsp_completion.into_owned())
13021 })
13022 .collect::<Vec<_>>();
13023
13024 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13025 lsp_adapter
13026 .labels_for_completions(&lsp_completions, language)
13027 .await
13028 .log_err()
13029 .unwrap_or_default()
13030 } else {
13031 Vec::new()
13032 }
13033 .into_iter()
13034 .fuse();
13035
13036 let mut completions = Vec::new();
13037 for completion in new_completions {
13038 match completion.source.lsp_completion(true) {
13039 Some(lsp_completion) => {
13040 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13041
13042 let mut label = labels.next().flatten().unwrap_or_else(|| {
13043 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13044 });
13045 ensure_uniform_list_compatible_label(&mut label);
13046 completions.push(Completion {
13047 label,
13048 documentation,
13049 replace_range: completion.replace_range,
13050 new_text: completion.new_text,
13051 insert_text_mode: lsp_completion.insert_text_mode,
13052 source: completion.source,
13053 icon_path: None,
13054 confirm: None,
13055 match_start: None,
13056 snippet_deduplication_key: None,
13057 });
13058 }
13059 None => {
13060 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13061 ensure_uniform_list_compatible_label(&mut label);
13062 completions.push(Completion {
13063 label,
13064 documentation: None,
13065 replace_range: completion.replace_range,
13066 new_text: completion.new_text,
13067 source: completion.source,
13068 insert_text_mode: None,
13069 icon_path: None,
13070 confirm: None,
13071 match_start: None,
13072 snippet_deduplication_key: None,
13073 });
13074 }
13075 }
13076 }
13077 completions
13078}
13079
13080#[derive(Debug)]
13081pub enum LanguageServerToQuery {
13082 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13083 FirstCapable,
13084 /// Query a specific language server.
13085 Other(LanguageServerId),
13086}
13087
13088#[derive(Default)]
13089struct RenamePathsWatchedForServer {
13090 did_rename: Vec<RenameActionPredicate>,
13091 will_rename: Vec<RenameActionPredicate>,
13092}
13093
13094impl RenamePathsWatchedForServer {
13095 fn with_did_rename_patterns(
13096 mut self,
13097 did_rename: Option<&FileOperationRegistrationOptions>,
13098 ) -> Self {
13099 if let Some(did_rename) = did_rename {
13100 self.did_rename = did_rename
13101 .filters
13102 .iter()
13103 .filter_map(|filter| filter.try_into().log_err())
13104 .collect();
13105 }
13106 self
13107 }
13108 fn with_will_rename_patterns(
13109 mut self,
13110 will_rename: Option<&FileOperationRegistrationOptions>,
13111 ) -> Self {
13112 if let Some(will_rename) = will_rename {
13113 self.will_rename = will_rename
13114 .filters
13115 .iter()
13116 .filter_map(|filter| filter.try_into().log_err())
13117 .collect();
13118 }
13119 self
13120 }
13121
13122 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13123 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13124 }
13125 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13126 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13127 }
13128}
13129
13130impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13131 type Error = globset::Error;
13132 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13133 Ok(Self {
13134 kind: ops.pattern.matches.clone(),
13135 glob: GlobBuilder::new(&ops.pattern.glob)
13136 .case_insensitive(
13137 ops.pattern
13138 .options
13139 .as_ref()
13140 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13141 )
13142 .build()?
13143 .compile_matcher(),
13144 })
13145 }
13146}
13147struct RenameActionPredicate {
13148 glob: GlobMatcher,
13149 kind: Option<FileOperationPatternKind>,
13150}
13151
13152impl RenameActionPredicate {
13153 // Returns true if language server should be notified
13154 fn eval(&self, path: &str, is_dir: bool) -> bool {
13155 self.kind.as_ref().is_none_or(|kind| {
13156 let expected_kind = if is_dir {
13157 FileOperationPatternKind::Folder
13158 } else {
13159 FileOperationPatternKind::File
13160 };
13161 kind == &expected_kind
13162 }) && self.glob.is_match(path)
13163 }
13164}
13165
13166#[derive(Default)]
13167struct LanguageServerWatchedPaths {
13168 worktree_paths: HashMap<WorktreeId, GlobSet>,
13169 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13170}
13171
13172#[derive(Default)]
13173struct LanguageServerWatchedPathsBuilder {
13174 worktree_paths: HashMap<WorktreeId, GlobSet>,
13175 abs_paths: HashMap<Arc<Path>, GlobSet>,
13176}
13177
13178impl LanguageServerWatchedPathsBuilder {
13179 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13180 self.worktree_paths.insert(worktree_id, glob_set);
13181 }
13182 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13183 self.abs_paths.insert(path, glob_set);
13184 }
13185 fn build(
13186 self,
13187 fs: Arc<dyn Fs>,
13188 language_server_id: LanguageServerId,
13189 cx: &mut Context<LspStore>,
13190 ) -> LanguageServerWatchedPaths {
13191 let lsp_store = cx.weak_entity();
13192
13193 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13194 let abs_paths = self
13195 .abs_paths
13196 .into_iter()
13197 .map(|(abs_path, globset)| {
13198 let task = cx.spawn({
13199 let abs_path = abs_path.clone();
13200 let fs = fs.clone();
13201
13202 let lsp_store = lsp_store.clone();
13203 async move |_, cx| {
13204 maybe!(async move {
13205 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13206 while let Some(update) = push_updates.0.next().await {
13207 let action = lsp_store
13208 .update(cx, |this, _| {
13209 let Some(local) = this.as_local() else {
13210 return ControlFlow::Break(());
13211 };
13212 let Some(watcher) = local
13213 .language_server_watched_paths
13214 .get(&language_server_id)
13215 else {
13216 return ControlFlow::Break(());
13217 };
13218 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13219 "Watched abs path is not registered with a watcher",
13220 );
13221 let matching_entries = update
13222 .into_iter()
13223 .filter(|event| globs.is_match(&event.path))
13224 .collect::<Vec<_>>();
13225 this.lsp_notify_abs_paths_changed(
13226 language_server_id,
13227 matching_entries,
13228 );
13229 ControlFlow::Continue(())
13230 })
13231 .ok()?;
13232
13233 if action.is_break() {
13234 break;
13235 }
13236 }
13237 Some(())
13238 })
13239 .await;
13240 }
13241 });
13242 (abs_path, (globset, task))
13243 })
13244 .collect();
13245 LanguageServerWatchedPaths {
13246 worktree_paths: self.worktree_paths,
13247 abs_paths,
13248 }
13249 }
13250}
13251
13252struct LspBufferSnapshot {
13253 version: i32,
13254 snapshot: TextBufferSnapshot,
13255}
13256
13257/// A prompt requested by LSP server.
13258#[derive(Clone, Debug)]
13259pub struct LanguageServerPromptRequest {
13260 pub level: PromptLevel,
13261 pub message: String,
13262 pub actions: Vec<MessageActionItem>,
13263 pub lsp_name: String,
13264 pub(crate) response_channel: Sender<MessageActionItem>,
13265}
13266
13267impl LanguageServerPromptRequest {
13268 pub async fn respond(self, index: usize) -> Option<()> {
13269 if let Some(response) = self.actions.into_iter().nth(index) {
13270 self.response_channel.send(response).await.ok()
13271 } else {
13272 None
13273 }
13274 }
13275}
13276impl PartialEq for LanguageServerPromptRequest {
13277 fn eq(&self, other: &Self) -> bool {
13278 self.message == other.message && self.actions == other.actions
13279 }
13280}
13281
13282#[derive(Clone, Debug, PartialEq)]
13283pub enum LanguageServerLogType {
13284 Log(MessageType),
13285 Trace { verbose_info: Option<String> },
13286 Rpc { received: bool },
13287}
13288
13289impl LanguageServerLogType {
13290 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13291 match self {
13292 Self::Log(log_type) => {
13293 use proto::log_message::LogLevel;
13294 let level = match *log_type {
13295 MessageType::ERROR => LogLevel::Error,
13296 MessageType::WARNING => LogLevel::Warning,
13297 MessageType::INFO => LogLevel::Info,
13298 MessageType::LOG => LogLevel::Log,
13299 other => {
13300 log::warn!("Unknown lsp log message type: {other:?}");
13301 LogLevel::Log
13302 }
13303 };
13304 proto::language_server_log::LogType::Log(proto::LogMessage {
13305 level: level as i32,
13306 })
13307 }
13308 Self::Trace { verbose_info } => {
13309 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13310 verbose_info: verbose_info.to_owned(),
13311 })
13312 }
13313 Self::Rpc { received } => {
13314 let kind = if *received {
13315 proto::rpc_message::Kind::Received
13316 } else {
13317 proto::rpc_message::Kind::Sent
13318 };
13319 let kind = kind as i32;
13320 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13321 }
13322 }
13323 }
13324
13325 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13326 use proto::log_message::LogLevel;
13327 use proto::rpc_message;
13328 match log_type {
13329 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13330 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13331 LogLevel::Error => MessageType::ERROR,
13332 LogLevel::Warning => MessageType::WARNING,
13333 LogLevel::Info => MessageType::INFO,
13334 LogLevel::Log => MessageType::LOG,
13335 },
13336 ),
13337 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13338 verbose_info: trace_message.verbose_info,
13339 },
13340 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13341 received: match rpc_message::Kind::from_i32(message.kind)
13342 .unwrap_or(rpc_message::Kind::Received)
13343 {
13344 rpc_message::Kind::Received => true,
13345 rpc_message::Kind::Sent => false,
13346 },
13347 },
13348 }
13349 }
13350}
13351
13352pub struct WorkspaceRefreshTask {
13353 refresh_tx: mpsc::Sender<()>,
13354 progress_tx: mpsc::Sender<()>,
13355 #[allow(dead_code)]
13356 task: Task<()>,
13357}
13358
13359pub enum LanguageServerState {
13360 Starting {
13361 startup: Task<Option<Arc<LanguageServer>>>,
13362 /// List of language servers that will be added to the workspace once it's initialization completes.
13363 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13364 },
13365
13366 Running {
13367 adapter: Arc<CachedLspAdapter>,
13368 server: Arc<LanguageServer>,
13369 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13370 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13371 },
13372}
13373
13374impl LanguageServerState {
13375 fn add_workspace_folder(&self, uri: Uri) {
13376 match self {
13377 LanguageServerState::Starting {
13378 pending_workspace_folders,
13379 ..
13380 } => {
13381 pending_workspace_folders.lock().insert(uri);
13382 }
13383 LanguageServerState::Running { server, .. } => {
13384 server.add_workspace_folder(uri);
13385 }
13386 }
13387 }
13388 fn _remove_workspace_folder(&self, uri: Uri) {
13389 match self {
13390 LanguageServerState::Starting {
13391 pending_workspace_folders,
13392 ..
13393 } => {
13394 pending_workspace_folders.lock().remove(&uri);
13395 }
13396 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13397 }
13398 }
13399}
13400
13401impl std::fmt::Debug for LanguageServerState {
13402 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13403 match self {
13404 LanguageServerState::Starting { .. } => {
13405 f.debug_struct("LanguageServerState::Starting").finish()
13406 }
13407 LanguageServerState::Running { .. } => {
13408 f.debug_struct("LanguageServerState::Running").finish()
13409 }
13410 }
13411 }
13412}
13413
13414#[derive(Clone, Debug, Serialize)]
13415pub struct LanguageServerProgress {
13416 pub is_disk_based_diagnostics_progress: bool,
13417 pub is_cancellable: bool,
13418 pub title: Option<String>,
13419 pub message: Option<String>,
13420 pub percentage: Option<usize>,
13421 #[serde(skip_serializing)]
13422 pub last_update_at: Instant,
13423}
13424
13425#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13426pub struct DiagnosticSummary {
13427 pub error_count: usize,
13428 pub warning_count: usize,
13429}
13430
13431impl DiagnosticSummary {
13432 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13433 let mut this = Self {
13434 error_count: 0,
13435 warning_count: 0,
13436 };
13437
13438 for entry in diagnostics {
13439 if entry.diagnostic.is_primary {
13440 match entry.diagnostic.severity {
13441 DiagnosticSeverity::ERROR => this.error_count += 1,
13442 DiagnosticSeverity::WARNING => this.warning_count += 1,
13443 _ => {}
13444 }
13445 }
13446 }
13447
13448 this
13449 }
13450
13451 pub fn is_empty(&self) -> bool {
13452 self.error_count == 0 && self.warning_count == 0
13453 }
13454
13455 pub fn to_proto(
13456 self,
13457 language_server_id: LanguageServerId,
13458 path: &RelPath,
13459 ) -> proto::DiagnosticSummary {
13460 proto::DiagnosticSummary {
13461 path: path.to_proto(),
13462 language_server_id: language_server_id.0 as u64,
13463 error_count: self.error_count as u32,
13464 warning_count: self.warning_count as u32,
13465 }
13466 }
13467}
13468
13469#[derive(Clone, Debug)]
13470pub enum CompletionDocumentation {
13471 /// There is no documentation for this completion.
13472 Undocumented,
13473 /// A single line of documentation.
13474 SingleLine(SharedString),
13475 /// Multiple lines of plain text documentation.
13476 MultiLinePlainText(SharedString),
13477 /// Markdown documentation.
13478 MultiLineMarkdown(SharedString),
13479 /// Both single line and multiple lines of plain text documentation.
13480 SingleLineAndMultiLinePlainText {
13481 single_line: SharedString,
13482 plain_text: Option<SharedString>,
13483 },
13484}
13485
13486impl CompletionDocumentation {
13487 #[cfg(any(test, feature = "test-support"))]
13488 pub fn text(&self) -> SharedString {
13489 match self {
13490 CompletionDocumentation::Undocumented => "".into(),
13491 CompletionDocumentation::SingleLine(s) => s.clone(),
13492 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13493 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13494 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13495 single_line.clone()
13496 }
13497 }
13498 }
13499}
13500
13501impl From<lsp::Documentation> for CompletionDocumentation {
13502 fn from(docs: lsp::Documentation) -> Self {
13503 match docs {
13504 lsp::Documentation::String(text) => {
13505 if text.lines().count() <= 1 {
13506 CompletionDocumentation::SingleLine(text.into())
13507 } else {
13508 CompletionDocumentation::MultiLinePlainText(text.into())
13509 }
13510 }
13511
13512 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13513 lsp::MarkupKind::PlainText => {
13514 if value.lines().count() <= 1 {
13515 CompletionDocumentation::SingleLine(value.into())
13516 } else {
13517 CompletionDocumentation::MultiLinePlainText(value.into())
13518 }
13519 }
13520
13521 lsp::MarkupKind::Markdown => {
13522 CompletionDocumentation::MultiLineMarkdown(value.into())
13523 }
13524 },
13525 }
13526 }
13527}
13528
13529pub enum ResolvedHint {
13530 Resolved(InlayHint),
13531 Resolving(Shared<Task<()>>),
13532}
13533
13534fn glob_literal_prefix(glob: &Path) -> PathBuf {
13535 glob.components()
13536 .take_while(|component| match component {
13537 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13538 _ => true,
13539 })
13540 .collect()
13541}
13542
13543pub struct SshLspAdapter {
13544 name: LanguageServerName,
13545 binary: LanguageServerBinary,
13546 initialization_options: Option<String>,
13547 code_action_kinds: Option<Vec<CodeActionKind>>,
13548}
13549
13550impl SshLspAdapter {
13551 pub fn new(
13552 name: LanguageServerName,
13553 binary: LanguageServerBinary,
13554 initialization_options: Option<String>,
13555 code_action_kinds: Option<String>,
13556 ) -> Self {
13557 Self {
13558 name,
13559 binary,
13560 initialization_options,
13561 code_action_kinds: code_action_kinds
13562 .as_ref()
13563 .and_then(|c| serde_json::from_str(c).ok()),
13564 }
13565 }
13566}
13567
13568impl LspInstaller for SshLspAdapter {
13569 type BinaryVersion = ();
13570 async fn check_if_user_installed(
13571 &self,
13572 _: &dyn LspAdapterDelegate,
13573 _: Option<Toolchain>,
13574 _: &AsyncApp,
13575 ) -> Option<LanguageServerBinary> {
13576 Some(self.binary.clone())
13577 }
13578
13579 async fn cached_server_binary(
13580 &self,
13581 _: PathBuf,
13582 _: &dyn LspAdapterDelegate,
13583 ) -> Option<LanguageServerBinary> {
13584 None
13585 }
13586
13587 async fn fetch_latest_server_version(
13588 &self,
13589 _: &dyn LspAdapterDelegate,
13590 _: bool,
13591 _: &mut AsyncApp,
13592 ) -> Result<()> {
13593 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13594 }
13595
13596 async fn fetch_server_binary(
13597 &self,
13598 _: (),
13599 _: PathBuf,
13600 _: &dyn LspAdapterDelegate,
13601 ) -> Result<LanguageServerBinary> {
13602 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13603 }
13604}
13605
13606#[async_trait(?Send)]
13607impl LspAdapter for SshLspAdapter {
13608 fn name(&self) -> LanguageServerName {
13609 self.name.clone()
13610 }
13611
13612 async fn initialization_options(
13613 self: Arc<Self>,
13614 _: &Arc<dyn LspAdapterDelegate>,
13615 ) -> Result<Option<serde_json::Value>> {
13616 let Some(options) = &self.initialization_options else {
13617 return Ok(None);
13618 };
13619 let result = serde_json::from_str(options)?;
13620 Ok(result)
13621 }
13622
13623 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13624 self.code_action_kinds.clone()
13625 }
13626}
13627
13628pub fn language_server_settings<'a>(
13629 delegate: &'a dyn LspAdapterDelegate,
13630 language: &LanguageServerName,
13631 cx: &'a App,
13632) -> Option<&'a LspSettings> {
13633 language_server_settings_for(
13634 SettingsLocation {
13635 worktree_id: delegate.worktree_id(),
13636 path: RelPath::empty(),
13637 },
13638 language,
13639 cx,
13640 )
13641}
13642
13643pub fn language_server_settings_for<'a>(
13644 location: SettingsLocation<'a>,
13645 language: &LanguageServerName,
13646 cx: &'a App,
13647) -> Option<&'a LspSettings> {
13648 ProjectSettings::get(Some(location), cx).lsp.get(language)
13649}
13650
13651pub struct LocalLspAdapterDelegate {
13652 lsp_store: WeakEntity<LspStore>,
13653 worktree: worktree::Snapshot,
13654 fs: Arc<dyn Fs>,
13655 http_client: Arc<dyn HttpClient>,
13656 language_registry: Arc<LanguageRegistry>,
13657 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13658}
13659
13660impl LocalLspAdapterDelegate {
13661 pub fn new(
13662 language_registry: Arc<LanguageRegistry>,
13663 environment: &Entity<ProjectEnvironment>,
13664 lsp_store: WeakEntity<LspStore>,
13665 worktree: &Entity<Worktree>,
13666 http_client: Arc<dyn HttpClient>,
13667 fs: Arc<dyn Fs>,
13668 cx: &mut App,
13669 ) -> Arc<Self> {
13670 let load_shell_env_task =
13671 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13672
13673 Arc::new(Self {
13674 lsp_store,
13675 worktree: worktree.read(cx).snapshot(),
13676 fs,
13677 http_client,
13678 language_registry,
13679 load_shell_env_task,
13680 })
13681 }
13682
13683 fn from_local_lsp(
13684 local: &LocalLspStore,
13685 worktree: &Entity<Worktree>,
13686 cx: &mut App,
13687 ) -> Arc<Self> {
13688 Self::new(
13689 local.languages.clone(),
13690 &local.environment,
13691 local.weak.clone(),
13692 worktree,
13693 local.http_client.clone(),
13694 local.fs.clone(),
13695 cx,
13696 )
13697 }
13698}
13699
13700#[async_trait]
13701impl LspAdapterDelegate for LocalLspAdapterDelegate {
13702 fn show_notification(&self, message: &str, cx: &mut App) {
13703 self.lsp_store
13704 .update(cx, |_, cx| {
13705 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13706 })
13707 .ok();
13708 }
13709
13710 fn http_client(&self) -> Arc<dyn HttpClient> {
13711 self.http_client.clone()
13712 }
13713
13714 fn worktree_id(&self) -> WorktreeId {
13715 self.worktree.id()
13716 }
13717
13718 fn worktree_root_path(&self) -> &Path {
13719 self.worktree.abs_path().as_ref()
13720 }
13721
13722 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13723 self.worktree.resolve_executable_path(path)
13724 }
13725
13726 async fn shell_env(&self) -> HashMap<String, String> {
13727 let task = self.load_shell_env_task.clone();
13728 task.await.unwrap_or_default()
13729 }
13730
13731 async fn npm_package_installed_version(
13732 &self,
13733 package_name: &str,
13734 ) -> Result<Option<(PathBuf, String)>> {
13735 let local_package_directory = self.worktree_root_path();
13736 let node_modules_directory = local_package_directory.join("node_modules");
13737
13738 if let Some(version) =
13739 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13740 {
13741 return Ok(Some((node_modules_directory, version)));
13742 }
13743 let Some(npm) = self.which("npm".as_ref()).await else {
13744 log::warn!(
13745 "Failed to find npm executable for {:?}",
13746 local_package_directory
13747 );
13748 return Ok(None);
13749 };
13750
13751 let env = self.shell_env().await;
13752 let output = util::command::new_smol_command(&npm)
13753 .args(["root", "-g"])
13754 .envs(env)
13755 .current_dir(local_package_directory)
13756 .output()
13757 .await?;
13758 let global_node_modules =
13759 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13760
13761 if let Some(version) =
13762 read_package_installed_version(global_node_modules.clone(), package_name).await?
13763 {
13764 return Ok(Some((global_node_modules, version)));
13765 }
13766 return Ok(None);
13767 }
13768
13769 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13770 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13771 if self.fs.is_file(&worktree_abs_path).await {
13772 worktree_abs_path.pop();
13773 }
13774
13775 let env = self.shell_env().await;
13776
13777 let shell_path = env.get("PATH").cloned();
13778
13779 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13780 }
13781
13782 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13783 let mut working_dir = self.worktree_root_path().to_path_buf();
13784 if self.fs.is_file(&working_dir).await {
13785 working_dir.pop();
13786 }
13787 let output = util::command::new_smol_command(&command.path)
13788 .args(command.arguments)
13789 .envs(command.env.clone().unwrap_or_default())
13790 .current_dir(working_dir)
13791 .output()
13792 .await?;
13793
13794 anyhow::ensure!(
13795 output.status.success(),
13796 "{}, stdout: {:?}, stderr: {:?}",
13797 output.status,
13798 String::from_utf8_lossy(&output.stdout),
13799 String::from_utf8_lossy(&output.stderr)
13800 );
13801 Ok(())
13802 }
13803
13804 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13805 self.language_registry
13806 .update_lsp_binary_status(server_name, status);
13807 }
13808
13809 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13810 self.language_registry
13811 .all_lsp_adapters()
13812 .into_iter()
13813 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13814 .collect()
13815 }
13816
13817 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13818 let dir = self.language_registry.language_server_download_dir(name)?;
13819
13820 if !dir.exists() {
13821 smol::fs::create_dir_all(&dir)
13822 .await
13823 .context("failed to create container directory")
13824 .log_err()?;
13825 }
13826
13827 Some(dir)
13828 }
13829
13830 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13831 let entry = self
13832 .worktree
13833 .entry_for_path(path)
13834 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13835 let abs_path = self.worktree.absolutize(&entry.path);
13836 self.fs.load(&abs_path).await
13837 }
13838}
13839
13840async fn populate_labels_for_symbols(
13841 symbols: Vec<CoreSymbol>,
13842 language_registry: &Arc<LanguageRegistry>,
13843 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13844 output: &mut Vec<Symbol>,
13845) {
13846 #[allow(clippy::mutable_key_type)]
13847 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13848
13849 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13850 for symbol in symbols {
13851 let Some(file_name) = symbol.path.file_name() else {
13852 continue;
13853 };
13854 let language = language_registry
13855 .load_language_for_file_path(Path::new(file_name))
13856 .await
13857 .ok()
13858 .or_else(|| {
13859 unknown_paths.insert(file_name.into());
13860 None
13861 });
13862 symbols_by_language
13863 .entry(language)
13864 .or_default()
13865 .push(symbol);
13866 }
13867
13868 for unknown_path in unknown_paths {
13869 log::info!("no language found for symbol in file {unknown_path:?}");
13870 }
13871
13872 let mut label_params = Vec::new();
13873 for (language, mut symbols) in symbols_by_language {
13874 label_params.clear();
13875 label_params.extend(
13876 symbols
13877 .iter_mut()
13878 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13879 );
13880
13881 let mut labels = Vec::new();
13882 if let Some(language) = language {
13883 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13884 language_registry
13885 .lsp_adapters(&language.name())
13886 .first()
13887 .cloned()
13888 });
13889 if let Some(lsp_adapter) = lsp_adapter {
13890 labels = lsp_adapter
13891 .labels_for_symbols(&label_params, &language)
13892 .await
13893 .log_err()
13894 .unwrap_or_default();
13895 }
13896 }
13897
13898 for ((symbol, (name, _)), label) in symbols
13899 .into_iter()
13900 .zip(label_params.drain(..))
13901 .zip(labels.into_iter().chain(iter::repeat(None)))
13902 {
13903 output.push(Symbol {
13904 language_server_name: symbol.language_server_name,
13905 source_worktree_id: symbol.source_worktree_id,
13906 source_language_server_id: symbol.source_language_server_id,
13907 path: symbol.path,
13908 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13909 name,
13910 kind: symbol.kind,
13911 range: symbol.range,
13912 });
13913 }
13914 }
13915}
13916
13917fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13918 match server.capabilities().text_document_sync.as_ref()? {
13919 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13920 // Server wants didSave but didn't specify includeText.
13921 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13922 // Server doesn't want didSave at all.
13923 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13924 // Server provided SaveOptions.
13925 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13926 Some(save_options.include_text.unwrap_or(false))
13927 }
13928 },
13929 // We do not have any save info. Kind affects didChange only.
13930 lsp::TextDocumentSyncCapability::Kind(_) => None,
13931 }
13932}
13933
13934/// Completion items are displayed in a `UniformList`.
13935/// Usually, those items are single-line strings, but in LSP responses,
13936/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13937/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13938/// 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,
13939/// breaking the completions menu presentation.
13940///
13941/// 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.
13942fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13943 let mut new_text = String::with_capacity(label.text.len());
13944 let mut offset_map = vec![0; label.text.len() + 1];
13945 let mut last_char_was_space = false;
13946 let mut new_idx = 0;
13947 let chars = label.text.char_indices().fuse();
13948 let mut newlines_removed = false;
13949
13950 for (idx, c) in chars {
13951 offset_map[idx] = new_idx;
13952
13953 match c {
13954 '\n' if last_char_was_space => {
13955 newlines_removed = true;
13956 }
13957 '\t' | ' ' if last_char_was_space => {}
13958 '\n' if !last_char_was_space => {
13959 new_text.push(' ');
13960 new_idx += 1;
13961 last_char_was_space = true;
13962 newlines_removed = true;
13963 }
13964 ' ' | '\t' => {
13965 new_text.push(' ');
13966 new_idx += 1;
13967 last_char_was_space = true;
13968 }
13969 _ => {
13970 new_text.push(c);
13971 new_idx += c.len_utf8();
13972 last_char_was_space = false;
13973 }
13974 }
13975 }
13976 offset_map[label.text.len()] = new_idx;
13977
13978 // Only modify the label if newlines were removed.
13979 if !newlines_removed {
13980 return;
13981 }
13982
13983 let last_index = new_idx;
13984 let mut run_ranges_errors = Vec::new();
13985 label.runs.retain_mut(|(range, _)| {
13986 match offset_map.get(range.start) {
13987 Some(&start) => range.start = start,
13988 None => {
13989 run_ranges_errors.push(range.clone());
13990 return false;
13991 }
13992 }
13993
13994 match offset_map.get(range.end) {
13995 Some(&end) => range.end = end,
13996 None => {
13997 run_ranges_errors.push(range.clone());
13998 range.end = last_index;
13999 }
14000 }
14001 true
14002 });
14003 if !run_ranges_errors.is_empty() {
14004 log::error!(
14005 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14006 label.text
14007 );
14008 }
14009
14010 let mut wrong_filter_range = None;
14011 if label.filter_range == (0..label.text.len()) {
14012 label.filter_range = 0..new_text.len();
14013 } else {
14014 let mut original_filter_range = Some(label.filter_range.clone());
14015 match offset_map.get(label.filter_range.start) {
14016 Some(&start) => label.filter_range.start = start,
14017 None => {
14018 wrong_filter_range = original_filter_range.take();
14019 label.filter_range.start = last_index;
14020 }
14021 }
14022
14023 match offset_map.get(label.filter_range.end) {
14024 Some(&end) => label.filter_range.end = end,
14025 None => {
14026 wrong_filter_range = original_filter_range.take();
14027 label.filter_range.end = last_index;
14028 }
14029 }
14030 }
14031 if let Some(wrong_filter_range) = wrong_filter_range {
14032 log::error!(
14033 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14034 label.text
14035 );
14036 }
14037
14038 label.text = new_text;
14039}
14040
14041#[cfg(test)]
14042mod tests {
14043 use language::HighlightId;
14044
14045 use super::*;
14046
14047 #[test]
14048 fn test_glob_literal_prefix() {
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 #[cfg(target_os = "windows")]
14064 {
14065 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14066 assert_eq!(
14067 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14068 Path::new("node_modules")
14069 );
14070 assert_eq!(
14071 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14072 Path::new("foo")
14073 );
14074 assert_eq!(
14075 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14076 Path::new("foo/bar/baz.js")
14077 );
14078 }
14079 }
14080
14081 #[test]
14082 fn test_multi_len_chars_normalization() {
14083 let mut label = CodeLabel::new(
14084 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14085 0..6,
14086 vec![(0..6, HighlightId(1))],
14087 );
14088 ensure_uniform_list_compatible_label(&mut label);
14089 assert_eq!(
14090 label,
14091 CodeLabel::new(
14092 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14093 0..6,
14094 vec![(0..6, HighlightId(1))],
14095 )
14096 );
14097 }
14098}