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