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 vec,
120};
121use sum_tree::Dimensions;
122use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
123
124use util::{
125 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
126 paths::{PathStyle, SanitizedPath},
127 post_inc,
128 rel_path::RelPath,
129};
130
131pub use fs::*;
132pub use language::Location;
133pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
134#[cfg(any(test, feature = "test-support"))]
135pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
136pub use worktree::{
137 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
138 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
139};
140
141const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
142pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
143const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
144const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
145
146#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
147pub enum ProgressToken {
148 Number(i32),
149 String(SharedString),
150}
151
152impl std::fmt::Display for ProgressToken {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 match self {
155 Self::Number(number) => write!(f, "{number}"),
156 Self::String(string) => write!(f, "{string}"),
157 }
158 }
159}
160
161impl ProgressToken {
162 fn from_lsp(value: lsp::NumberOrString) -> Self {
163 match value {
164 lsp::NumberOrString::Number(number) => Self::Number(number),
165 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
166 }
167 }
168
169 fn to_lsp(&self) -> lsp::NumberOrString {
170 match self {
171 Self::Number(number) => lsp::NumberOrString::Number(*number),
172 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
173 }
174 }
175
176 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
177 Some(match value.value? {
178 proto::progress_token::Value::Number(number) => Self::Number(number),
179 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
180 })
181 }
182
183 fn to_proto(&self) -> proto::ProgressToken {
184 proto::ProgressToken {
185 value: Some(match self {
186 Self::Number(number) => proto::progress_token::Value::Number(*number),
187 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
188 }),
189 }
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194pub enum FormatTrigger {
195 Save,
196 Manual,
197}
198
199pub enum LspFormatTarget {
200 Buffers,
201 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
202}
203
204pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
205
206impl FormatTrigger {
207 fn from_proto(value: i32) -> FormatTrigger {
208 match value {
209 0 => FormatTrigger::Save,
210 1 => FormatTrigger::Manual,
211 _ => FormatTrigger::Save,
212 }
213 }
214}
215
216#[derive(Clone)]
217struct UnifiedLanguageServer {
218 id: LanguageServerId,
219 project_roots: HashSet<Arc<RelPath>>,
220}
221
222#[derive(Clone, Debug, Hash, PartialEq, Eq)]
223struct LanguageServerSeed {
224 worktree_id: WorktreeId,
225 name: LanguageServerName,
226 toolchain: Option<Toolchain>,
227 settings: Arc<LspSettings>,
228}
229
230#[derive(Debug)]
231pub struct DocumentDiagnosticsUpdate<'a, D> {
232 pub diagnostics: D,
233 pub result_id: Option<SharedString>,
234 pub registration_id: Option<SharedString>,
235 pub server_id: LanguageServerId,
236 pub disk_based_sources: Cow<'a, [String]>,
237}
238
239pub struct DocumentDiagnostics {
240 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
241 document_abs_path: PathBuf,
242 version: Option<i32>,
243}
244
245#[derive(Default, Debug)]
246struct DynamicRegistrations {
247 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
248 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
249}
250
251pub struct LocalLspStore {
252 weak: WeakEntity<LspStore>,
253 worktree_store: Entity<WorktreeStore>,
254 toolchain_store: Entity<LocalToolchainStore>,
255 http_client: Arc<dyn HttpClient>,
256 environment: Entity<ProjectEnvironment>,
257 fs: Arc<dyn Fs>,
258 languages: Arc<LanguageRegistry>,
259 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
260 yarn: Entity<YarnPathStore>,
261 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
262 buffers_being_formatted: HashSet<BufferId>,
263 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
264 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
265 watched_manifest_filenames: HashSet<ManifestName>,
266 language_server_paths_watched_for_rename:
267 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
268 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
269 supplementary_language_servers:
270 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
271 prettier_store: Entity<PrettierStore>,
272 next_diagnostic_group_id: usize,
273 diagnostics: HashMap<
274 WorktreeId,
275 HashMap<
276 Arc<RelPath>,
277 Vec<(
278 LanguageServerId,
279 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
280 )>,
281 >,
282 >,
283 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
284 _subscription: gpui::Subscription,
285 lsp_tree: LanguageServerTree,
286 registered_buffers: HashMap<BufferId, usize>,
287 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
288 buffer_pull_diagnostics_result_ids: HashMap<
289 LanguageServerId,
290 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
291 >,
292 workspace_pull_diagnostics_result_ids: HashMap<
293 LanguageServerId,
294 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
295 >,
296}
297
298impl LocalLspStore {
299 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
300 pub fn running_language_server_for_id(
301 &self,
302 id: LanguageServerId,
303 ) -> Option<&Arc<LanguageServer>> {
304 let language_server_state = self.language_servers.get(&id)?;
305
306 match language_server_state {
307 LanguageServerState::Running { server, .. } => Some(server),
308 LanguageServerState::Starting { .. } => None,
309 }
310 }
311
312 fn get_or_insert_language_server(
313 &mut self,
314 worktree_handle: &Entity<Worktree>,
315 delegate: Arc<LocalLspAdapterDelegate>,
316 disposition: &Arc<LaunchDisposition>,
317 language_name: &LanguageName,
318 cx: &mut App,
319 ) -> LanguageServerId {
320 let key = LanguageServerSeed {
321 worktree_id: worktree_handle.read(cx).id(),
322 name: disposition.server_name.clone(),
323 settings: disposition.settings.clone(),
324 toolchain: disposition.toolchain.clone(),
325 };
326 if let Some(state) = self.language_server_ids.get_mut(&key) {
327 state.project_roots.insert(disposition.path.path.clone());
328 state.id
329 } else {
330 let adapter = self
331 .languages
332 .lsp_adapters(language_name)
333 .into_iter()
334 .find(|adapter| adapter.name() == disposition.server_name)
335 .expect("To find LSP adapter");
336 let new_language_server_id = self.start_language_server(
337 worktree_handle,
338 delegate,
339 adapter,
340 disposition.settings.clone(),
341 key.clone(),
342 cx,
343 );
344 if let Some(state) = self.language_server_ids.get_mut(&key) {
345 state.project_roots.insert(disposition.path.path.clone());
346 } else {
347 debug_assert!(
348 false,
349 "Expected `start_language_server` to ensure that `key` exists in a map"
350 );
351 }
352 new_language_server_id
353 }
354 }
355
356 fn start_language_server(
357 &mut self,
358 worktree_handle: &Entity<Worktree>,
359 delegate: Arc<LocalLspAdapterDelegate>,
360 adapter: Arc<CachedLspAdapter>,
361 settings: Arc<LspSettings>,
362 key: LanguageServerSeed,
363 cx: &mut App,
364 ) -> LanguageServerId {
365 let worktree = worktree_handle.read(cx);
366
367 let root_path = worktree.abs_path();
368 let toolchain = key.toolchain.clone();
369 let override_options = settings.initialization_options.clone();
370
371 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
372
373 let server_id = self.languages.next_language_server_id();
374 log::trace!(
375 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
376 adapter.name.0
377 );
378
379 let binary = self.get_language_server_binary(
380 adapter.clone(),
381 settings,
382 toolchain.clone(),
383 delegate.clone(),
384 true,
385 cx,
386 );
387 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
388
389 let pending_server = cx.spawn({
390 let adapter = adapter.clone();
391 let server_name = adapter.name.clone();
392 let stderr_capture = stderr_capture.clone();
393 #[cfg(any(test, feature = "test-support"))]
394 let lsp_store = self.weak.clone();
395 let pending_workspace_folders = pending_workspace_folders.clone();
396 async move |cx| {
397 let binary = binary.await?;
398 #[cfg(any(test, feature = "test-support"))]
399 if let Some(server) = lsp_store
400 .update(&mut cx.clone(), |this, cx| {
401 this.languages.create_fake_language_server(
402 server_id,
403 &server_name,
404 binary.clone(),
405 &mut cx.to_async(),
406 )
407 })
408 .ok()
409 .flatten()
410 {
411 return Ok(server);
412 }
413
414 let code_action_kinds = adapter.code_action_kinds();
415 lsp::LanguageServer::new(
416 stderr_capture,
417 server_id,
418 server_name,
419 binary,
420 &root_path,
421 code_action_kinds,
422 Some(pending_workspace_folders),
423 cx,
424 )
425 .await
426 }
427 });
428
429 let startup = {
430 let server_name = adapter.name.0.clone();
431 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
432 let key = key.clone();
433 let adapter = adapter.clone();
434 let lsp_store = self.weak.clone();
435 let pending_workspace_folders = pending_workspace_folders.clone();
436
437 let pull_diagnostics = ProjectSettings::get_global(cx)
438 .diagnostics
439 .lsp_pull_diagnostics
440 .enabled;
441 cx.spawn(async move |cx| {
442 let result = async {
443 let language_server = pending_server.await?;
444
445 let workspace_config = Self::workspace_configuration_for_adapter(
446 adapter.adapter.clone(),
447 &delegate,
448 toolchain,
449 None,
450 cx,
451 )
452 .await?;
453
454 let mut initialization_options = Self::initialization_options_for_adapter(
455 adapter.adapter.clone(),
456 &delegate,
457 )
458 .await?;
459
460 match (&mut initialization_options, override_options) {
461 (Some(initialization_options), Some(override_options)) => {
462 merge_json_value_into(override_options, initialization_options);
463 }
464 (None, override_options) => initialization_options = override_options,
465 _ => {}
466 }
467
468 let initialization_params = cx.update(|cx| {
469 let mut params =
470 language_server.default_initialize_params(pull_diagnostics, cx);
471 params.initialization_options = initialization_options;
472 adapter.adapter.prepare_initialize_params(params, cx)
473 })??;
474
475 Self::setup_lsp_messages(
476 lsp_store.clone(),
477 &language_server,
478 delegate.clone(),
479 adapter.clone(),
480 );
481
482 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
483 settings: workspace_config,
484 };
485 let language_server = cx
486 .update(|cx| {
487 language_server.initialize(
488 initialization_params,
489 Arc::new(did_change_configuration_params.clone()),
490 cx,
491 )
492 })?
493 .await
494 .inspect_err(|_| {
495 if let Some(lsp_store) = lsp_store.upgrade() {
496 lsp_store
497 .update(cx, |lsp_store, cx| {
498 lsp_store.cleanup_lsp_data(server_id);
499 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
500 })
501 .ok();
502 }
503 })?;
504
505 language_server.notify::<lsp::notification::DidChangeConfiguration>(
506 did_change_configuration_params,
507 )?;
508
509 anyhow::Ok(language_server)
510 }
511 .await;
512
513 match result {
514 Ok(server) => {
515 lsp_store
516 .update(cx, |lsp_store, cx| {
517 lsp_store.insert_newly_running_language_server(
518 adapter,
519 server.clone(),
520 server_id,
521 key,
522 pending_workspace_folders,
523 cx,
524 );
525 })
526 .ok();
527 stderr_capture.lock().take();
528 Some(server)
529 }
530
531 Err(err) => {
532 let log = stderr_capture.lock().take().unwrap_or_default();
533 delegate.update_status(
534 adapter.name(),
535 BinaryStatus::Failed {
536 error: if log.is_empty() {
537 format!("{err:#}")
538 } else {
539 format!("{err:#}\n-- stderr --\n{log}")
540 },
541 },
542 );
543 log::error!("Failed to start language server {server_name:?}: {err:?}");
544 if !log.is_empty() {
545 log::error!("server stderr: {log}");
546 }
547 None
548 }
549 }
550 })
551 };
552 let state = LanguageServerState::Starting {
553 startup,
554 pending_workspace_folders,
555 };
556
557 self.languages
558 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
559
560 self.language_servers.insert(server_id, state);
561 self.language_server_ids
562 .entry(key)
563 .or_insert(UnifiedLanguageServer {
564 id: server_id,
565 project_roots: Default::default(),
566 });
567 server_id
568 }
569
570 fn get_language_server_binary(
571 &self,
572 adapter: Arc<CachedLspAdapter>,
573 settings: Arc<LspSettings>,
574 toolchain: Option<Toolchain>,
575 delegate: Arc<dyn LspAdapterDelegate>,
576 allow_binary_download: bool,
577 cx: &mut App,
578 ) -> Task<Result<LanguageServerBinary>> {
579 if let Some(settings) = &settings.binary
580 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
581 {
582 let settings = settings.clone();
583
584 return cx.background_spawn(async move {
585 let mut env = delegate.shell_env().await;
586 env.extend(settings.env.unwrap_or_default());
587
588 Ok(LanguageServerBinary {
589 path: delegate.resolve_executable_path(path),
590 env: Some(env),
591 arguments: settings
592 .arguments
593 .unwrap_or_default()
594 .iter()
595 .map(Into::into)
596 .collect(),
597 })
598 });
599 }
600 let lsp_binary_options = LanguageServerBinaryOptions {
601 allow_path_lookup: !settings
602 .binary
603 .as_ref()
604 .and_then(|b| b.ignore_system_version)
605 .unwrap_or_default(),
606 allow_binary_download,
607 pre_release: settings
608 .fetch
609 .as_ref()
610 .and_then(|f| f.pre_release)
611 .unwrap_or(false),
612 };
613
614 cx.spawn(async move |cx| {
615 let (existing_binary, maybe_download_binary) = adapter
616 .clone()
617 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
618 .await
619 .await;
620
621 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
622
623 let mut binary = match (existing_binary, maybe_download_binary) {
624 (binary, None) => binary?,
625 (Err(_), Some(downloader)) => downloader.await?,
626 (Ok(existing_binary), Some(downloader)) => {
627 let mut download_timeout = cx
628 .background_executor()
629 .timer(SERVER_DOWNLOAD_TIMEOUT)
630 .fuse();
631 let mut downloader = downloader.fuse();
632 futures::select! {
633 _ = download_timeout => {
634 // Return existing binary and kick the existing work to the background.
635 cx.spawn(async move |_| downloader.await).detach();
636 Ok(existing_binary)
637 },
638 downloaded_or_existing_binary = downloader => {
639 // If download fails, this results in the existing binary.
640 downloaded_or_existing_binary
641 }
642 }?
643 }
644 };
645 let mut shell_env = delegate.shell_env().await;
646
647 shell_env.extend(binary.env.unwrap_or_default());
648
649 if let Some(settings) = settings.binary.as_ref() {
650 if let Some(arguments) = &settings.arguments {
651 binary.arguments = arguments.iter().map(Into::into).collect();
652 }
653 if let Some(env) = &settings.env {
654 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
655 }
656 }
657
658 binary.env = Some(shell_env);
659 Ok(binary)
660 })
661 }
662
663 fn setup_lsp_messages(
664 lsp_store: WeakEntity<LspStore>,
665 language_server: &LanguageServer,
666 delegate: Arc<dyn LspAdapterDelegate>,
667 adapter: Arc<CachedLspAdapter>,
668 ) {
669 let name = language_server.name();
670 let server_id = language_server.server_id();
671 language_server
672 .on_notification::<lsp::notification::PublishDiagnostics, _>({
673 let adapter = adapter.clone();
674 let this = lsp_store.clone();
675 move |mut params, cx| {
676 let adapter = adapter.clone();
677 if let Some(this) = this.upgrade() {
678 this.update(cx, |this, cx| {
679 {
680 let buffer = params
681 .uri
682 .to_file_path()
683 .map(|file_path| this.get_buffer(&file_path, cx))
684 .ok()
685 .flatten();
686 adapter.process_diagnostics(&mut params, server_id, buffer);
687 }
688
689 this.merge_lsp_diagnostics(
690 DiagnosticSourceKind::Pushed,
691 vec![DocumentDiagnosticsUpdate {
692 server_id,
693 diagnostics: params,
694 result_id: None,
695 disk_based_sources: Cow::Borrowed(
696 &adapter.disk_based_diagnostic_sources,
697 ),
698 registration_id: None,
699 }],
700 |_, diagnostic, cx| match diagnostic.source_kind {
701 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
702 adapter.retain_old_diagnostic(diagnostic, cx)
703 }
704 DiagnosticSourceKind::Pulled => true,
705 },
706 cx,
707 )
708 .log_err();
709 })
710 .ok();
711 }
712 }
713 })
714 .detach();
715 language_server
716 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
717 let adapter = adapter.adapter.clone();
718 let delegate = delegate.clone();
719 let this = lsp_store.clone();
720 move |params, cx| {
721 let adapter = adapter.clone();
722 let delegate = delegate.clone();
723 let this = this.clone();
724 let mut cx = cx.clone();
725 async move {
726 let toolchain_for_id = this
727 .update(&mut cx, |this, _| {
728 this.as_local()?.language_server_ids.iter().find_map(
729 |(seed, value)| {
730 (value.id == server_id).then(|| seed.toolchain.clone())
731 },
732 )
733 })?
734 .context("Expected the LSP store to be in a local mode")?;
735
736 let mut scope_uri_to_workspace_config = BTreeMap::new();
737 for item in ¶ms.items {
738 let scope_uri = item.scope_uri.clone();
739 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
740 scope_uri_to_workspace_config.entry(scope_uri.clone())
741 else {
742 // We've already queried workspace configuration of this URI.
743 continue;
744 };
745 let workspace_config = Self::workspace_configuration_for_adapter(
746 adapter.clone(),
747 &delegate,
748 toolchain_for_id.clone(),
749 scope_uri,
750 &mut cx,
751 )
752 .await?;
753 new_scope_uri.insert(workspace_config);
754 }
755
756 Ok(params
757 .items
758 .into_iter()
759 .filter_map(|item| {
760 let workspace_config =
761 scope_uri_to_workspace_config.get(&item.scope_uri)?;
762 if let Some(section) = &item.section {
763 Some(
764 workspace_config
765 .get(section)
766 .cloned()
767 .unwrap_or(serde_json::Value::Null),
768 )
769 } else {
770 Some(workspace_config.clone())
771 }
772 })
773 .collect())
774 }
775 }
776 })
777 .detach();
778
779 language_server
780 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
781 let this = lsp_store.clone();
782 move |_, cx| {
783 let this = this.clone();
784 let cx = cx.clone();
785 async move {
786 let Some(server) =
787 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
788 else {
789 return Ok(None);
790 };
791 let root = server.workspace_folders();
792 Ok(Some(
793 root.into_iter()
794 .map(|uri| WorkspaceFolder {
795 uri,
796 name: Default::default(),
797 })
798 .collect(),
799 ))
800 }
801 }
802 })
803 .detach();
804 // Even though we don't have handling for these requests, respond to them to
805 // avoid stalling any language server like `gopls` which waits for a response
806 // to these requests when initializing.
807 language_server
808 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
809 let this = lsp_store.clone();
810 move |params, cx| {
811 let this = this.clone();
812 let mut cx = cx.clone();
813 async move {
814 this.update(&mut cx, |this, _| {
815 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
816 {
817 status
818 .progress_tokens
819 .insert(ProgressToken::from_lsp(params.token));
820 }
821 })?;
822
823 Ok(())
824 }
825 }
826 })
827 .detach();
828
829 language_server
830 .on_request::<lsp::request::RegisterCapability, _, _>({
831 let lsp_store = lsp_store.clone();
832 move |params, cx| {
833 let lsp_store = lsp_store.clone();
834 let mut cx = cx.clone();
835 async move {
836 lsp_store
837 .update(&mut cx, |lsp_store, cx| {
838 if lsp_store.as_local().is_some() {
839 match lsp_store
840 .register_server_capabilities(server_id, params, cx)
841 {
842 Ok(()) => {}
843 Err(e) => {
844 log::error!(
845 "Failed to register server capabilities: {e:#}"
846 );
847 }
848 };
849 }
850 })
851 .ok();
852 Ok(())
853 }
854 }
855 })
856 .detach();
857
858 language_server
859 .on_request::<lsp::request::UnregisterCapability, _, _>({
860 let lsp_store = lsp_store.clone();
861 move |params, cx| {
862 let lsp_store = lsp_store.clone();
863 let mut cx = cx.clone();
864 async move {
865 lsp_store
866 .update(&mut cx, |lsp_store, cx| {
867 if lsp_store.as_local().is_some() {
868 match lsp_store
869 .unregister_server_capabilities(server_id, params, cx)
870 {
871 Ok(()) => {}
872 Err(e) => {
873 log::error!(
874 "Failed to unregister server capabilities: {e:#}"
875 );
876 }
877 }
878 }
879 })
880 .ok();
881 Ok(())
882 }
883 }
884 })
885 .detach();
886
887 language_server
888 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
889 let this = lsp_store.clone();
890 move |params, cx| {
891 let mut cx = cx.clone();
892 let this = this.clone();
893 async move {
894 LocalLspStore::on_lsp_workspace_edit(
895 this.clone(),
896 params,
897 server_id,
898 &mut cx,
899 )
900 .await
901 }
902 }
903 })
904 .detach();
905
906 language_server
907 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
908 let lsp_store = lsp_store.clone();
909 let request_id = Arc::new(AtomicUsize::new(0));
910 move |(), cx| {
911 let lsp_store = lsp_store.clone();
912 let request_id = request_id.clone();
913 let mut cx = cx.clone();
914 async move {
915 lsp_store
916 .update(&mut cx, |lsp_store, cx| {
917 let request_id =
918 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
919 cx.emit(LspStoreEvent::RefreshInlayHints {
920 server_id,
921 request_id,
922 });
923 lsp_store
924 .downstream_client
925 .as_ref()
926 .map(|(client, project_id)| {
927 client.send(proto::RefreshInlayHints {
928 project_id: *project_id,
929 server_id: server_id.to_proto(),
930 request_id: request_id.map(|id| id as u64),
931 })
932 })
933 })?
934 .transpose()?;
935 Ok(())
936 }
937 }
938 })
939 .detach();
940
941 language_server
942 .on_request::<lsp::request::CodeLensRefresh, _, _>({
943 let this = lsp_store.clone();
944 move |(), cx| {
945 let this = this.clone();
946 let mut cx = cx.clone();
947 async move {
948 this.update(&mut cx, |this, cx| {
949 cx.emit(LspStoreEvent::RefreshCodeLens);
950 this.downstream_client.as_ref().map(|(client, project_id)| {
951 client.send(proto::RefreshCodeLens {
952 project_id: *project_id,
953 })
954 })
955 })?
956 .transpose()?;
957 Ok(())
958 }
959 }
960 })
961 .detach();
962
963 language_server
964 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
965 let this = lsp_store.clone();
966 move |(), cx| {
967 let this = this.clone();
968 let mut cx = cx.clone();
969 async move {
970 this.update(&mut cx, |lsp_store, _| {
971 lsp_store.pull_workspace_diagnostics(server_id);
972 lsp_store
973 .downstream_client
974 .as_ref()
975 .map(|(client, project_id)| {
976 client.send(proto::PullWorkspaceDiagnostics {
977 project_id: *project_id,
978 server_id: server_id.to_proto(),
979 })
980 })
981 })?
982 .transpose()?;
983 Ok(())
984 }
985 }
986 })
987 .detach();
988
989 language_server
990 .on_request::<lsp::request::ShowMessageRequest, _, _>({
991 let this = lsp_store.clone();
992 let name = name.to_string();
993 move |params, cx| {
994 let this = this.clone();
995 let name = name.to_string();
996 let mut cx = cx.clone();
997 async move {
998 let actions = params.actions.unwrap_or_default();
999 let (tx, rx) = smol::channel::bounded(1);
1000 let request = LanguageServerPromptRequest {
1001 level: match params.typ {
1002 lsp::MessageType::ERROR => PromptLevel::Critical,
1003 lsp::MessageType::WARNING => PromptLevel::Warning,
1004 _ => PromptLevel::Info,
1005 },
1006 message: params.message,
1007 actions,
1008 response_channel: tx,
1009 lsp_name: name.clone(),
1010 };
1011
1012 let did_update = this
1013 .update(&mut cx, |_, cx| {
1014 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1015 })
1016 .is_ok();
1017 if did_update {
1018 let response = rx.recv().await.ok();
1019 Ok(response)
1020 } else {
1021 Ok(None)
1022 }
1023 }
1024 }
1025 })
1026 .detach();
1027 language_server
1028 .on_notification::<lsp::notification::ShowMessage, _>({
1029 let this = lsp_store.clone();
1030 let name = name.to_string();
1031 move |params, cx| {
1032 let this = this.clone();
1033 let name = name.to_string();
1034 let mut cx = cx.clone();
1035
1036 let (tx, _) = smol::channel::bounded(1);
1037 let request = LanguageServerPromptRequest {
1038 level: match params.typ {
1039 lsp::MessageType::ERROR => PromptLevel::Critical,
1040 lsp::MessageType::WARNING => PromptLevel::Warning,
1041 _ => PromptLevel::Info,
1042 },
1043 message: params.message,
1044 actions: vec![],
1045 response_channel: tx,
1046 lsp_name: name,
1047 };
1048
1049 let _ = this.update(&mut cx, |_, cx| {
1050 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1051 });
1052 }
1053 })
1054 .detach();
1055
1056 let disk_based_diagnostics_progress_token =
1057 adapter.disk_based_diagnostics_progress_token.clone();
1058
1059 language_server
1060 .on_notification::<lsp::notification::Progress, _>({
1061 let this = lsp_store.clone();
1062 move |params, cx| {
1063 if let Some(this) = this.upgrade() {
1064 this.update(cx, |this, cx| {
1065 this.on_lsp_progress(
1066 params,
1067 server_id,
1068 disk_based_diagnostics_progress_token.clone(),
1069 cx,
1070 );
1071 })
1072 .ok();
1073 }
1074 }
1075 })
1076 .detach();
1077
1078 language_server
1079 .on_notification::<lsp::notification::LogMessage, _>({
1080 let this = lsp_store.clone();
1081 move |params, cx| {
1082 if let Some(this) = this.upgrade() {
1083 this.update(cx, |_, cx| {
1084 cx.emit(LspStoreEvent::LanguageServerLog(
1085 server_id,
1086 LanguageServerLogType::Log(params.typ),
1087 params.message,
1088 ));
1089 })
1090 .ok();
1091 }
1092 }
1093 })
1094 .detach();
1095
1096 language_server
1097 .on_notification::<lsp::notification::LogTrace, _>({
1098 let this = lsp_store.clone();
1099 move |params, cx| {
1100 let mut cx = cx.clone();
1101 if let Some(this) = this.upgrade() {
1102 this.update(&mut cx, |_, cx| {
1103 cx.emit(LspStoreEvent::LanguageServerLog(
1104 server_id,
1105 LanguageServerLogType::Trace {
1106 verbose_info: params.verbose,
1107 },
1108 params.message,
1109 ));
1110 })
1111 .ok();
1112 }
1113 }
1114 })
1115 .detach();
1116
1117 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1118 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1119 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1120 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1121 }
1122
1123 fn shutdown_language_servers_on_quit(
1124 &mut self,
1125 _: &mut Context<LspStore>,
1126 ) -> impl Future<Output = ()> + use<> {
1127 let shutdown_futures = self
1128 .language_servers
1129 .drain()
1130 .map(|(_, server_state)| Self::shutdown_server(server_state))
1131 .collect::<Vec<_>>();
1132
1133 async move {
1134 join_all(shutdown_futures).await;
1135 }
1136 }
1137
1138 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1139 match server_state {
1140 LanguageServerState::Running { server, .. } => {
1141 if let Some(shutdown) = server.shutdown() {
1142 shutdown.await;
1143 }
1144 }
1145 LanguageServerState::Starting { startup, .. } => {
1146 if let Some(server) = startup.await
1147 && let Some(shutdown) = server.shutdown()
1148 {
1149 shutdown.await;
1150 }
1151 }
1152 }
1153 Ok(())
1154 }
1155
1156 fn language_servers_for_worktree(
1157 &self,
1158 worktree_id: WorktreeId,
1159 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1160 self.language_server_ids
1161 .iter()
1162 .filter_map(move |(seed, state)| {
1163 if seed.worktree_id != worktree_id {
1164 return None;
1165 }
1166
1167 if let Some(LanguageServerState::Running { server, .. }) =
1168 self.language_servers.get(&state.id)
1169 {
1170 Some(server)
1171 } else {
1172 None
1173 }
1174 })
1175 }
1176
1177 fn language_server_ids_for_project_path(
1178 &self,
1179 project_path: ProjectPath,
1180 language: &Language,
1181 cx: &mut App,
1182 ) -> Vec<LanguageServerId> {
1183 let Some(worktree) = self
1184 .worktree_store
1185 .read(cx)
1186 .worktree_for_id(project_path.worktree_id, cx)
1187 else {
1188 return Vec::new();
1189 };
1190 let delegate: Arc<dyn ManifestDelegate> =
1191 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1192
1193 self.lsp_tree
1194 .get(
1195 project_path,
1196 language.name(),
1197 language.manifest(),
1198 &delegate,
1199 cx,
1200 )
1201 .collect::<Vec<_>>()
1202 }
1203
1204 fn language_server_ids_for_buffer(
1205 &self,
1206 buffer: &Buffer,
1207 cx: &mut App,
1208 ) -> Vec<LanguageServerId> {
1209 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1210 let worktree_id = file.worktree_id(cx);
1211
1212 let path: Arc<RelPath> = file
1213 .path()
1214 .parent()
1215 .map(Arc::from)
1216 .unwrap_or_else(|| file.path().clone());
1217 let worktree_path = ProjectPath { worktree_id, path };
1218 self.language_server_ids_for_project_path(worktree_path, language, cx)
1219 } else {
1220 Vec::new()
1221 }
1222 }
1223
1224 fn language_servers_for_buffer<'a>(
1225 &'a self,
1226 buffer: &'a Buffer,
1227 cx: &'a mut App,
1228 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1229 self.language_server_ids_for_buffer(buffer, cx)
1230 .into_iter()
1231 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1232 LanguageServerState::Running {
1233 adapter, server, ..
1234 } => Some((adapter, server)),
1235 _ => None,
1236 })
1237 }
1238
1239 async fn execute_code_action_kind_locally(
1240 lsp_store: WeakEntity<LspStore>,
1241 mut buffers: Vec<Entity<Buffer>>,
1242 kind: CodeActionKind,
1243 push_to_history: bool,
1244 cx: &mut AsyncApp,
1245 ) -> anyhow::Result<ProjectTransaction> {
1246 // Do not allow multiple concurrent code actions requests for the
1247 // same buffer.
1248 lsp_store.update(cx, |this, cx| {
1249 let this = this.as_local_mut().unwrap();
1250 buffers.retain(|buffer| {
1251 this.buffers_being_formatted
1252 .insert(buffer.read(cx).remote_id())
1253 });
1254 })?;
1255 let _cleanup = defer({
1256 let this = lsp_store.clone();
1257 let mut cx = cx.clone();
1258 let buffers = &buffers;
1259 move || {
1260 this.update(&mut cx, |this, cx| {
1261 let this = this.as_local_mut().unwrap();
1262 for buffer in buffers {
1263 this.buffers_being_formatted
1264 .remove(&buffer.read(cx).remote_id());
1265 }
1266 })
1267 .ok();
1268 }
1269 });
1270 let mut project_transaction = ProjectTransaction::default();
1271
1272 for buffer in &buffers {
1273 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1274 buffer.update(cx, |buffer, cx| {
1275 lsp_store
1276 .as_local()
1277 .unwrap()
1278 .language_servers_for_buffer(buffer, cx)
1279 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1280 .collect::<Vec<_>>()
1281 })
1282 })?;
1283 for (_, language_server) in adapters_and_servers.iter() {
1284 let actions = Self::get_server_code_actions_from_action_kinds(
1285 &lsp_store,
1286 language_server.server_id(),
1287 vec![kind.clone()],
1288 buffer,
1289 cx,
1290 )
1291 .await?;
1292 Self::execute_code_actions_on_server(
1293 &lsp_store,
1294 language_server,
1295 actions,
1296 push_to_history,
1297 &mut project_transaction,
1298 cx,
1299 )
1300 .await?;
1301 }
1302 }
1303 Ok(project_transaction)
1304 }
1305
1306 async fn format_locally(
1307 lsp_store: WeakEntity<LspStore>,
1308 mut buffers: Vec<FormattableBuffer>,
1309 push_to_history: bool,
1310 trigger: FormatTrigger,
1311 logger: zlog::Logger,
1312 cx: &mut AsyncApp,
1313 ) -> anyhow::Result<ProjectTransaction> {
1314 // Do not allow multiple concurrent formatting requests for the
1315 // same buffer.
1316 lsp_store.update(cx, |this, cx| {
1317 let this = this.as_local_mut().unwrap();
1318 buffers.retain(|buffer| {
1319 this.buffers_being_formatted
1320 .insert(buffer.handle.read(cx).remote_id())
1321 });
1322 })?;
1323
1324 let _cleanup = defer({
1325 let this = lsp_store.clone();
1326 let mut cx = cx.clone();
1327 let buffers = &buffers;
1328 move || {
1329 this.update(&mut cx, |this, cx| {
1330 let this = this.as_local_mut().unwrap();
1331 for buffer in buffers {
1332 this.buffers_being_formatted
1333 .remove(&buffer.handle.read(cx).remote_id());
1334 }
1335 })
1336 .ok();
1337 }
1338 });
1339
1340 let mut project_transaction = ProjectTransaction::default();
1341
1342 for buffer in &buffers {
1343 zlog::debug!(
1344 logger =>
1345 "formatting buffer '{:?}'",
1346 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1347 );
1348 // Create an empty transaction to hold all of the formatting edits.
1349 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1350 // ensure no transactions created while formatting are
1351 // grouped with the previous transaction in the history
1352 // based on the transaction group interval
1353 buffer.finalize_last_transaction();
1354 buffer
1355 .start_transaction()
1356 .context("transaction already open")?;
1357 buffer.end_transaction(cx);
1358 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1359 buffer.finalize_last_transaction();
1360 anyhow::Ok(transaction_id)
1361 })??;
1362
1363 let result = Self::format_buffer_locally(
1364 lsp_store.clone(),
1365 buffer,
1366 formatting_transaction_id,
1367 trigger,
1368 logger,
1369 cx,
1370 )
1371 .await;
1372
1373 buffer.handle.update(cx, |buffer, cx| {
1374 let Some(formatting_transaction) =
1375 buffer.get_transaction(formatting_transaction_id).cloned()
1376 else {
1377 zlog::warn!(logger => "no formatting transaction");
1378 return;
1379 };
1380 if formatting_transaction.edit_ids.is_empty() {
1381 zlog::debug!(logger => "no changes made while formatting");
1382 buffer.forget_transaction(formatting_transaction_id);
1383 return;
1384 }
1385 if !push_to_history {
1386 zlog::trace!(logger => "forgetting format transaction");
1387 buffer.forget_transaction(formatting_transaction.id);
1388 }
1389 project_transaction
1390 .0
1391 .insert(cx.entity(), formatting_transaction);
1392 })?;
1393
1394 result?;
1395 }
1396
1397 Ok(project_transaction)
1398 }
1399
1400 async fn format_buffer_locally(
1401 lsp_store: WeakEntity<LspStore>,
1402 buffer: &FormattableBuffer,
1403 formatting_transaction_id: clock::Lamport,
1404 trigger: FormatTrigger,
1405 logger: zlog::Logger,
1406 cx: &mut AsyncApp,
1407 ) -> Result<()> {
1408 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1409 buffer.handle.update(cx, |buffer, cx| {
1410 let adapters_and_servers = lsp_store
1411 .as_local()
1412 .unwrap()
1413 .language_servers_for_buffer(buffer, cx)
1414 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1415 .collect::<Vec<_>>();
1416 let settings =
1417 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1418 .into_owned();
1419 (adapters_and_servers, settings)
1420 })
1421 })?;
1422
1423 /// Apply edits to the buffer that will become part of the formatting transaction.
1424 /// Fails if the buffer has been edited since the start of that transaction.
1425 fn extend_formatting_transaction(
1426 buffer: &FormattableBuffer,
1427 formatting_transaction_id: text::TransactionId,
1428 cx: &mut AsyncApp,
1429 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1430 ) -> anyhow::Result<()> {
1431 buffer.handle.update(cx, |buffer, cx| {
1432 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1433 if last_transaction_id != Some(formatting_transaction_id) {
1434 anyhow::bail!("Buffer edited while formatting. Aborting")
1435 }
1436 buffer.start_transaction();
1437 operation(buffer, cx);
1438 if let Some(transaction_id) = buffer.end_transaction(cx) {
1439 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1440 }
1441 Ok(())
1442 })?
1443 }
1444
1445 // handle whitespace formatting
1446 if settings.remove_trailing_whitespace_on_save {
1447 zlog::trace!(logger => "removing trailing whitespace");
1448 let diff = buffer
1449 .handle
1450 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1451 .await;
1452 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1453 buffer.apply_diff(diff, cx);
1454 })?;
1455 }
1456
1457 if settings.ensure_final_newline_on_save {
1458 zlog::trace!(logger => "ensuring final newline");
1459 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1460 buffer.ensure_final_newline(cx);
1461 })?;
1462 }
1463
1464 // Formatter for `code_actions_on_format` that runs before
1465 // the rest of the formatters
1466 let mut code_actions_on_format_formatters = None;
1467 let should_run_code_actions_on_format = !matches!(
1468 (trigger, &settings.format_on_save),
1469 (FormatTrigger::Save, &FormatOnSave::Off)
1470 );
1471 if should_run_code_actions_on_format {
1472 let have_code_actions_to_run_on_format = settings
1473 .code_actions_on_format
1474 .values()
1475 .any(|enabled| *enabled);
1476 if have_code_actions_to_run_on_format {
1477 zlog::trace!(logger => "going to run code actions on format");
1478 code_actions_on_format_formatters = Some(
1479 settings
1480 .code_actions_on_format
1481 .iter()
1482 .filter_map(|(action, enabled)| enabled.then_some(action))
1483 .cloned()
1484 .map(Formatter::CodeAction)
1485 .collect::<Vec<_>>(),
1486 );
1487 }
1488 }
1489
1490 let formatters = match (trigger, &settings.format_on_save) {
1491 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1492 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1493 settings.formatter.as_ref()
1494 }
1495 };
1496
1497 let formatters = code_actions_on_format_formatters
1498 .iter()
1499 .flatten()
1500 .chain(formatters);
1501
1502 for formatter in formatters {
1503 let formatter = if formatter == &Formatter::Auto {
1504 if settings.prettier.allowed {
1505 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1506 &Formatter::Prettier
1507 } else {
1508 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1509 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1510 }
1511 } else {
1512 formatter
1513 };
1514 match formatter {
1515 Formatter::Auto => unreachable!("Auto resolved above"),
1516 Formatter::Prettier => {
1517 let logger = zlog::scoped!(logger => "prettier");
1518 zlog::trace!(logger => "formatting");
1519 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1520
1521 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1522 lsp_store.prettier_store().unwrap().downgrade()
1523 })?;
1524 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1525 .await
1526 .transpose()?;
1527 let Some(diff) = diff else {
1528 zlog::trace!(logger => "No changes");
1529 continue;
1530 };
1531
1532 extend_formatting_transaction(
1533 buffer,
1534 formatting_transaction_id,
1535 cx,
1536 |buffer, cx| {
1537 buffer.apply_diff(diff, cx);
1538 },
1539 )?;
1540 }
1541 Formatter::External { command, arguments } => {
1542 let logger = zlog::scoped!(logger => "command");
1543 zlog::trace!(logger => "formatting");
1544 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1545
1546 let diff = Self::format_via_external_command(
1547 buffer,
1548 command.as_ref(),
1549 arguments.as_deref(),
1550 cx,
1551 )
1552 .await
1553 .with_context(|| {
1554 format!("Failed to format buffer via external command: {}", command)
1555 })?;
1556 let Some(diff) = diff else {
1557 zlog::trace!(logger => "No changes");
1558 continue;
1559 };
1560
1561 extend_formatting_transaction(
1562 buffer,
1563 formatting_transaction_id,
1564 cx,
1565 |buffer, cx| {
1566 buffer.apply_diff(diff, cx);
1567 },
1568 )?;
1569 }
1570 Formatter::LanguageServer(specifier) => {
1571 let logger = zlog::scoped!(logger => "language-server");
1572 zlog::trace!(logger => "formatting");
1573 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1574
1575 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1576 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1577 continue;
1578 };
1579
1580 let language_server = match specifier {
1581 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1582 adapters_and_servers.iter().find_map(|(adapter, server)| {
1583 if adapter.name.0.as_ref() == name {
1584 Some(server.clone())
1585 } else {
1586 None
1587 }
1588 })
1589 }
1590 settings::LanguageServerFormatterSpecifier::Current => {
1591 adapters_and_servers.first().map(|e| e.1.clone())
1592 }
1593 };
1594
1595 let Some(language_server) = language_server else {
1596 log::debug!(
1597 "No language server found to format buffer '{:?}'. Skipping",
1598 buffer_path_abs.as_path().to_string_lossy()
1599 );
1600 continue;
1601 };
1602
1603 zlog::trace!(
1604 logger =>
1605 "Formatting buffer '{:?}' using language server '{:?}'",
1606 buffer_path_abs.as_path().to_string_lossy(),
1607 language_server.name()
1608 );
1609
1610 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1611 zlog::trace!(logger => "formatting ranges");
1612 Self::format_ranges_via_lsp(
1613 &lsp_store,
1614 &buffer.handle,
1615 ranges,
1616 buffer_path_abs,
1617 &language_server,
1618 &settings,
1619 cx,
1620 )
1621 .await
1622 .context("Failed to format ranges via language server")?
1623 } else {
1624 zlog::trace!(logger => "formatting full");
1625 Self::format_via_lsp(
1626 &lsp_store,
1627 &buffer.handle,
1628 buffer_path_abs,
1629 &language_server,
1630 &settings,
1631 cx,
1632 )
1633 .await
1634 .context("failed to format via language server")?
1635 };
1636
1637 if edits.is_empty() {
1638 zlog::trace!(logger => "No changes");
1639 continue;
1640 }
1641 extend_formatting_transaction(
1642 buffer,
1643 formatting_transaction_id,
1644 cx,
1645 |buffer, cx| {
1646 buffer.edit(edits, None, cx);
1647 },
1648 )?;
1649 }
1650 Formatter::CodeAction(code_action_name) => {
1651 let logger = zlog::scoped!(logger => "code-actions");
1652 zlog::trace!(logger => "formatting");
1653 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1654
1655 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1656 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1657 continue;
1658 };
1659
1660 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1661 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1662
1663 let mut actions_and_servers = Vec::new();
1664
1665 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1666 let actions_result = Self::get_server_code_actions_from_action_kinds(
1667 &lsp_store,
1668 language_server.server_id(),
1669 vec![code_action_kind.clone()],
1670 &buffer.handle,
1671 cx,
1672 )
1673 .await
1674 .with_context(|| {
1675 format!(
1676 "Failed to resolve code action {:?} with language server {}",
1677 code_action_kind,
1678 language_server.name()
1679 )
1680 });
1681 let Ok(actions) = actions_result else {
1682 // note: it may be better to set result to the error and break formatters here
1683 // but for now we try to execute the actions that we can resolve and skip the rest
1684 zlog::error!(
1685 logger =>
1686 "Failed to resolve code action {:?} with language server {}",
1687 code_action_kind,
1688 language_server.name()
1689 );
1690 continue;
1691 };
1692 for action in actions {
1693 actions_and_servers.push((action, index));
1694 }
1695 }
1696
1697 if actions_and_servers.is_empty() {
1698 zlog::warn!(logger => "No code actions were resolved, continuing");
1699 continue;
1700 }
1701
1702 'actions: for (mut action, server_index) in actions_and_servers {
1703 let server = &adapters_and_servers[server_index].1;
1704
1705 let describe_code_action = |action: &CodeAction| {
1706 format!(
1707 "code action '{}' with title \"{}\" on server {}",
1708 action
1709 .lsp_action
1710 .action_kind()
1711 .unwrap_or("unknown".into())
1712 .as_str(),
1713 action.lsp_action.title(),
1714 server.name(),
1715 )
1716 };
1717
1718 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1719
1720 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1721 zlog::error!(
1722 logger =>
1723 "Failed to resolve {}. Error: {}",
1724 describe_code_action(&action),
1725 err
1726 );
1727 continue;
1728 }
1729
1730 if let Some(edit) = action.lsp_action.edit().cloned() {
1731 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1732 // but filters out and logs warnings for code actions that require unreasonably
1733 // difficult handling on our part, such as:
1734 // - applying edits that call commands
1735 // which can result in arbitrary workspace edits being sent from the server that
1736 // have no way of being tied back to the command that initiated them (i.e. we
1737 // can't know which edits are part of the format request, or if the server is done sending
1738 // actions in response to the command)
1739 // - actions that create/delete/modify/rename files other than the one we are formatting
1740 // as we then would need to handle such changes correctly in the local history as well
1741 // as the remote history through the ProjectTransaction
1742 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1743 // Supporting these actions is not impossible, but not supported as of yet.
1744 if edit.changes.is_none() && edit.document_changes.is_none() {
1745 zlog::trace!(
1746 logger =>
1747 "No changes for code action. Skipping {}",
1748 describe_code_action(&action),
1749 );
1750 continue;
1751 }
1752
1753 let mut operations = Vec::new();
1754 if let Some(document_changes) = edit.document_changes {
1755 match document_changes {
1756 lsp::DocumentChanges::Edits(edits) => operations.extend(
1757 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1758 ),
1759 lsp::DocumentChanges::Operations(ops) => operations = ops,
1760 }
1761 } else if let Some(changes) = edit.changes {
1762 operations.extend(changes.into_iter().map(|(uri, edits)| {
1763 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1764 text_document:
1765 lsp::OptionalVersionedTextDocumentIdentifier {
1766 uri,
1767 version: None,
1768 },
1769 edits: edits.into_iter().map(Edit::Plain).collect(),
1770 })
1771 }));
1772 }
1773
1774 let mut edits = Vec::with_capacity(operations.len());
1775
1776 if operations.is_empty() {
1777 zlog::trace!(
1778 logger =>
1779 "No changes for code action. Skipping {}",
1780 describe_code_action(&action),
1781 );
1782 continue;
1783 }
1784 for operation in operations {
1785 let op = match operation {
1786 lsp::DocumentChangeOperation::Edit(op) => op,
1787 lsp::DocumentChangeOperation::Op(_) => {
1788 zlog::warn!(
1789 logger =>
1790 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1791 describe_code_action(&action),
1792 );
1793 continue 'actions;
1794 }
1795 };
1796 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1797 zlog::warn!(
1798 logger =>
1799 "Failed to convert URI '{:?}' to file path. Skipping {}",
1800 &op.text_document.uri,
1801 describe_code_action(&action),
1802 );
1803 continue 'actions;
1804 };
1805 if &file_path != buffer_path_abs {
1806 zlog::warn!(
1807 logger =>
1808 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1809 file_path,
1810 buffer_path_abs,
1811 describe_code_action(&action),
1812 );
1813 continue 'actions;
1814 }
1815
1816 let mut lsp_edits = Vec::new();
1817 for edit in op.edits {
1818 match edit {
1819 Edit::Plain(edit) => {
1820 if !lsp_edits.contains(&edit) {
1821 lsp_edits.push(edit);
1822 }
1823 }
1824 Edit::Annotated(edit) => {
1825 if !lsp_edits.contains(&edit.text_edit) {
1826 lsp_edits.push(edit.text_edit);
1827 }
1828 }
1829 Edit::Snippet(_) => {
1830 zlog::warn!(
1831 logger =>
1832 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1833 describe_code_action(&action),
1834 );
1835 continue 'actions;
1836 }
1837 }
1838 }
1839 let edits_result = lsp_store
1840 .update(cx, |lsp_store, cx| {
1841 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1842 &buffer.handle,
1843 lsp_edits,
1844 server.server_id(),
1845 op.text_document.version,
1846 cx,
1847 )
1848 })?
1849 .await;
1850 let Ok(resolved_edits) = edits_result else {
1851 zlog::warn!(
1852 logger =>
1853 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1854 buffer_path_abs.as_path(),
1855 describe_code_action(&action),
1856 );
1857 continue 'actions;
1858 };
1859 edits.extend(resolved_edits);
1860 }
1861
1862 if edits.is_empty() {
1863 zlog::warn!(logger => "No edits resolved from LSP");
1864 continue;
1865 }
1866
1867 extend_formatting_transaction(
1868 buffer,
1869 formatting_transaction_id,
1870 cx,
1871 |buffer, cx| {
1872 zlog::info!(
1873 "Applying edits {edits:?}. Content: {:?}",
1874 buffer.text()
1875 );
1876 buffer.edit(edits, None, cx);
1877 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1878 },
1879 )?;
1880 }
1881
1882 if let Some(command) = action.lsp_action.command() {
1883 zlog::warn!(
1884 logger =>
1885 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1886 &command.command,
1887 );
1888
1889 // bail early if command is invalid
1890 let server_capabilities = server.capabilities();
1891 let available_commands = server_capabilities
1892 .execute_command_provider
1893 .as_ref()
1894 .map(|options| options.commands.as_slice())
1895 .unwrap_or_default();
1896 if !available_commands.contains(&command.command) {
1897 zlog::warn!(
1898 logger =>
1899 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1900 command.command,
1901 server.name(),
1902 );
1903 continue;
1904 }
1905
1906 // noop so we just ensure buffer hasn't been edited since resolving code actions
1907 extend_formatting_transaction(
1908 buffer,
1909 formatting_transaction_id,
1910 cx,
1911 |_, _| {},
1912 )?;
1913 zlog::info!(logger => "Executing command {}", &command.command);
1914
1915 lsp_store.update(cx, |this, _| {
1916 this.as_local_mut()
1917 .unwrap()
1918 .last_workspace_edits_by_language_server
1919 .remove(&server.server_id());
1920 })?;
1921
1922 let execute_command_result = server
1923 .request::<lsp::request::ExecuteCommand>(
1924 lsp::ExecuteCommandParams {
1925 command: command.command.clone(),
1926 arguments: command.arguments.clone().unwrap_or_default(),
1927 ..Default::default()
1928 },
1929 )
1930 .await
1931 .into_response();
1932
1933 if execute_command_result.is_err() {
1934 zlog::error!(
1935 logger =>
1936 "Failed to execute command '{}' as part of {}",
1937 &command.command,
1938 describe_code_action(&action),
1939 );
1940 continue 'actions;
1941 }
1942
1943 let mut project_transaction_command =
1944 lsp_store.update(cx, |this, _| {
1945 this.as_local_mut()
1946 .unwrap()
1947 .last_workspace_edits_by_language_server
1948 .remove(&server.server_id())
1949 .unwrap_or_default()
1950 })?;
1951
1952 if let Some(transaction) =
1953 project_transaction_command.0.remove(&buffer.handle)
1954 {
1955 zlog::trace!(
1956 logger =>
1957 "Successfully captured {} edits that resulted from command {}",
1958 transaction.edit_ids.len(),
1959 &command.command,
1960 );
1961 let transaction_id_project_transaction = transaction.id;
1962 buffer.handle.update(cx, |buffer, _| {
1963 // it may have been removed from history if push_to_history was
1964 // false in deserialize_workspace_edit. If so push it so we
1965 // can merge it with the format transaction
1966 // and pop the combined transaction off the history stack
1967 // later if push_to_history is false
1968 if buffer.get_transaction(transaction.id).is_none() {
1969 buffer.push_transaction(transaction, Instant::now());
1970 }
1971 buffer.merge_transactions(
1972 transaction_id_project_transaction,
1973 formatting_transaction_id,
1974 );
1975 })?;
1976 }
1977
1978 if !project_transaction_command.0.is_empty() {
1979 let mut extra_buffers = String::new();
1980 for buffer in project_transaction_command.0.keys() {
1981 buffer
1982 .read_with(cx, |b, cx| {
1983 if let Some(path) = b.project_path(cx) {
1984 if !extra_buffers.is_empty() {
1985 extra_buffers.push_str(", ");
1986 }
1987 extra_buffers.push_str(path.path.as_unix_str());
1988 }
1989 })
1990 .ok();
1991 }
1992 zlog::warn!(
1993 logger =>
1994 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1995 &command.command,
1996 extra_buffers,
1997 );
1998 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1999 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2000 // add it so it's included, and merge it into the format transaction when its created later
2001 }
2002 }
2003 }
2004 }
2005 }
2006 }
2007
2008 Ok(())
2009 }
2010
2011 pub async fn format_ranges_via_lsp(
2012 this: &WeakEntity<LspStore>,
2013 buffer_handle: &Entity<Buffer>,
2014 ranges: &[Range<Anchor>],
2015 abs_path: &Path,
2016 language_server: &Arc<LanguageServer>,
2017 settings: &LanguageSettings,
2018 cx: &mut AsyncApp,
2019 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2020 let capabilities = &language_server.capabilities();
2021 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2022 if range_formatting_provider == Some(&OneOf::Left(false)) {
2023 anyhow::bail!(
2024 "{} language server does not support range formatting",
2025 language_server.name()
2026 );
2027 }
2028
2029 let uri = file_path_to_lsp_url(abs_path)?;
2030 let text_document = lsp::TextDocumentIdentifier::new(uri);
2031
2032 let lsp_edits = {
2033 let mut lsp_ranges = Vec::new();
2034 this.update(cx, |_this, cx| {
2035 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2036 // not have been sent to the language server. This seems like a fairly systemic
2037 // issue, though, the resolution probably is not specific to formatting.
2038 //
2039 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2040 // LSP.
2041 let snapshot = buffer_handle.read(cx).snapshot();
2042 for range in ranges {
2043 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2044 }
2045 anyhow::Ok(())
2046 })??;
2047
2048 let mut edits = None;
2049 for range in lsp_ranges {
2050 if let Some(mut edit) = language_server
2051 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2052 text_document: text_document.clone(),
2053 range,
2054 options: lsp_command::lsp_formatting_options(settings),
2055 work_done_progress_params: Default::default(),
2056 })
2057 .await
2058 .into_response()?
2059 {
2060 edits.get_or_insert_with(Vec::new).append(&mut edit);
2061 }
2062 }
2063 edits
2064 };
2065
2066 if let Some(lsp_edits) = lsp_edits {
2067 this.update(cx, |this, cx| {
2068 this.as_local_mut().unwrap().edits_from_lsp(
2069 buffer_handle,
2070 lsp_edits,
2071 language_server.server_id(),
2072 None,
2073 cx,
2074 )
2075 })?
2076 .await
2077 } else {
2078 Ok(Vec::with_capacity(0))
2079 }
2080 }
2081
2082 async fn format_via_lsp(
2083 this: &WeakEntity<LspStore>,
2084 buffer: &Entity<Buffer>,
2085 abs_path: &Path,
2086 language_server: &Arc<LanguageServer>,
2087 settings: &LanguageSettings,
2088 cx: &mut AsyncApp,
2089 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2090 let logger = zlog::scoped!("lsp_format");
2091 zlog::debug!(logger => "Formatting via LSP");
2092
2093 let uri = file_path_to_lsp_url(abs_path)?;
2094 let text_document = lsp::TextDocumentIdentifier::new(uri);
2095 let capabilities = &language_server.capabilities();
2096
2097 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2098 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2099
2100 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2101 let _timer = zlog::time!(logger => "format-full");
2102 language_server
2103 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2104 text_document,
2105 options: lsp_command::lsp_formatting_options(settings),
2106 work_done_progress_params: Default::default(),
2107 })
2108 .await
2109 .into_response()?
2110 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2111 let _timer = zlog::time!(logger => "format-range");
2112 let buffer_start = lsp::Position::new(0, 0);
2113 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2114 language_server
2115 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2116 text_document: text_document.clone(),
2117 range: lsp::Range::new(buffer_start, buffer_end),
2118 options: lsp_command::lsp_formatting_options(settings),
2119 work_done_progress_params: Default::default(),
2120 })
2121 .await
2122 .into_response()?
2123 } else {
2124 None
2125 };
2126
2127 if let Some(lsp_edits) = lsp_edits {
2128 this.update(cx, |this, cx| {
2129 this.as_local_mut().unwrap().edits_from_lsp(
2130 buffer,
2131 lsp_edits,
2132 language_server.server_id(),
2133 None,
2134 cx,
2135 )
2136 })?
2137 .await
2138 } else {
2139 Ok(Vec::with_capacity(0))
2140 }
2141 }
2142
2143 async fn format_via_external_command(
2144 buffer: &FormattableBuffer,
2145 command: &str,
2146 arguments: Option<&[String]>,
2147 cx: &mut AsyncApp,
2148 ) -> Result<Option<Diff>> {
2149 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2150 let file = File::from_dyn(buffer.file())?;
2151 let worktree = file.worktree.read(cx);
2152 let mut worktree_path = worktree.abs_path().to_path_buf();
2153 if worktree.root_entry()?.is_file() {
2154 worktree_path.pop();
2155 }
2156 Some(worktree_path)
2157 })?;
2158
2159 let mut child = util::command::new_smol_command(command);
2160
2161 if let Some(buffer_env) = buffer.env.as_ref() {
2162 child.envs(buffer_env);
2163 }
2164
2165 if let Some(working_dir_path) = working_dir_path {
2166 child.current_dir(working_dir_path);
2167 }
2168
2169 if let Some(arguments) = arguments {
2170 child.args(arguments.iter().map(|arg| {
2171 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2172 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2173 } else {
2174 arg.replace("{buffer_path}", "Untitled")
2175 }
2176 }));
2177 }
2178
2179 let mut child = child
2180 .stdin(smol::process::Stdio::piped())
2181 .stdout(smol::process::Stdio::piped())
2182 .stderr(smol::process::Stdio::piped())
2183 .spawn()?;
2184
2185 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2186 let text = buffer
2187 .handle
2188 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2189 for chunk in text.chunks() {
2190 stdin.write_all(chunk.as_bytes()).await?;
2191 }
2192 stdin.flush().await?;
2193
2194 let output = child.output().await?;
2195 anyhow::ensure!(
2196 output.status.success(),
2197 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2198 output.status.code(),
2199 String::from_utf8_lossy(&output.stdout),
2200 String::from_utf8_lossy(&output.stderr),
2201 );
2202
2203 let stdout = String::from_utf8(output.stdout)?;
2204 Ok(Some(
2205 buffer
2206 .handle
2207 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2208 .await,
2209 ))
2210 }
2211
2212 async fn try_resolve_code_action(
2213 lang_server: &LanguageServer,
2214 action: &mut CodeAction,
2215 ) -> anyhow::Result<()> {
2216 match &mut action.lsp_action {
2217 LspAction::Action(lsp_action) => {
2218 if !action.resolved
2219 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2220 && lsp_action.data.is_some()
2221 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2222 {
2223 *lsp_action = Box::new(
2224 lang_server
2225 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2226 .await
2227 .into_response()?,
2228 );
2229 }
2230 }
2231 LspAction::CodeLens(lens) => {
2232 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2233 *lens = lang_server
2234 .request::<lsp::request::CodeLensResolve>(lens.clone())
2235 .await
2236 .into_response()?;
2237 }
2238 }
2239 LspAction::Command(_) => {}
2240 }
2241
2242 action.resolved = true;
2243 anyhow::Ok(())
2244 }
2245
2246 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2247 let buffer = buffer_handle.read(cx);
2248
2249 let file = buffer.file().cloned();
2250
2251 let Some(file) = File::from_dyn(file.as_ref()) else {
2252 return;
2253 };
2254 if !file.is_local() {
2255 return;
2256 }
2257 let path = ProjectPath::from_file(file, cx);
2258 let worktree_id = file.worktree_id(cx);
2259 let language = buffer.language().cloned();
2260
2261 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2262 for (server_id, diagnostics) in
2263 diagnostics.get(file.path()).cloned().unwrap_or_default()
2264 {
2265 self.update_buffer_diagnostics(
2266 buffer_handle,
2267 server_id,
2268 None,
2269 None,
2270 None,
2271 Vec::new(),
2272 diagnostics,
2273 cx,
2274 )
2275 .log_err();
2276 }
2277 }
2278 let Some(language) = language else {
2279 return;
2280 };
2281 let Some(snapshot) = self
2282 .worktree_store
2283 .read(cx)
2284 .worktree_for_id(worktree_id, cx)
2285 .map(|worktree| worktree.read(cx).snapshot())
2286 else {
2287 return;
2288 };
2289 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2290
2291 for server_id in
2292 self.lsp_tree
2293 .get(path, language.name(), language.manifest(), &delegate, cx)
2294 {
2295 let server = self
2296 .language_servers
2297 .get(&server_id)
2298 .and_then(|server_state| {
2299 if let LanguageServerState::Running { server, .. } = server_state {
2300 Some(server.clone())
2301 } else {
2302 None
2303 }
2304 });
2305 let server = match server {
2306 Some(server) => server,
2307 None => continue,
2308 };
2309
2310 buffer_handle.update(cx, |buffer, cx| {
2311 buffer.set_completion_triggers(
2312 server.server_id(),
2313 server
2314 .capabilities()
2315 .completion_provider
2316 .as_ref()
2317 .and_then(|provider| {
2318 provider
2319 .trigger_characters
2320 .as_ref()
2321 .map(|characters| characters.iter().cloned().collect())
2322 })
2323 .unwrap_or_default(),
2324 cx,
2325 );
2326 });
2327 }
2328 }
2329
2330 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2331 buffer.update(cx, |buffer, cx| {
2332 let Some(language) = buffer.language() else {
2333 return;
2334 };
2335 let path = ProjectPath {
2336 worktree_id: old_file.worktree_id(cx),
2337 path: old_file.path.clone(),
2338 };
2339 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2340 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2341 buffer.set_completion_triggers(server_id, Default::default(), cx);
2342 }
2343 });
2344 }
2345
2346 fn update_buffer_diagnostics(
2347 &mut self,
2348 buffer: &Entity<Buffer>,
2349 server_id: LanguageServerId,
2350 registration_id: Option<Option<SharedString>>,
2351 result_id: Option<SharedString>,
2352 version: Option<i32>,
2353 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2354 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2355 cx: &mut Context<LspStore>,
2356 ) -> Result<()> {
2357 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2358 Ordering::Equal
2359 .then_with(|| b.is_primary.cmp(&a.is_primary))
2360 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2361 .then_with(|| a.severity.cmp(&b.severity))
2362 .then_with(|| a.message.cmp(&b.message))
2363 }
2364
2365 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2366 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2367 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2368
2369 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2370 Ordering::Equal
2371 .then_with(|| a.range.start.cmp(&b.range.start))
2372 .then_with(|| b.range.end.cmp(&a.range.end))
2373 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2374 });
2375
2376 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2377
2378 let edits_since_save = std::cell::LazyCell::new(|| {
2379 let saved_version = buffer.read(cx).saved_version();
2380 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2381 });
2382
2383 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2384
2385 for (new_diagnostic, entry) in diagnostics {
2386 let start;
2387 let end;
2388 if new_diagnostic && entry.diagnostic.is_disk_based {
2389 // Some diagnostics are based on files on disk instead of buffers'
2390 // current contents. Adjust these diagnostics' ranges to reflect
2391 // any unsaved edits.
2392 // Do not alter the reused ones though, as their coordinates were stored as anchors
2393 // and were properly adjusted on reuse.
2394 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2395 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2396 } else {
2397 start = entry.range.start;
2398 end = entry.range.end;
2399 }
2400
2401 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2402 ..snapshot.clip_point_utf16(end, Bias::Right);
2403
2404 // Expand empty ranges by one codepoint
2405 if range.start == range.end {
2406 // This will be go to the next boundary when being clipped
2407 range.end.column += 1;
2408 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2409 if range.start == range.end && range.end.column > 0 {
2410 range.start.column -= 1;
2411 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2412 }
2413 }
2414
2415 sanitized_diagnostics.push(DiagnosticEntry {
2416 range,
2417 diagnostic: entry.diagnostic,
2418 });
2419 }
2420 drop(edits_since_save);
2421
2422 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2423 buffer.update(cx, |buffer, cx| {
2424 if let Some(registration_id) = registration_id {
2425 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2426 self.buffer_pull_diagnostics_result_ids
2427 .entry(server_id)
2428 .or_default()
2429 .entry(registration_id)
2430 .or_default()
2431 .insert(abs_path, result_id);
2432 }
2433 }
2434
2435 buffer.update_diagnostics(server_id, set, cx)
2436 });
2437
2438 Ok(())
2439 }
2440
2441 fn register_language_server_for_invisible_worktree(
2442 &mut self,
2443 worktree: &Entity<Worktree>,
2444 language_server_id: LanguageServerId,
2445 cx: &mut App,
2446 ) {
2447 let worktree = worktree.read(cx);
2448 let worktree_id = worktree.id();
2449 debug_assert!(!worktree.is_visible());
2450 let Some(mut origin_seed) = self
2451 .language_server_ids
2452 .iter()
2453 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2454 else {
2455 return;
2456 };
2457 origin_seed.worktree_id = worktree_id;
2458 self.language_server_ids
2459 .entry(origin_seed)
2460 .or_insert_with(|| UnifiedLanguageServer {
2461 id: language_server_id,
2462 project_roots: Default::default(),
2463 });
2464 }
2465
2466 fn register_buffer_with_language_servers(
2467 &mut self,
2468 buffer_handle: &Entity<Buffer>,
2469 only_register_servers: HashSet<LanguageServerSelector>,
2470 cx: &mut Context<LspStore>,
2471 ) {
2472 let buffer = buffer_handle.read(cx);
2473 let buffer_id = buffer.remote_id();
2474
2475 let Some(file) = File::from_dyn(buffer.file()) else {
2476 return;
2477 };
2478 if !file.is_local() {
2479 return;
2480 }
2481
2482 let abs_path = file.abs_path(cx);
2483 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2484 return;
2485 };
2486 let initial_snapshot = buffer.text_snapshot();
2487 let worktree_id = file.worktree_id(cx);
2488
2489 let Some(language) = buffer.language().cloned() else {
2490 return;
2491 };
2492 let path: Arc<RelPath> = file
2493 .path()
2494 .parent()
2495 .map(Arc::from)
2496 .unwrap_or_else(|| file.path().clone());
2497 let Some(worktree) = self
2498 .worktree_store
2499 .read(cx)
2500 .worktree_for_id(worktree_id, cx)
2501 else {
2502 return;
2503 };
2504 let language_name = language.name();
2505 let (reused, delegate, servers) = self
2506 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2507 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2508 .unwrap_or_else(|| {
2509 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2510 let delegate: Arc<dyn ManifestDelegate> =
2511 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2512
2513 let servers = self
2514 .lsp_tree
2515 .walk(
2516 ProjectPath { worktree_id, path },
2517 language.name(),
2518 language.manifest(),
2519 &delegate,
2520 cx,
2521 )
2522 .collect::<Vec<_>>();
2523 (false, lsp_delegate, servers)
2524 });
2525 let servers_and_adapters = servers
2526 .into_iter()
2527 .filter_map(|server_node| {
2528 if reused && server_node.server_id().is_none() {
2529 return None;
2530 }
2531 if !only_register_servers.is_empty() {
2532 if let Some(server_id) = server_node.server_id()
2533 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2534 {
2535 return None;
2536 }
2537 if let Some(name) = server_node.name()
2538 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2539 {
2540 return None;
2541 }
2542 }
2543
2544 let server_id = server_node.server_id_or_init(|disposition| {
2545 let path = &disposition.path;
2546
2547 {
2548 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2549
2550 let server_id = self.get_or_insert_language_server(
2551 &worktree,
2552 delegate.clone(),
2553 disposition,
2554 &language_name,
2555 cx,
2556 );
2557
2558 if let Some(state) = self.language_servers.get(&server_id)
2559 && let Ok(uri) = uri
2560 {
2561 state.add_workspace_folder(uri);
2562 };
2563 server_id
2564 }
2565 })?;
2566 let server_state = self.language_servers.get(&server_id)?;
2567 if let LanguageServerState::Running {
2568 server, adapter, ..
2569 } = server_state
2570 {
2571 Some((server.clone(), adapter.clone()))
2572 } else {
2573 None
2574 }
2575 })
2576 .collect::<Vec<_>>();
2577 for (server, adapter) in servers_and_adapters {
2578 buffer_handle.update(cx, |buffer, cx| {
2579 buffer.set_completion_triggers(
2580 server.server_id(),
2581 server
2582 .capabilities()
2583 .completion_provider
2584 .as_ref()
2585 .and_then(|provider| {
2586 provider
2587 .trigger_characters
2588 .as_ref()
2589 .map(|characters| characters.iter().cloned().collect())
2590 })
2591 .unwrap_or_default(),
2592 cx,
2593 );
2594 });
2595
2596 let snapshot = LspBufferSnapshot {
2597 version: 0,
2598 snapshot: initial_snapshot.clone(),
2599 };
2600
2601 let mut registered = false;
2602 self.buffer_snapshots
2603 .entry(buffer_id)
2604 .or_default()
2605 .entry(server.server_id())
2606 .or_insert_with(|| {
2607 registered = true;
2608 server.register_buffer(
2609 uri.clone(),
2610 adapter.language_id(&language.name()),
2611 0,
2612 initial_snapshot.text(),
2613 );
2614
2615 vec![snapshot]
2616 });
2617
2618 self.buffers_opened_in_servers
2619 .entry(buffer_id)
2620 .or_default()
2621 .insert(server.server_id());
2622 if registered {
2623 cx.emit(LspStoreEvent::LanguageServerUpdate {
2624 language_server_id: server.server_id(),
2625 name: None,
2626 message: proto::update_language_server::Variant::RegisteredForBuffer(
2627 proto::RegisteredForBuffer {
2628 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2629 buffer_id: buffer_id.to_proto(),
2630 },
2631 ),
2632 });
2633 }
2634 }
2635 }
2636
2637 fn reuse_existing_language_server<'lang_name>(
2638 &self,
2639 server_tree: &LanguageServerTree,
2640 worktree: &Entity<Worktree>,
2641 language_name: &'lang_name LanguageName,
2642 cx: &mut App,
2643 ) -> Option<(
2644 Arc<LocalLspAdapterDelegate>,
2645 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2646 )> {
2647 if worktree.read(cx).is_visible() {
2648 return None;
2649 }
2650
2651 let worktree_store = self.worktree_store.read(cx);
2652 let servers = server_tree
2653 .instances
2654 .iter()
2655 .filter(|(worktree_id, _)| {
2656 worktree_store
2657 .worktree_for_id(**worktree_id, cx)
2658 .is_some_and(|worktree| worktree.read(cx).is_visible())
2659 })
2660 .flat_map(|(worktree_id, servers)| {
2661 servers
2662 .roots
2663 .iter()
2664 .flat_map(|(_, language_servers)| language_servers)
2665 .map(move |(_, (server_node, server_languages))| {
2666 (worktree_id, server_node, server_languages)
2667 })
2668 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2669 .map(|(worktree_id, server_node, _)| {
2670 (
2671 *worktree_id,
2672 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2673 )
2674 })
2675 })
2676 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2677 acc.entry(worktree_id)
2678 .or_insert_with(Vec::new)
2679 .push(server_node);
2680 acc
2681 })
2682 .into_values()
2683 .max_by_key(|servers| servers.len())?;
2684
2685 let worktree_id = worktree.read(cx).id();
2686 let apply = move |tree: &mut LanguageServerTree| {
2687 for server_node in &servers {
2688 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2689 }
2690 servers
2691 };
2692
2693 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2694 Some((delegate, apply))
2695 }
2696
2697 pub(crate) fn unregister_old_buffer_from_language_servers(
2698 &mut self,
2699 buffer: &Entity<Buffer>,
2700 old_file: &File,
2701 cx: &mut App,
2702 ) {
2703 let old_path = match old_file.as_local() {
2704 Some(local) => local.abs_path(cx),
2705 None => return,
2706 };
2707
2708 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2709 debug_panic!("{old_path:?} is not parseable as an URI");
2710 return;
2711 };
2712 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2713 }
2714
2715 pub(crate) fn unregister_buffer_from_language_servers(
2716 &mut self,
2717 buffer: &Entity<Buffer>,
2718 file_url: &lsp::Uri,
2719 cx: &mut App,
2720 ) {
2721 buffer.update(cx, |buffer, cx| {
2722 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2723
2724 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2725 if snapshots
2726 .as_mut()
2727 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2728 {
2729 language_server.unregister_buffer(file_url.clone());
2730 }
2731 }
2732 });
2733 }
2734
2735 fn buffer_snapshot_for_lsp_version(
2736 &mut self,
2737 buffer: &Entity<Buffer>,
2738 server_id: LanguageServerId,
2739 version: Option<i32>,
2740 cx: &App,
2741 ) -> Result<TextBufferSnapshot> {
2742 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2743
2744 if let Some(version) = version {
2745 let buffer_id = buffer.read(cx).remote_id();
2746 let snapshots = if let Some(snapshots) = self
2747 .buffer_snapshots
2748 .get_mut(&buffer_id)
2749 .and_then(|m| m.get_mut(&server_id))
2750 {
2751 snapshots
2752 } else if version == 0 {
2753 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2754 // We detect this case and treat it as if the version was `None`.
2755 return Ok(buffer.read(cx).text_snapshot());
2756 } else {
2757 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2758 };
2759
2760 let found_snapshot = snapshots
2761 .binary_search_by_key(&version, |e| e.version)
2762 .map(|ix| snapshots[ix].snapshot.clone())
2763 .map_err(|_| {
2764 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2765 })?;
2766
2767 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2768 Ok(found_snapshot)
2769 } else {
2770 Ok((buffer.read(cx)).text_snapshot())
2771 }
2772 }
2773
2774 async fn get_server_code_actions_from_action_kinds(
2775 lsp_store: &WeakEntity<LspStore>,
2776 language_server_id: LanguageServerId,
2777 code_action_kinds: Vec<lsp::CodeActionKind>,
2778 buffer: &Entity<Buffer>,
2779 cx: &mut AsyncApp,
2780 ) -> Result<Vec<CodeAction>> {
2781 let actions = lsp_store
2782 .update(cx, move |this, cx| {
2783 let request = GetCodeActions {
2784 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2785 kinds: Some(code_action_kinds),
2786 };
2787 let server = LanguageServerToQuery::Other(language_server_id);
2788 this.request_lsp(buffer.clone(), server, request, cx)
2789 })?
2790 .await?;
2791 Ok(actions)
2792 }
2793
2794 pub async fn execute_code_actions_on_server(
2795 lsp_store: &WeakEntity<LspStore>,
2796 language_server: &Arc<LanguageServer>,
2797
2798 actions: Vec<CodeAction>,
2799 push_to_history: bool,
2800 project_transaction: &mut ProjectTransaction,
2801 cx: &mut AsyncApp,
2802 ) -> anyhow::Result<()> {
2803 for mut action in actions {
2804 Self::try_resolve_code_action(language_server, &mut action)
2805 .await
2806 .context("resolving a formatting code action")?;
2807
2808 if let Some(edit) = action.lsp_action.edit() {
2809 if edit.changes.is_none() && edit.document_changes.is_none() {
2810 continue;
2811 }
2812
2813 let new = Self::deserialize_workspace_edit(
2814 lsp_store.upgrade().context("project dropped")?,
2815 edit.clone(),
2816 push_to_history,
2817 language_server.clone(),
2818 cx,
2819 )
2820 .await?;
2821 project_transaction.0.extend(new.0);
2822 }
2823
2824 if let Some(command) = action.lsp_action.command() {
2825 let server_capabilities = language_server.capabilities();
2826 let available_commands = server_capabilities
2827 .execute_command_provider
2828 .as_ref()
2829 .map(|options| options.commands.as_slice())
2830 .unwrap_or_default();
2831 if available_commands.contains(&command.command) {
2832 lsp_store.update(cx, |lsp_store, _| {
2833 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2834 mode.last_workspace_edits_by_language_server
2835 .remove(&language_server.server_id());
2836 }
2837 })?;
2838
2839 language_server
2840 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2841 command: command.command.clone(),
2842 arguments: command.arguments.clone().unwrap_or_default(),
2843 ..Default::default()
2844 })
2845 .await
2846 .into_response()
2847 .context("execute command")?;
2848
2849 lsp_store.update(cx, |this, _| {
2850 if let LspStoreMode::Local(mode) = &mut this.mode {
2851 project_transaction.0.extend(
2852 mode.last_workspace_edits_by_language_server
2853 .remove(&language_server.server_id())
2854 .unwrap_or_default()
2855 .0,
2856 )
2857 }
2858 })?;
2859 } else {
2860 log::warn!(
2861 "Cannot execute a command {} not listed in the language server capabilities",
2862 command.command
2863 )
2864 }
2865 }
2866 }
2867 Ok(())
2868 }
2869
2870 pub async fn deserialize_text_edits(
2871 this: Entity<LspStore>,
2872 buffer_to_edit: Entity<Buffer>,
2873 edits: Vec<lsp::TextEdit>,
2874 push_to_history: bool,
2875 _: Arc<CachedLspAdapter>,
2876 language_server: Arc<LanguageServer>,
2877 cx: &mut AsyncApp,
2878 ) -> Result<Option<Transaction>> {
2879 let edits = this
2880 .update(cx, |this, cx| {
2881 this.as_local_mut().unwrap().edits_from_lsp(
2882 &buffer_to_edit,
2883 edits,
2884 language_server.server_id(),
2885 None,
2886 cx,
2887 )
2888 })?
2889 .await?;
2890
2891 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2892 buffer.finalize_last_transaction();
2893 buffer.start_transaction();
2894 for (range, text) in edits {
2895 buffer.edit([(range, text)], None, cx);
2896 }
2897
2898 if buffer.end_transaction(cx).is_some() {
2899 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2900 if !push_to_history {
2901 buffer.forget_transaction(transaction.id);
2902 }
2903 Some(transaction)
2904 } else {
2905 None
2906 }
2907 })?;
2908
2909 Ok(transaction)
2910 }
2911
2912 #[allow(clippy::type_complexity)]
2913 pub(crate) fn edits_from_lsp(
2914 &mut self,
2915 buffer: &Entity<Buffer>,
2916 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2917 server_id: LanguageServerId,
2918 version: Option<i32>,
2919 cx: &mut Context<LspStore>,
2920 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2921 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2922 cx.background_spawn(async move {
2923 let snapshot = snapshot?;
2924 let mut lsp_edits = lsp_edits
2925 .into_iter()
2926 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2927 .collect::<Vec<_>>();
2928
2929 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2930
2931 let mut lsp_edits = lsp_edits.into_iter().peekable();
2932 let mut edits = Vec::new();
2933 while let Some((range, mut new_text)) = lsp_edits.next() {
2934 // Clip invalid ranges provided by the language server.
2935 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2936 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2937
2938 // Combine any LSP edits that are adjacent.
2939 //
2940 // Also, combine LSP edits that are separated from each other by only
2941 // a newline. This is important because for some code actions,
2942 // Rust-analyzer rewrites the entire buffer via a series of edits that
2943 // are separated by unchanged newline characters.
2944 //
2945 // In order for the diffing logic below to work properly, any edits that
2946 // cancel each other out must be combined into one.
2947 while let Some((next_range, next_text)) = lsp_edits.peek() {
2948 if next_range.start.0 > range.end {
2949 if next_range.start.0.row > range.end.row + 1
2950 || next_range.start.0.column > 0
2951 || snapshot.clip_point_utf16(
2952 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2953 Bias::Left,
2954 ) > range.end
2955 {
2956 break;
2957 }
2958 new_text.push('\n');
2959 }
2960 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2961 new_text.push_str(next_text);
2962 lsp_edits.next();
2963 }
2964
2965 // For multiline edits, perform a diff of the old and new text so that
2966 // we can identify the changes more precisely, preserving the locations
2967 // of any anchors positioned in the unchanged regions.
2968 if range.end.row > range.start.row {
2969 let offset = range.start.to_offset(&snapshot);
2970 let old_text = snapshot.text_for_range(range).collect::<String>();
2971 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2972 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2973 (
2974 snapshot.anchor_after(offset + range.start)
2975 ..snapshot.anchor_before(offset + range.end),
2976 replacement,
2977 )
2978 }));
2979 } else if range.end == range.start {
2980 let anchor = snapshot.anchor_after(range.start);
2981 edits.push((anchor..anchor, new_text.into()));
2982 } else {
2983 let edit_start = snapshot.anchor_after(range.start);
2984 let edit_end = snapshot.anchor_before(range.end);
2985 edits.push((edit_start..edit_end, new_text.into()));
2986 }
2987 }
2988
2989 Ok(edits)
2990 })
2991 }
2992
2993 pub(crate) async fn deserialize_workspace_edit(
2994 this: Entity<LspStore>,
2995 edit: lsp::WorkspaceEdit,
2996 push_to_history: bool,
2997 language_server: Arc<LanguageServer>,
2998 cx: &mut AsyncApp,
2999 ) -> Result<ProjectTransaction> {
3000 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3001
3002 let mut operations = Vec::new();
3003 if let Some(document_changes) = edit.document_changes {
3004 match document_changes {
3005 lsp::DocumentChanges::Edits(edits) => {
3006 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3007 }
3008 lsp::DocumentChanges::Operations(ops) => operations = ops,
3009 }
3010 } else if let Some(changes) = edit.changes {
3011 operations.extend(changes.into_iter().map(|(uri, edits)| {
3012 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3013 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3014 uri,
3015 version: None,
3016 },
3017 edits: edits.into_iter().map(Edit::Plain).collect(),
3018 })
3019 }));
3020 }
3021
3022 let mut project_transaction = ProjectTransaction::default();
3023 for operation in operations {
3024 match operation {
3025 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3026 let abs_path = op
3027 .uri
3028 .to_file_path()
3029 .map_err(|()| anyhow!("can't convert URI to path"))?;
3030
3031 if let Some(parent_path) = abs_path.parent() {
3032 fs.create_dir(parent_path).await?;
3033 }
3034 if abs_path.ends_with("/") {
3035 fs.create_dir(&abs_path).await?;
3036 } else {
3037 fs.create_file(
3038 &abs_path,
3039 op.options
3040 .map(|options| fs::CreateOptions {
3041 overwrite: options.overwrite.unwrap_or(false),
3042 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3043 })
3044 .unwrap_or_default(),
3045 )
3046 .await?;
3047 }
3048 }
3049
3050 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3051 let source_abs_path = op
3052 .old_uri
3053 .to_file_path()
3054 .map_err(|()| anyhow!("can't convert URI to path"))?;
3055 let target_abs_path = op
3056 .new_uri
3057 .to_file_path()
3058 .map_err(|()| anyhow!("can't convert URI to path"))?;
3059
3060 let options = fs::RenameOptions {
3061 overwrite: op
3062 .options
3063 .as_ref()
3064 .and_then(|options| options.overwrite)
3065 .unwrap_or(false),
3066 ignore_if_exists: op
3067 .options
3068 .as_ref()
3069 .and_then(|options| options.ignore_if_exists)
3070 .unwrap_or(false),
3071 create_parents: true,
3072 };
3073
3074 fs.rename(&source_abs_path, &target_abs_path, options)
3075 .await?;
3076 }
3077
3078 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3079 let abs_path = op
3080 .uri
3081 .to_file_path()
3082 .map_err(|()| anyhow!("can't convert URI to path"))?;
3083 let options = op
3084 .options
3085 .map(|options| fs::RemoveOptions {
3086 recursive: options.recursive.unwrap_or(false),
3087 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3088 })
3089 .unwrap_or_default();
3090 if abs_path.ends_with("/") {
3091 fs.remove_dir(&abs_path, options).await?;
3092 } else {
3093 fs.remove_file(&abs_path, options).await?;
3094 }
3095 }
3096
3097 lsp::DocumentChangeOperation::Edit(op) => {
3098 let buffer_to_edit = this
3099 .update(cx, |this, cx| {
3100 this.open_local_buffer_via_lsp(
3101 op.text_document.uri.clone(),
3102 language_server.server_id(),
3103 cx,
3104 )
3105 })?
3106 .await?;
3107
3108 let edits = this
3109 .update(cx, |this, cx| {
3110 let path = buffer_to_edit.read(cx).project_path(cx);
3111 let active_entry = this.active_entry;
3112 let is_active_entry = path.is_some_and(|project_path| {
3113 this.worktree_store
3114 .read(cx)
3115 .entry_for_path(&project_path, cx)
3116 .is_some_and(|entry| Some(entry.id) == active_entry)
3117 });
3118 let local = this.as_local_mut().unwrap();
3119
3120 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3121 for edit in op.edits {
3122 match edit {
3123 Edit::Plain(edit) => {
3124 if !edits.contains(&edit) {
3125 edits.push(edit)
3126 }
3127 }
3128 Edit::Annotated(edit) => {
3129 if !edits.contains(&edit.text_edit) {
3130 edits.push(edit.text_edit)
3131 }
3132 }
3133 Edit::Snippet(edit) => {
3134 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3135 else {
3136 continue;
3137 };
3138
3139 if is_active_entry {
3140 snippet_edits.push((edit.range, snippet));
3141 } else {
3142 // Since this buffer is not focused, apply a normal edit.
3143 let new_edit = TextEdit {
3144 range: edit.range,
3145 new_text: snippet.text,
3146 };
3147 if !edits.contains(&new_edit) {
3148 edits.push(new_edit);
3149 }
3150 }
3151 }
3152 }
3153 }
3154 if !snippet_edits.is_empty() {
3155 let buffer_id = buffer_to_edit.read(cx).remote_id();
3156 let version = if let Some(buffer_version) = op.text_document.version
3157 {
3158 local
3159 .buffer_snapshot_for_lsp_version(
3160 &buffer_to_edit,
3161 language_server.server_id(),
3162 Some(buffer_version),
3163 cx,
3164 )
3165 .ok()
3166 .map(|snapshot| snapshot.version)
3167 } else {
3168 Some(buffer_to_edit.read(cx).saved_version().clone())
3169 };
3170
3171 let most_recent_edit =
3172 version.and_then(|version| version.most_recent());
3173 // Check if the edit that triggered that edit has been made by this participant.
3174
3175 if let Some(most_recent_edit) = most_recent_edit {
3176 cx.emit(LspStoreEvent::SnippetEdit {
3177 buffer_id,
3178 edits: snippet_edits,
3179 most_recent_edit,
3180 });
3181 }
3182 }
3183
3184 local.edits_from_lsp(
3185 &buffer_to_edit,
3186 edits,
3187 language_server.server_id(),
3188 op.text_document.version,
3189 cx,
3190 )
3191 })?
3192 .await?;
3193
3194 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3195 buffer.finalize_last_transaction();
3196 buffer.start_transaction();
3197 for (range, text) in edits {
3198 buffer.edit([(range, text)], None, cx);
3199 }
3200
3201 buffer.end_transaction(cx).and_then(|transaction_id| {
3202 if push_to_history {
3203 buffer.finalize_last_transaction();
3204 buffer.get_transaction(transaction_id).cloned()
3205 } else {
3206 buffer.forget_transaction(transaction_id)
3207 }
3208 })
3209 })?;
3210 if let Some(transaction) = transaction {
3211 project_transaction.0.insert(buffer_to_edit, transaction);
3212 }
3213 }
3214 }
3215 }
3216
3217 Ok(project_transaction)
3218 }
3219
3220 async fn on_lsp_workspace_edit(
3221 this: WeakEntity<LspStore>,
3222 params: lsp::ApplyWorkspaceEditParams,
3223 server_id: LanguageServerId,
3224 cx: &mut AsyncApp,
3225 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3226 let this = this.upgrade().context("project project closed")?;
3227 let language_server = this
3228 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3229 .context("language server not found")?;
3230 let transaction = Self::deserialize_workspace_edit(
3231 this.clone(),
3232 params.edit,
3233 true,
3234 language_server.clone(),
3235 cx,
3236 )
3237 .await
3238 .log_err();
3239 this.update(cx, |this, _| {
3240 if let Some(transaction) = transaction {
3241 this.as_local_mut()
3242 .unwrap()
3243 .last_workspace_edits_by_language_server
3244 .insert(server_id, transaction);
3245 }
3246 })?;
3247 Ok(lsp::ApplyWorkspaceEditResponse {
3248 applied: true,
3249 failed_change: None,
3250 failure_reason: None,
3251 })
3252 }
3253
3254 fn remove_worktree(
3255 &mut self,
3256 id_to_remove: WorktreeId,
3257 cx: &mut Context<LspStore>,
3258 ) -> Vec<LanguageServerId> {
3259 self.diagnostics.remove(&id_to_remove);
3260 self.prettier_store.update(cx, |prettier_store, cx| {
3261 prettier_store.remove_worktree(id_to_remove, cx);
3262 });
3263
3264 let mut servers_to_remove = BTreeSet::default();
3265 let mut servers_to_preserve = HashSet::default();
3266 for (seed, state) in &self.language_server_ids {
3267 if seed.worktree_id == id_to_remove {
3268 servers_to_remove.insert(state.id);
3269 } else {
3270 servers_to_preserve.insert(state.id);
3271 }
3272 }
3273 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3274 self.language_server_ids
3275 .retain(|_, state| !servers_to_remove.contains(&state.id));
3276 for server_id_to_remove in &servers_to_remove {
3277 self.language_server_watched_paths
3278 .remove(server_id_to_remove);
3279 self.language_server_paths_watched_for_rename
3280 .remove(server_id_to_remove);
3281 self.last_workspace_edits_by_language_server
3282 .remove(server_id_to_remove);
3283 self.language_servers.remove(server_id_to_remove);
3284 self.buffer_pull_diagnostics_result_ids
3285 .remove(server_id_to_remove);
3286 self.workspace_pull_diagnostics_result_ids
3287 .remove(server_id_to_remove);
3288 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3289 buffer_servers.remove(server_id_to_remove);
3290 }
3291 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3292 }
3293 servers_to_remove.into_iter().collect()
3294 }
3295
3296 fn rebuild_watched_paths_inner<'a>(
3297 &'a self,
3298 language_server_id: LanguageServerId,
3299 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3300 cx: &mut Context<LspStore>,
3301 ) -> LanguageServerWatchedPathsBuilder {
3302 let worktrees = self
3303 .worktree_store
3304 .read(cx)
3305 .worktrees()
3306 .filter_map(|worktree| {
3307 self.language_servers_for_worktree(worktree.read(cx).id())
3308 .find(|server| server.server_id() == language_server_id)
3309 .map(|_| worktree)
3310 })
3311 .collect::<Vec<_>>();
3312
3313 let mut worktree_globs = HashMap::default();
3314 let mut abs_globs = HashMap::default();
3315 log::trace!(
3316 "Processing new watcher paths for language server with id {}",
3317 language_server_id
3318 );
3319
3320 for watcher in watchers {
3321 if let Some((worktree, literal_prefix, pattern)) =
3322 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3323 {
3324 worktree.update(cx, |worktree, _| {
3325 if let Some((tree, glob)) =
3326 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3327 {
3328 tree.add_path_prefix_to_scan(literal_prefix);
3329 worktree_globs
3330 .entry(tree.id())
3331 .or_insert_with(GlobSetBuilder::new)
3332 .add(glob);
3333 }
3334 });
3335 } else {
3336 let (path, pattern) = match &watcher.glob_pattern {
3337 lsp::GlobPattern::String(s) => {
3338 let watcher_path = SanitizedPath::new(s);
3339 let path = glob_literal_prefix(watcher_path.as_path());
3340 let pattern = watcher_path
3341 .as_path()
3342 .strip_prefix(&path)
3343 .map(|p| p.to_string_lossy().into_owned())
3344 .unwrap_or_else(|e| {
3345 debug_panic!(
3346 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3347 s,
3348 path.display(),
3349 e
3350 );
3351 watcher_path.as_path().to_string_lossy().into_owned()
3352 });
3353 (path, pattern)
3354 }
3355 lsp::GlobPattern::Relative(rp) => {
3356 let Ok(mut base_uri) = match &rp.base_uri {
3357 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3358 lsp::OneOf::Right(base_uri) => base_uri,
3359 }
3360 .to_file_path() else {
3361 continue;
3362 };
3363
3364 let path = glob_literal_prefix(Path::new(&rp.pattern));
3365 let pattern = Path::new(&rp.pattern)
3366 .strip_prefix(&path)
3367 .map(|p| p.to_string_lossy().into_owned())
3368 .unwrap_or_else(|e| {
3369 debug_panic!(
3370 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3371 rp.pattern,
3372 path.display(),
3373 e
3374 );
3375 rp.pattern.clone()
3376 });
3377 base_uri.push(path);
3378 (base_uri, pattern)
3379 }
3380 };
3381
3382 if let Some(glob) = Glob::new(&pattern).log_err() {
3383 if !path
3384 .components()
3385 .any(|c| matches!(c, path::Component::Normal(_)))
3386 {
3387 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3388 // rather than adding a new watcher for `/`.
3389 for worktree in &worktrees {
3390 worktree_globs
3391 .entry(worktree.read(cx).id())
3392 .or_insert_with(GlobSetBuilder::new)
3393 .add(glob.clone());
3394 }
3395 } else {
3396 abs_globs
3397 .entry(path.into())
3398 .or_insert_with(GlobSetBuilder::new)
3399 .add(glob);
3400 }
3401 }
3402 }
3403 }
3404
3405 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3406 for (worktree_id, builder) in worktree_globs {
3407 if let Ok(globset) = builder.build() {
3408 watch_builder.watch_worktree(worktree_id, globset);
3409 }
3410 }
3411 for (abs_path, builder) in abs_globs {
3412 if let Ok(globset) = builder.build() {
3413 watch_builder.watch_abs_path(abs_path, globset);
3414 }
3415 }
3416 watch_builder
3417 }
3418
3419 fn worktree_and_path_for_file_watcher(
3420 worktrees: &[Entity<Worktree>],
3421 watcher: &FileSystemWatcher,
3422 cx: &App,
3423 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3424 worktrees.iter().find_map(|worktree| {
3425 let tree = worktree.read(cx);
3426 let worktree_root_path = tree.abs_path();
3427 let path_style = tree.path_style();
3428 match &watcher.glob_pattern {
3429 lsp::GlobPattern::String(s) => {
3430 let watcher_path = SanitizedPath::new(s);
3431 let relative = watcher_path
3432 .as_path()
3433 .strip_prefix(&worktree_root_path)
3434 .ok()?;
3435 let literal_prefix = glob_literal_prefix(relative);
3436 Some((
3437 worktree.clone(),
3438 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3439 relative.to_string_lossy().into_owned(),
3440 ))
3441 }
3442 lsp::GlobPattern::Relative(rp) => {
3443 let base_uri = match &rp.base_uri {
3444 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3445 lsp::OneOf::Right(base_uri) => base_uri,
3446 }
3447 .to_file_path()
3448 .ok()?;
3449 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3450 let mut literal_prefix = relative.to_owned();
3451 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3452 Some((
3453 worktree.clone(),
3454 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3455 rp.pattern.clone(),
3456 ))
3457 }
3458 }
3459 })
3460 }
3461
3462 fn rebuild_watched_paths(
3463 &mut self,
3464 language_server_id: LanguageServerId,
3465 cx: &mut Context<LspStore>,
3466 ) {
3467 let Some(registrations) = self
3468 .language_server_dynamic_registrations
3469 .get(&language_server_id)
3470 else {
3471 return;
3472 };
3473
3474 let watch_builder = self.rebuild_watched_paths_inner(
3475 language_server_id,
3476 registrations.did_change_watched_files.values().flatten(),
3477 cx,
3478 );
3479 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3480 self.language_server_watched_paths
3481 .insert(language_server_id, watcher);
3482
3483 cx.notify();
3484 }
3485
3486 fn on_lsp_did_change_watched_files(
3487 &mut self,
3488 language_server_id: LanguageServerId,
3489 registration_id: &str,
3490 params: DidChangeWatchedFilesRegistrationOptions,
3491 cx: &mut Context<LspStore>,
3492 ) {
3493 let registrations = self
3494 .language_server_dynamic_registrations
3495 .entry(language_server_id)
3496 .or_default();
3497
3498 registrations
3499 .did_change_watched_files
3500 .insert(registration_id.to_string(), params.watchers);
3501
3502 self.rebuild_watched_paths(language_server_id, cx);
3503 }
3504
3505 fn on_lsp_unregister_did_change_watched_files(
3506 &mut self,
3507 language_server_id: LanguageServerId,
3508 registration_id: &str,
3509 cx: &mut Context<LspStore>,
3510 ) {
3511 let registrations = self
3512 .language_server_dynamic_registrations
3513 .entry(language_server_id)
3514 .or_default();
3515
3516 if registrations
3517 .did_change_watched_files
3518 .remove(registration_id)
3519 .is_some()
3520 {
3521 log::info!(
3522 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3523 language_server_id,
3524 registration_id
3525 );
3526 } else {
3527 log::warn!(
3528 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3529 language_server_id,
3530 registration_id
3531 );
3532 }
3533
3534 self.rebuild_watched_paths(language_server_id, cx);
3535 }
3536
3537 async fn initialization_options_for_adapter(
3538 adapter: Arc<dyn LspAdapter>,
3539 delegate: &Arc<dyn LspAdapterDelegate>,
3540 ) -> Result<Option<serde_json::Value>> {
3541 let Some(mut initialization_config) =
3542 adapter.clone().initialization_options(delegate).await?
3543 else {
3544 return Ok(None);
3545 };
3546
3547 for other_adapter in delegate.registered_lsp_adapters() {
3548 if other_adapter.name() == adapter.name() {
3549 continue;
3550 }
3551 if let Ok(Some(target_config)) = other_adapter
3552 .clone()
3553 .additional_initialization_options(adapter.name(), delegate)
3554 .await
3555 {
3556 merge_json_value_into(target_config.clone(), &mut initialization_config);
3557 }
3558 }
3559
3560 Ok(Some(initialization_config))
3561 }
3562
3563 async fn workspace_configuration_for_adapter(
3564 adapter: Arc<dyn LspAdapter>,
3565 delegate: &Arc<dyn LspAdapterDelegate>,
3566 toolchain: Option<Toolchain>,
3567 requested_uri: Option<Uri>,
3568 cx: &mut AsyncApp,
3569 ) -> Result<serde_json::Value> {
3570 let mut workspace_config = adapter
3571 .clone()
3572 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3573 .await?;
3574
3575 for other_adapter in delegate.registered_lsp_adapters() {
3576 if other_adapter.name() == adapter.name() {
3577 continue;
3578 }
3579 if let Ok(Some(target_config)) = other_adapter
3580 .clone()
3581 .additional_workspace_configuration(adapter.name(), delegate, cx)
3582 .await
3583 {
3584 merge_json_value_into(target_config.clone(), &mut workspace_config);
3585 }
3586 }
3587
3588 Ok(workspace_config)
3589 }
3590
3591 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3592 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3593 Some(server.clone())
3594 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3595 Some(Arc::clone(server))
3596 } else {
3597 None
3598 }
3599 }
3600}
3601
3602fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3603 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3604 cx.emit(LspStoreEvent::LanguageServerUpdate {
3605 language_server_id: server.server_id(),
3606 name: Some(server.name()),
3607 message: proto::update_language_server::Variant::MetadataUpdated(
3608 proto::ServerMetadataUpdated {
3609 capabilities: Some(capabilities),
3610 binary: Some(proto::LanguageServerBinaryInfo {
3611 path: server.binary().path.to_string_lossy().into_owned(),
3612 arguments: server
3613 .binary()
3614 .arguments
3615 .iter()
3616 .map(|arg| arg.to_string_lossy().into_owned())
3617 .collect(),
3618 }),
3619 configuration: serde_json::to_string(server.configuration()).ok(),
3620 workspace_folders: server
3621 .workspace_folders()
3622 .iter()
3623 .map(|uri| uri.to_string())
3624 .collect(),
3625 },
3626 ),
3627 });
3628 }
3629}
3630
3631#[derive(Debug)]
3632pub struct FormattableBuffer {
3633 handle: Entity<Buffer>,
3634 abs_path: Option<PathBuf>,
3635 env: Option<HashMap<String, String>>,
3636 ranges: Option<Vec<Range<Anchor>>>,
3637}
3638
3639pub struct RemoteLspStore {
3640 upstream_client: Option<AnyProtoClient>,
3641 upstream_project_id: u64,
3642}
3643
3644pub(crate) enum LspStoreMode {
3645 Local(LocalLspStore), // ssh host and collab host
3646 Remote(RemoteLspStore), // collab guest
3647}
3648
3649impl LspStoreMode {
3650 fn is_local(&self) -> bool {
3651 matches!(self, LspStoreMode::Local(_))
3652 }
3653}
3654
3655pub struct LspStore {
3656 mode: LspStoreMode,
3657 last_formatting_failure: Option<String>,
3658 downstream_client: Option<(AnyProtoClient, u64)>,
3659 nonce: u128,
3660 buffer_store: Entity<BufferStore>,
3661 worktree_store: Entity<WorktreeStore>,
3662 pub languages: Arc<LanguageRegistry>,
3663 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3664 active_entry: Option<ProjectEntryId>,
3665 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3666 _maintain_buffer_languages: Task<()>,
3667 diagnostic_summaries:
3668 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3669 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3670 lsp_data: HashMap<BufferId, BufferLspData>,
3671 next_hint_id: Arc<AtomicUsize>,
3672}
3673
3674#[derive(Debug)]
3675pub struct BufferLspData {
3676 buffer_version: Global,
3677 document_colors: Option<DocumentColorData>,
3678 code_lens: Option<CodeLensData>,
3679 inlay_hints: BufferInlayHints,
3680 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3681 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3682}
3683
3684#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3685struct LspKey {
3686 request_type: TypeId,
3687 server_queried: Option<LanguageServerId>,
3688}
3689
3690impl BufferLspData {
3691 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3692 Self {
3693 buffer_version: buffer.read(cx).version(),
3694 document_colors: None,
3695 code_lens: None,
3696 inlay_hints: BufferInlayHints::new(buffer, cx),
3697 lsp_requests: HashMap::default(),
3698 chunk_lsp_requests: HashMap::default(),
3699 }
3700 }
3701
3702 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3703 if let Some(document_colors) = &mut self.document_colors {
3704 document_colors.colors.remove(&for_server);
3705 document_colors.cache_version += 1;
3706 }
3707
3708 if let Some(code_lens) = &mut self.code_lens {
3709 code_lens.lens.remove(&for_server);
3710 }
3711
3712 self.inlay_hints.remove_server_data(for_server);
3713 }
3714
3715 #[cfg(any(test, feature = "test-support"))]
3716 pub fn inlay_hints(&self) -> &BufferInlayHints {
3717 &self.inlay_hints
3718 }
3719}
3720
3721#[derive(Debug, Default, Clone)]
3722pub struct DocumentColors {
3723 pub colors: HashSet<DocumentColor>,
3724 pub cache_version: Option<usize>,
3725}
3726
3727type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3728type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3729
3730#[derive(Debug, Default)]
3731struct DocumentColorData {
3732 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3733 cache_version: usize,
3734 colors_update: Option<(Global, DocumentColorTask)>,
3735}
3736
3737#[derive(Debug, Default)]
3738struct CodeLensData {
3739 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3740 update: Option<(Global, CodeLensTask)>,
3741}
3742
3743#[derive(Debug)]
3744pub enum LspStoreEvent {
3745 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3746 LanguageServerRemoved(LanguageServerId),
3747 LanguageServerUpdate {
3748 language_server_id: LanguageServerId,
3749 name: Option<LanguageServerName>,
3750 message: proto::update_language_server::Variant,
3751 },
3752 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3753 LanguageServerPrompt(LanguageServerPromptRequest),
3754 LanguageDetected {
3755 buffer: Entity<Buffer>,
3756 new_language: Option<Arc<Language>>,
3757 },
3758 Notification(String),
3759 RefreshInlayHints {
3760 server_id: LanguageServerId,
3761 request_id: Option<usize>,
3762 },
3763 RefreshCodeLens,
3764 DiagnosticsUpdated {
3765 server_id: LanguageServerId,
3766 paths: Vec<ProjectPath>,
3767 },
3768 DiskBasedDiagnosticsStarted {
3769 language_server_id: LanguageServerId,
3770 },
3771 DiskBasedDiagnosticsFinished {
3772 language_server_id: LanguageServerId,
3773 },
3774 SnippetEdit {
3775 buffer_id: BufferId,
3776 edits: Vec<(lsp::Range, Snippet)>,
3777 most_recent_edit: clock::Lamport,
3778 },
3779}
3780
3781#[derive(Clone, Debug, Serialize)]
3782pub struct LanguageServerStatus {
3783 pub name: LanguageServerName,
3784 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3785 pub has_pending_diagnostic_updates: bool,
3786 pub progress_tokens: HashSet<ProgressToken>,
3787 pub worktree: Option<WorktreeId>,
3788 pub binary: Option<LanguageServerBinary>,
3789 pub configuration: Option<Value>,
3790 pub workspace_folders: BTreeSet<Uri>,
3791}
3792
3793#[derive(Clone, Debug)]
3794struct CoreSymbol {
3795 pub language_server_name: LanguageServerName,
3796 pub source_worktree_id: WorktreeId,
3797 pub source_language_server_id: LanguageServerId,
3798 pub path: SymbolLocation,
3799 pub name: String,
3800 pub kind: lsp::SymbolKind,
3801 pub range: Range<Unclipped<PointUtf16>>,
3802}
3803
3804#[derive(Clone, Debug, PartialEq, Eq)]
3805pub enum SymbolLocation {
3806 InProject(ProjectPath),
3807 OutsideProject {
3808 abs_path: Arc<Path>,
3809 signature: [u8; 32],
3810 },
3811}
3812
3813impl SymbolLocation {
3814 fn file_name(&self) -> Option<&str> {
3815 match self {
3816 Self::InProject(path) => path.path.file_name(),
3817 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3818 }
3819 }
3820}
3821
3822impl LspStore {
3823 pub fn init(client: &AnyProtoClient) {
3824 client.add_entity_request_handler(Self::handle_lsp_query);
3825 client.add_entity_message_handler(Self::handle_lsp_query_response);
3826 client.add_entity_request_handler(Self::handle_restart_language_servers);
3827 client.add_entity_request_handler(Self::handle_stop_language_servers);
3828 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3829 client.add_entity_message_handler(Self::handle_start_language_server);
3830 client.add_entity_message_handler(Self::handle_update_language_server);
3831 client.add_entity_message_handler(Self::handle_language_server_log);
3832 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3833 client.add_entity_request_handler(Self::handle_format_buffers);
3834 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3835 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3836 client.add_entity_request_handler(Self::handle_apply_code_action);
3837 client.add_entity_request_handler(Self::handle_get_project_symbols);
3838 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3839 client.add_entity_request_handler(Self::handle_get_color_presentation);
3840 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3841 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3842 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3843 client.add_entity_request_handler(Self::handle_on_type_formatting);
3844 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3845 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3846 client.add_entity_request_handler(Self::handle_rename_project_entry);
3847 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3848 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3849 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3850 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3851 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3852 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3853 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3854
3855 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3856 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3857 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3858 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3859 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3860 client.add_entity_request_handler(
3861 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3862 );
3863 client.add_entity_request_handler(
3864 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3865 );
3866 client.add_entity_request_handler(
3867 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3868 );
3869 }
3870
3871 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3872 match &self.mode {
3873 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3874 _ => None,
3875 }
3876 }
3877
3878 pub fn as_local(&self) -> Option<&LocalLspStore> {
3879 match &self.mode {
3880 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3881 _ => None,
3882 }
3883 }
3884
3885 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3886 match &mut self.mode {
3887 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3888 _ => None,
3889 }
3890 }
3891
3892 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3893 match &self.mode {
3894 LspStoreMode::Remote(RemoteLspStore {
3895 upstream_client: Some(upstream_client),
3896 upstream_project_id,
3897 ..
3898 }) => Some((upstream_client.clone(), *upstream_project_id)),
3899
3900 LspStoreMode::Remote(RemoteLspStore {
3901 upstream_client: None,
3902 ..
3903 }) => None,
3904 LspStoreMode::Local(_) => None,
3905 }
3906 }
3907
3908 pub fn new_local(
3909 buffer_store: Entity<BufferStore>,
3910 worktree_store: Entity<WorktreeStore>,
3911 prettier_store: Entity<PrettierStore>,
3912 toolchain_store: Entity<LocalToolchainStore>,
3913 environment: Entity<ProjectEnvironment>,
3914 manifest_tree: Entity<ManifestTree>,
3915 languages: Arc<LanguageRegistry>,
3916 http_client: Arc<dyn HttpClient>,
3917 fs: Arc<dyn Fs>,
3918 cx: &mut Context<Self>,
3919 ) -> Self {
3920 let yarn = YarnPathStore::new(fs.clone(), cx);
3921 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3922 .detach();
3923 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3924 .detach();
3925 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3926 .detach();
3927 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3928 .detach();
3929 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3930 .detach();
3931 subscribe_to_binary_statuses(&languages, cx).detach();
3932
3933 let _maintain_workspace_config = {
3934 let (sender, receiver) = watch::channel();
3935 (Self::maintain_workspace_config(receiver, cx), sender)
3936 };
3937
3938 Self {
3939 mode: LspStoreMode::Local(LocalLspStore {
3940 weak: cx.weak_entity(),
3941 worktree_store: worktree_store.clone(),
3942
3943 supplementary_language_servers: Default::default(),
3944 languages: languages.clone(),
3945 language_server_ids: Default::default(),
3946 language_servers: Default::default(),
3947 last_workspace_edits_by_language_server: Default::default(),
3948 language_server_watched_paths: Default::default(),
3949 language_server_paths_watched_for_rename: Default::default(),
3950 language_server_dynamic_registrations: Default::default(),
3951 buffers_being_formatted: Default::default(),
3952 buffer_snapshots: Default::default(),
3953 prettier_store,
3954 environment,
3955 http_client,
3956 fs,
3957 yarn,
3958 next_diagnostic_group_id: Default::default(),
3959 diagnostics: Default::default(),
3960 _subscription: cx.on_app_quit(|this, cx| {
3961 this.as_local_mut()
3962 .unwrap()
3963 .shutdown_language_servers_on_quit(cx)
3964 }),
3965 lsp_tree: LanguageServerTree::new(
3966 manifest_tree,
3967 languages.clone(),
3968 toolchain_store.clone(),
3969 ),
3970 toolchain_store,
3971 registered_buffers: HashMap::default(),
3972 buffers_opened_in_servers: HashMap::default(),
3973 buffer_pull_diagnostics_result_ids: HashMap::default(),
3974 workspace_pull_diagnostics_result_ids: HashMap::default(),
3975 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3976 .manifest_file_names(),
3977 }),
3978 last_formatting_failure: None,
3979 downstream_client: None,
3980 buffer_store,
3981 worktree_store,
3982 languages: languages.clone(),
3983 language_server_statuses: Default::default(),
3984 nonce: StdRng::from_os_rng().random(),
3985 diagnostic_summaries: HashMap::default(),
3986 lsp_server_capabilities: HashMap::default(),
3987 lsp_data: HashMap::default(),
3988 next_hint_id: Arc::default(),
3989 active_entry: None,
3990 _maintain_workspace_config,
3991 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3992 }
3993 }
3994
3995 fn send_lsp_proto_request<R: LspCommand>(
3996 &self,
3997 buffer: Entity<Buffer>,
3998 client: AnyProtoClient,
3999 upstream_project_id: u64,
4000 request: R,
4001 cx: &mut Context<LspStore>,
4002 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4003 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4004 return Task::ready(Ok(R::Response::default()));
4005 }
4006 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4007 cx.spawn(async move |this, cx| {
4008 let response = client.request(message).await?;
4009 let this = this.upgrade().context("project dropped")?;
4010 request
4011 .response_from_proto(response, this, buffer, cx.clone())
4012 .await
4013 })
4014 }
4015
4016 pub(super) fn new_remote(
4017 buffer_store: Entity<BufferStore>,
4018 worktree_store: Entity<WorktreeStore>,
4019 languages: Arc<LanguageRegistry>,
4020 upstream_client: AnyProtoClient,
4021 project_id: u64,
4022 cx: &mut Context<Self>,
4023 ) -> Self {
4024 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4025 .detach();
4026 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4027 .detach();
4028 subscribe_to_binary_statuses(&languages, cx).detach();
4029 let _maintain_workspace_config = {
4030 let (sender, receiver) = watch::channel();
4031 (Self::maintain_workspace_config(receiver, cx), sender)
4032 };
4033 Self {
4034 mode: LspStoreMode::Remote(RemoteLspStore {
4035 upstream_client: Some(upstream_client),
4036 upstream_project_id: project_id,
4037 }),
4038 downstream_client: None,
4039 last_formatting_failure: None,
4040 buffer_store,
4041 worktree_store,
4042 languages: languages.clone(),
4043 language_server_statuses: Default::default(),
4044 nonce: StdRng::from_os_rng().random(),
4045 diagnostic_summaries: HashMap::default(),
4046 lsp_server_capabilities: HashMap::default(),
4047 next_hint_id: Arc::default(),
4048 lsp_data: HashMap::default(),
4049 active_entry: None,
4050
4051 _maintain_workspace_config,
4052 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4053 }
4054 }
4055
4056 fn on_buffer_store_event(
4057 &mut self,
4058 _: Entity<BufferStore>,
4059 event: &BufferStoreEvent,
4060 cx: &mut Context<Self>,
4061 ) {
4062 match event {
4063 BufferStoreEvent::BufferAdded(buffer) => {
4064 self.on_buffer_added(buffer, cx).log_err();
4065 }
4066 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4067 let buffer_id = buffer.read(cx).remote_id();
4068 if let Some(local) = self.as_local_mut()
4069 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4070 {
4071 local.reset_buffer(buffer, old_file, cx);
4072
4073 if local.registered_buffers.contains_key(&buffer_id) {
4074 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4075 }
4076 }
4077
4078 self.detect_language_for_buffer(buffer, cx);
4079 if let Some(local) = self.as_local_mut() {
4080 local.initialize_buffer(buffer, cx);
4081 if local.registered_buffers.contains_key(&buffer_id) {
4082 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4083 }
4084 }
4085 }
4086 _ => {}
4087 }
4088 }
4089
4090 fn on_worktree_store_event(
4091 &mut self,
4092 _: Entity<WorktreeStore>,
4093 event: &WorktreeStoreEvent,
4094 cx: &mut Context<Self>,
4095 ) {
4096 match event {
4097 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4098 if !worktree.read(cx).is_local() {
4099 return;
4100 }
4101 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4102 worktree::Event::UpdatedEntries(changes) => {
4103 this.update_local_worktree_language_servers(&worktree, changes, cx);
4104 }
4105 worktree::Event::UpdatedGitRepositories(_)
4106 | worktree::Event::DeletedEntry(_) => {}
4107 })
4108 .detach()
4109 }
4110 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4111 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4112 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4113 }
4114 WorktreeStoreEvent::WorktreeReleased(..)
4115 | WorktreeStoreEvent::WorktreeOrderChanged
4116 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4117 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4118 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4119 }
4120 }
4121
4122 fn on_prettier_store_event(
4123 &mut self,
4124 _: Entity<PrettierStore>,
4125 event: &PrettierStoreEvent,
4126 cx: &mut Context<Self>,
4127 ) {
4128 match event {
4129 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4130 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4131 }
4132 PrettierStoreEvent::LanguageServerAdded {
4133 new_server_id,
4134 name,
4135 prettier_server,
4136 } => {
4137 self.register_supplementary_language_server(
4138 *new_server_id,
4139 name.clone(),
4140 prettier_server.clone(),
4141 cx,
4142 );
4143 }
4144 }
4145 }
4146
4147 fn on_toolchain_store_event(
4148 &mut self,
4149 _: Entity<LocalToolchainStore>,
4150 event: &ToolchainStoreEvent,
4151 _: &mut Context<Self>,
4152 ) {
4153 if let ToolchainStoreEvent::ToolchainActivated = event {
4154 self.request_workspace_config_refresh()
4155 }
4156 }
4157
4158 fn request_workspace_config_refresh(&mut self) {
4159 *self._maintain_workspace_config.1.borrow_mut() = ();
4160 }
4161
4162 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4163 self.as_local().map(|local| local.prettier_store.clone())
4164 }
4165
4166 fn on_buffer_event(
4167 &mut self,
4168 buffer: Entity<Buffer>,
4169 event: &language::BufferEvent,
4170 cx: &mut Context<Self>,
4171 ) {
4172 match event {
4173 language::BufferEvent::Edited => {
4174 self.on_buffer_edited(buffer, cx);
4175 }
4176
4177 language::BufferEvent::Saved => {
4178 self.on_buffer_saved(buffer, cx);
4179 }
4180
4181 _ => {}
4182 }
4183 }
4184
4185 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4186 buffer
4187 .read(cx)
4188 .set_language_registry(self.languages.clone());
4189
4190 cx.subscribe(buffer, |this, buffer, event, cx| {
4191 this.on_buffer_event(buffer, event, cx);
4192 })
4193 .detach();
4194
4195 self.detect_language_for_buffer(buffer, cx);
4196 if let Some(local) = self.as_local_mut() {
4197 local.initialize_buffer(buffer, cx);
4198 }
4199
4200 Ok(())
4201 }
4202
4203 pub(crate) fn register_buffer_with_language_servers(
4204 &mut self,
4205 buffer: &Entity<Buffer>,
4206 only_register_servers: HashSet<LanguageServerSelector>,
4207 ignore_refcounts: bool,
4208 cx: &mut Context<Self>,
4209 ) -> OpenLspBufferHandle {
4210 let buffer_id = buffer.read(cx).remote_id();
4211 let handle = cx.new(|_| buffer.clone());
4212 if let Some(local) = self.as_local_mut() {
4213 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4214 if !ignore_refcounts {
4215 *refcount += 1;
4216 }
4217
4218 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4219 // 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
4220 // 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
4221 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4222 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4223 return handle;
4224 };
4225 if !file.is_local() {
4226 return handle;
4227 }
4228
4229 if ignore_refcounts || *refcount == 1 {
4230 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4231 }
4232 if !ignore_refcounts {
4233 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4234 let refcount = {
4235 let local = lsp_store.as_local_mut().unwrap();
4236 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4237 debug_panic!("bad refcounting");
4238 return;
4239 };
4240
4241 *refcount -= 1;
4242 *refcount
4243 };
4244 if refcount == 0 {
4245 lsp_store.lsp_data.remove(&buffer_id);
4246 let local = lsp_store.as_local_mut().unwrap();
4247 local.registered_buffers.remove(&buffer_id);
4248
4249 local.buffers_opened_in_servers.remove(&buffer_id);
4250 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4251 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4252
4253 let buffer_abs_path = file.abs_path(cx);
4254 for (_, buffer_pull_diagnostics_result_ids) in
4255 &mut local.buffer_pull_diagnostics_result_ids
4256 {
4257 buffer_pull_diagnostics_result_ids.retain(
4258 |_, buffer_result_ids| {
4259 buffer_result_ids.remove(&buffer_abs_path);
4260 !buffer_result_ids.is_empty()
4261 },
4262 );
4263 }
4264
4265 let diagnostic_updates = local
4266 .language_servers
4267 .keys()
4268 .cloned()
4269 .map(|server_id| DocumentDiagnosticsUpdate {
4270 diagnostics: DocumentDiagnostics {
4271 document_abs_path: buffer_abs_path.clone(),
4272 version: None,
4273 diagnostics: Vec::new(),
4274 },
4275 result_id: None,
4276 registration_id: None,
4277 server_id: server_id,
4278 disk_based_sources: Cow::Borrowed(&[]),
4279 })
4280 .collect::<Vec<_>>();
4281
4282 lsp_store
4283 .merge_diagnostic_entries(
4284 diagnostic_updates,
4285 |_, diagnostic, _| {
4286 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4287 },
4288 cx,
4289 )
4290 .context("Clearing diagnostics for the closed buffer")
4291 .log_err();
4292 }
4293 }
4294 })
4295 .detach();
4296 }
4297 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4298 let buffer_id = buffer.read(cx).remote_id().to_proto();
4299 cx.background_spawn(async move {
4300 upstream_client
4301 .request(proto::RegisterBufferWithLanguageServers {
4302 project_id: upstream_project_id,
4303 buffer_id,
4304 only_servers: only_register_servers
4305 .into_iter()
4306 .map(|selector| {
4307 let selector = match selector {
4308 LanguageServerSelector::Id(language_server_id) => {
4309 proto::language_server_selector::Selector::ServerId(
4310 language_server_id.to_proto(),
4311 )
4312 }
4313 LanguageServerSelector::Name(language_server_name) => {
4314 proto::language_server_selector::Selector::Name(
4315 language_server_name.to_string(),
4316 )
4317 }
4318 };
4319 proto::LanguageServerSelector {
4320 selector: Some(selector),
4321 }
4322 })
4323 .collect(),
4324 })
4325 .await
4326 })
4327 .detach();
4328 } else {
4329 // Our remote connection got closed
4330 }
4331 handle
4332 }
4333
4334 fn maintain_buffer_languages(
4335 languages: Arc<LanguageRegistry>,
4336 cx: &mut Context<Self>,
4337 ) -> Task<()> {
4338 let mut subscription = languages.subscribe();
4339 let mut prev_reload_count = languages.reload_count();
4340 cx.spawn(async move |this, cx| {
4341 while let Some(()) = subscription.next().await {
4342 if let Some(this) = this.upgrade() {
4343 // If the language registry has been reloaded, then remove and
4344 // re-assign the languages on all open buffers.
4345 let reload_count = languages.reload_count();
4346 if reload_count > prev_reload_count {
4347 prev_reload_count = reload_count;
4348 this.update(cx, |this, cx| {
4349 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4350 for buffer in buffer_store.buffers() {
4351 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4352 {
4353 buffer.update(cx, |buffer, cx| {
4354 buffer.set_language_async(None, cx)
4355 });
4356 if let Some(local) = this.as_local_mut() {
4357 local.reset_buffer(&buffer, &f, cx);
4358
4359 if local
4360 .registered_buffers
4361 .contains_key(&buffer.read(cx).remote_id())
4362 && let Some(file_url) =
4363 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4364 {
4365 local.unregister_buffer_from_language_servers(
4366 &buffer, &file_url, cx,
4367 );
4368 }
4369 }
4370 }
4371 }
4372 });
4373 })
4374 .ok();
4375 }
4376
4377 this.update(cx, |this, cx| {
4378 let mut plain_text_buffers = Vec::new();
4379 let mut buffers_with_unknown_injections = Vec::new();
4380 for handle in this.buffer_store.read(cx).buffers() {
4381 let buffer = handle.read(cx);
4382 if buffer.language().is_none()
4383 || buffer.language() == Some(&*language::PLAIN_TEXT)
4384 {
4385 plain_text_buffers.push(handle);
4386 } else if buffer.contains_unknown_injections() {
4387 buffers_with_unknown_injections.push(handle);
4388 }
4389 }
4390
4391 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4392 // and reused later in the invisible worktrees.
4393 plain_text_buffers.sort_by_key(|buffer| {
4394 Reverse(
4395 File::from_dyn(buffer.read(cx).file())
4396 .map(|file| file.worktree.read(cx).is_visible()),
4397 )
4398 });
4399
4400 for buffer in plain_text_buffers {
4401 this.detect_language_for_buffer(&buffer, cx);
4402 if let Some(local) = this.as_local_mut() {
4403 local.initialize_buffer(&buffer, cx);
4404 if local
4405 .registered_buffers
4406 .contains_key(&buffer.read(cx).remote_id())
4407 {
4408 local.register_buffer_with_language_servers(
4409 &buffer,
4410 HashSet::default(),
4411 cx,
4412 );
4413 }
4414 }
4415 }
4416
4417 for buffer in buffers_with_unknown_injections {
4418 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4419 }
4420 })
4421 .ok();
4422 }
4423 }
4424 })
4425 }
4426
4427 fn detect_language_for_buffer(
4428 &mut self,
4429 buffer_handle: &Entity<Buffer>,
4430 cx: &mut Context<Self>,
4431 ) -> Option<language::AvailableLanguage> {
4432 // If the buffer has a language, set it and start the language server if we haven't already.
4433 let buffer = buffer_handle.read(cx);
4434 let file = buffer.file()?;
4435
4436 let content = buffer.as_rope();
4437 let available_language = self.languages.language_for_file(file, Some(content), cx);
4438 if let Some(available_language) = &available_language {
4439 if let Some(Ok(Ok(new_language))) = self
4440 .languages
4441 .load_language(available_language)
4442 .now_or_never()
4443 {
4444 self.set_language_for_buffer(buffer_handle, new_language, cx);
4445 }
4446 } else {
4447 cx.emit(LspStoreEvent::LanguageDetected {
4448 buffer: buffer_handle.clone(),
4449 new_language: None,
4450 });
4451 }
4452
4453 available_language
4454 }
4455
4456 pub(crate) fn set_language_for_buffer(
4457 &mut self,
4458 buffer_entity: &Entity<Buffer>,
4459 new_language: Arc<Language>,
4460 cx: &mut Context<Self>,
4461 ) {
4462 let buffer = buffer_entity.read(cx);
4463 let buffer_file = buffer.file().cloned();
4464 let buffer_id = buffer.remote_id();
4465 if let Some(local_store) = self.as_local_mut()
4466 && local_store.registered_buffers.contains_key(&buffer_id)
4467 && let Some(abs_path) =
4468 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4469 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4470 {
4471 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4472 }
4473 buffer_entity.update(cx, |buffer, cx| {
4474 if buffer
4475 .language()
4476 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4477 {
4478 buffer.set_language_async(Some(new_language.clone()), cx);
4479 }
4480 });
4481
4482 let settings =
4483 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4484 let buffer_file = File::from_dyn(buffer_file.as_ref());
4485
4486 let worktree_id = if let Some(file) = buffer_file {
4487 let worktree = file.worktree.clone();
4488
4489 if let Some(local) = self.as_local_mut()
4490 && local.registered_buffers.contains_key(&buffer_id)
4491 {
4492 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4493 }
4494 Some(worktree.read(cx).id())
4495 } else {
4496 None
4497 };
4498
4499 if settings.prettier.allowed
4500 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4501 {
4502 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4503 if let Some(prettier_store) = prettier_store {
4504 prettier_store.update(cx, |prettier_store, cx| {
4505 prettier_store.install_default_prettier(
4506 worktree_id,
4507 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4508 cx,
4509 )
4510 })
4511 }
4512 }
4513
4514 cx.emit(LspStoreEvent::LanguageDetected {
4515 buffer: buffer_entity.clone(),
4516 new_language: Some(new_language),
4517 })
4518 }
4519
4520 pub fn buffer_store(&self) -> Entity<BufferStore> {
4521 self.buffer_store.clone()
4522 }
4523
4524 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4525 self.active_entry = active_entry;
4526 }
4527
4528 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4529 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4530 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4531 {
4532 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4533 summaries
4534 .iter()
4535 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4536 });
4537 if let Some(summary) = summaries.next() {
4538 client
4539 .send(proto::UpdateDiagnosticSummary {
4540 project_id: downstream_project_id,
4541 worktree_id: worktree.id().to_proto(),
4542 summary: Some(summary),
4543 more_summaries: summaries.collect(),
4544 })
4545 .log_err();
4546 }
4547 }
4548 }
4549
4550 fn is_capable_for_proto_request<R>(
4551 &self,
4552 buffer: &Entity<Buffer>,
4553 request: &R,
4554 cx: &App,
4555 ) -> bool
4556 where
4557 R: LspCommand,
4558 {
4559 self.check_if_capable_for_proto_request(
4560 buffer,
4561 |capabilities| {
4562 request.check_capabilities(AdapterServerCapabilities {
4563 server_capabilities: capabilities.clone(),
4564 code_action_kinds: None,
4565 })
4566 },
4567 cx,
4568 )
4569 }
4570
4571 fn check_if_capable_for_proto_request<F>(
4572 &self,
4573 buffer: &Entity<Buffer>,
4574 check: F,
4575 cx: &App,
4576 ) -> bool
4577 where
4578 F: FnMut(&lsp::ServerCapabilities) -> bool,
4579 {
4580 let Some(language) = buffer.read(cx).language().cloned() else {
4581 return false;
4582 };
4583 let relevant_language_servers = self
4584 .languages
4585 .lsp_adapters(&language.name())
4586 .into_iter()
4587 .map(|lsp_adapter| lsp_adapter.name())
4588 .collect::<HashSet<_>>();
4589 self.language_server_statuses
4590 .iter()
4591 .filter_map(|(server_id, server_status)| {
4592 relevant_language_servers
4593 .contains(&server_status.name)
4594 .then_some(server_id)
4595 })
4596 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4597 .any(check)
4598 }
4599
4600 fn all_capable_for_proto_request<F>(
4601 &self,
4602 buffer: &Entity<Buffer>,
4603 mut check: F,
4604 cx: &App,
4605 ) -> Vec<lsp::LanguageServerId>
4606 where
4607 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4608 {
4609 let Some(language) = buffer.read(cx).language().cloned() else {
4610 return Vec::default();
4611 };
4612 let relevant_language_servers = self
4613 .languages
4614 .lsp_adapters(&language.name())
4615 .into_iter()
4616 .map(|lsp_adapter| lsp_adapter.name())
4617 .collect::<HashSet<_>>();
4618 self.language_server_statuses
4619 .iter()
4620 .filter_map(|(server_id, server_status)| {
4621 relevant_language_servers
4622 .contains(&server_status.name)
4623 .then_some((server_id, &server_status.name))
4624 })
4625 .filter_map(|(server_id, server_name)| {
4626 self.lsp_server_capabilities
4627 .get(server_id)
4628 .map(|c| (server_id, server_name, c))
4629 })
4630 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4631 .map(|(server_id, _, _)| *server_id)
4632 .collect()
4633 }
4634
4635 pub fn request_lsp<R>(
4636 &mut self,
4637 buffer: Entity<Buffer>,
4638 server: LanguageServerToQuery,
4639 request: R,
4640 cx: &mut Context<Self>,
4641 ) -> Task<Result<R::Response>>
4642 where
4643 R: LspCommand,
4644 <R::LspRequest as lsp::request::Request>::Result: Send,
4645 <R::LspRequest as lsp::request::Request>::Params: Send,
4646 {
4647 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4648 return self.send_lsp_proto_request(
4649 buffer,
4650 upstream_client,
4651 upstream_project_id,
4652 request,
4653 cx,
4654 );
4655 }
4656
4657 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4658 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4659 local
4660 .language_servers_for_buffer(buffer, cx)
4661 .find(|(_, server)| {
4662 request.check_capabilities(server.adapter_server_capabilities())
4663 })
4664 .map(|(_, server)| server.clone())
4665 }),
4666 LanguageServerToQuery::Other(id) => self
4667 .language_server_for_local_buffer(buffer, id, cx)
4668 .and_then(|(_, server)| {
4669 request
4670 .check_capabilities(server.adapter_server_capabilities())
4671 .then(|| Arc::clone(server))
4672 }),
4673 }) else {
4674 return Task::ready(Ok(Default::default()));
4675 };
4676
4677 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4678
4679 let Some(file) = file else {
4680 return Task::ready(Ok(Default::default()));
4681 };
4682
4683 let lsp_params = match request.to_lsp_params_or_response(
4684 &file.abs_path(cx),
4685 buffer.read(cx),
4686 &language_server,
4687 cx,
4688 ) {
4689 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4690 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4691 Err(err) => {
4692 let message = format!(
4693 "{} via {} failed: {}",
4694 request.display_name(),
4695 language_server.name(),
4696 err
4697 );
4698 // rust-analyzer likes to error with this when its still loading up
4699 if !message.ends_with("content modified") {
4700 log::warn!("{message}");
4701 }
4702 return Task::ready(Err(anyhow!(message)));
4703 }
4704 };
4705
4706 let status = request.status();
4707 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4708 return Task::ready(Ok(Default::default()));
4709 }
4710 cx.spawn(async move |this, cx| {
4711 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4712
4713 let id = lsp_request.id();
4714 let _cleanup = if status.is_some() {
4715 cx.update(|cx| {
4716 this.update(cx, |this, cx| {
4717 this.on_lsp_work_start(
4718 language_server.server_id(),
4719 ProgressToken::Number(id),
4720 LanguageServerProgress {
4721 is_disk_based_diagnostics_progress: false,
4722 is_cancellable: false,
4723 title: None,
4724 message: status.clone(),
4725 percentage: None,
4726 last_update_at: cx.background_executor().now(),
4727 },
4728 cx,
4729 );
4730 })
4731 })
4732 .log_err();
4733
4734 Some(defer(|| {
4735 cx.update(|cx| {
4736 this.update(cx, |this, cx| {
4737 this.on_lsp_work_end(
4738 language_server.server_id(),
4739 ProgressToken::Number(id),
4740 cx,
4741 );
4742 })
4743 })
4744 .log_err();
4745 }))
4746 } else {
4747 None
4748 };
4749
4750 let result = lsp_request.await.into_response();
4751
4752 let response = result.map_err(|err| {
4753 let message = format!(
4754 "{} via {} failed: {}",
4755 request.display_name(),
4756 language_server.name(),
4757 err
4758 );
4759 // rust-analyzer likes to error with this when its still loading up
4760 if !message.ends_with("content modified") {
4761 log::warn!("{message}");
4762 }
4763 anyhow::anyhow!(message)
4764 })?;
4765
4766 request
4767 .response_from_lsp(
4768 response,
4769 this.upgrade().context("no app context")?,
4770 buffer,
4771 language_server.server_id(),
4772 cx.clone(),
4773 )
4774 .await
4775 })
4776 }
4777
4778 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4779 let mut language_formatters_to_check = Vec::new();
4780 for buffer in self.buffer_store.read(cx).buffers() {
4781 let buffer = buffer.read(cx);
4782 let buffer_file = File::from_dyn(buffer.file());
4783 let buffer_language = buffer.language();
4784 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4785 if buffer_language.is_some() {
4786 language_formatters_to_check.push((
4787 buffer_file.map(|f| f.worktree_id(cx)),
4788 settings.into_owned(),
4789 ));
4790 }
4791 }
4792
4793 self.request_workspace_config_refresh();
4794
4795 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4796 prettier_store.update(cx, |prettier_store, cx| {
4797 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4798 })
4799 }
4800
4801 cx.notify();
4802 }
4803
4804 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4805 let buffer_store = self.buffer_store.clone();
4806 let Some(local) = self.as_local_mut() else {
4807 return;
4808 };
4809 let mut adapters = BTreeMap::default();
4810 let get_adapter = {
4811 let languages = local.languages.clone();
4812 let environment = local.environment.clone();
4813 let weak = local.weak.clone();
4814 let worktree_store = local.worktree_store.clone();
4815 let http_client = local.http_client.clone();
4816 let fs = local.fs.clone();
4817 move |worktree_id, cx: &mut App| {
4818 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4819 Some(LocalLspAdapterDelegate::new(
4820 languages.clone(),
4821 &environment,
4822 weak.clone(),
4823 &worktree,
4824 http_client.clone(),
4825 fs.clone(),
4826 cx,
4827 ))
4828 }
4829 };
4830
4831 let mut messages_to_report = Vec::new();
4832 let (new_tree, to_stop) = {
4833 let mut rebase = local.lsp_tree.rebase();
4834 let buffers = buffer_store
4835 .read(cx)
4836 .buffers()
4837 .filter_map(|buffer| {
4838 let raw_buffer = buffer.read(cx);
4839 if !local
4840 .registered_buffers
4841 .contains_key(&raw_buffer.remote_id())
4842 {
4843 return None;
4844 }
4845 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4846 let language = raw_buffer.language().cloned()?;
4847 Some((file, language, raw_buffer.remote_id()))
4848 })
4849 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4850 for (file, language, buffer_id) in buffers {
4851 let worktree_id = file.worktree_id(cx);
4852 let Some(worktree) = local
4853 .worktree_store
4854 .read(cx)
4855 .worktree_for_id(worktree_id, cx)
4856 else {
4857 continue;
4858 };
4859
4860 if let Some((_, apply)) = local.reuse_existing_language_server(
4861 rebase.server_tree(),
4862 &worktree,
4863 &language.name(),
4864 cx,
4865 ) {
4866 (apply)(rebase.server_tree());
4867 } else if let Some(lsp_delegate) = adapters
4868 .entry(worktree_id)
4869 .or_insert_with(|| get_adapter(worktree_id, cx))
4870 .clone()
4871 {
4872 let delegate =
4873 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4874 let path = file
4875 .path()
4876 .parent()
4877 .map(Arc::from)
4878 .unwrap_or_else(|| file.path().clone());
4879 let worktree_path = ProjectPath { worktree_id, path };
4880 let abs_path = file.abs_path(cx);
4881 let nodes = rebase
4882 .walk(
4883 worktree_path,
4884 language.name(),
4885 language.manifest(),
4886 delegate.clone(),
4887 cx,
4888 )
4889 .collect::<Vec<_>>();
4890 for node in nodes {
4891 let server_id = node.server_id_or_init(|disposition| {
4892 let path = &disposition.path;
4893 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4894 let key = LanguageServerSeed {
4895 worktree_id,
4896 name: disposition.server_name.clone(),
4897 settings: disposition.settings.clone(),
4898 toolchain: local.toolchain_store.read(cx).active_toolchain(
4899 path.worktree_id,
4900 &path.path,
4901 language.name(),
4902 ),
4903 };
4904 local.language_server_ids.remove(&key);
4905
4906 let server_id = local.get_or_insert_language_server(
4907 &worktree,
4908 lsp_delegate.clone(),
4909 disposition,
4910 &language.name(),
4911 cx,
4912 );
4913 if let Some(state) = local.language_servers.get(&server_id)
4914 && let Ok(uri) = uri
4915 {
4916 state.add_workspace_folder(uri);
4917 };
4918 server_id
4919 });
4920
4921 if let Some(language_server_id) = server_id {
4922 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4923 language_server_id,
4924 name: node.name(),
4925 message:
4926 proto::update_language_server::Variant::RegisteredForBuffer(
4927 proto::RegisteredForBuffer {
4928 buffer_abs_path: abs_path
4929 .to_string_lossy()
4930 .into_owned(),
4931 buffer_id: buffer_id.to_proto(),
4932 },
4933 ),
4934 });
4935 }
4936 }
4937 } else {
4938 continue;
4939 }
4940 }
4941 rebase.finish()
4942 };
4943 for message in messages_to_report {
4944 cx.emit(message);
4945 }
4946 local.lsp_tree = new_tree;
4947 for (id, _) in to_stop {
4948 self.stop_local_language_server(id, cx).detach();
4949 }
4950 }
4951
4952 pub fn apply_code_action(
4953 &self,
4954 buffer_handle: Entity<Buffer>,
4955 mut action: CodeAction,
4956 push_to_history: bool,
4957 cx: &mut Context<Self>,
4958 ) -> Task<Result<ProjectTransaction>> {
4959 if let Some((upstream_client, project_id)) = self.upstream_client() {
4960 let request = proto::ApplyCodeAction {
4961 project_id,
4962 buffer_id: buffer_handle.read(cx).remote_id().into(),
4963 action: Some(Self::serialize_code_action(&action)),
4964 };
4965 let buffer_store = self.buffer_store();
4966 cx.spawn(async move |_, cx| {
4967 let response = upstream_client
4968 .request(request)
4969 .await?
4970 .transaction
4971 .context("missing transaction")?;
4972
4973 buffer_store
4974 .update(cx, |buffer_store, cx| {
4975 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4976 })?
4977 .await
4978 })
4979 } else if self.mode.is_local() {
4980 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4981 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4982 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4983 }) else {
4984 return Task::ready(Ok(ProjectTransaction::default()));
4985 };
4986 cx.spawn(async move |this, cx| {
4987 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4988 .await
4989 .context("resolving a code action")?;
4990 if let Some(edit) = action.lsp_action.edit()
4991 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4992 return LocalLspStore::deserialize_workspace_edit(
4993 this.upgrade().context("no app present")?,
4994 edit.clone(),
4995 push_to_history,
4996
4997 lang_server.clone(),
4998 cx,
4999 )
5000 .await;
5001 }
5002
5003 if let Some(command) = action.lsp_action.command() {
5004 let server_capabilities = lang_server.capabilities();
5005 let available_commands = server_capabilities
5006 .execute_command_provider
5007 .as_ref()
5008 .map(|options| options.commands.as_slice())
5009 .unwrap_or_default();
5010 if available_commands.contains(&command.command) {
5011 this.update(cx, |this, _| {
5012 this.as_local_mut()
5013 .unwrap()
5014 .last_workspace_edits_by_language_server
5015 .remove(&lang_server.server_id());
5016 })?;
5017
5018 let _result = lang_server
5019 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5020 command: command.command.clone(),
5021 arguments: command.arguments.clone().unwrap_or_default(),
5022 ..lsp::ExecuteCommandParams::default()
5023 })
5024 .await.into_response()
5025 .context("execute command")?;
5026
5027 return this.update(cx, |this, _| {
5028 this.as_local_mut()
5029 .unwrap()
5030 .last_workspace_edits_by_language_server
5031 .remove(&lang_server.server_id())
5032 .unwrap_or_default()
5033 });
5034 } else {
5035 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5036 }
5037 }
5038
5039 Ok(ProjectTransaction::default())
5040 })
5041 } else {
5042 Task::ready(Err(anyhow!("no upstream client and not local")))
5043 }
5044 }
5045
5046 pub fn apply_code_action_kind(
5047 &mut self,
5048 buffers: HashSet<Entity<Buffer>>,
5049 kind: CodeActionKind,
5050 push_to_history: bool,
5051 cx: &mut Context<Self>,
5052 ) -> Task<anyhow::Result<ProjectTransaction>> {
5053 if self.as_local().is_some() {
5054 cx.spawn(async move |lsp_store, cx| {
5055 let buffers = buffers.into_iter().collect::<Vec<_>>();
5056 let result = LocalLspStore::execute_code_action_kind_locally(
5057 lsp_store.clone(),
5058 buffers,
5059 kind,
5060 push_to_history,
5061 cx,
5062 )
5063 .await;
5064 lsp_store.update(cx, |lsp_store, _| {
5065 lsp_store.update_last_formatting_failure(&result);
5066 })?;
5067 result
5068 })
5069 } else if let Some((client, project_id)) = self.upstream_client() {
5070 let buffer_store = self.buffer_store();
5071 cx.spawn(async move |lsp_store, cx| {
5072 let result = client
5073 .request(proto::ApplyCodeActionKind {
5074 project_id,
5075 kind: kind.as_str().to_owned(),
5076 buffer_ids: buffers
5077 .iter()
5078 .map(|buffer| {
5079 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5080 })
5081 .collect::<Result<_>>()?,
5082 })
5083 .await
5084 .and_then(|result| result.transaction.context("missing transaction"));
5085 lsp_store.update(cx, |lsp_store, _| {
5086 lsp_store.update_last_formatting_failure(&result);
5087 })?;
5088
5089 let transaction_response = result?;
5090 buffer_store
5091 .update(cx, |buffer_store, cx| {
5092 buffer_store.deserialize_project_transaction(
5093 transaction_response,
5094 push_to_history,
5095 cx,
5096 )
5097 })?
5098 .await
5099 })
5100 } else {
5101 Task::ready(Ok(ProjectTransaction::default()))
5102 }
5103 }
5104
5105 pub fn resolved_hint(
5106 &mut self,
5107 buffer_id: BufferId,
5108 id: InlayId,
5109 cx: &mut Context<Self>,
5110 ) -> Option<ResolvedHint> {
5111 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5112
5113 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5114 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5115 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5116 let (server_id, resolve_data) = match &hint.resolve_state {
5117 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5118 ResolveState::Resolving => {
5119 return Some(ResolvedHint::Resolving(
5120 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5121 ));
5122 }
5123 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5124 };
5125
5126 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5127 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5128 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5129 id,
5130 cx.spawn(async move |lsp_store, cx| {
5131 let resolved_hint = resolve_task.await;
5132 lsp_store
5133 .update(cx, |lsp_store, _| {
5134 if let Some(old_inlay_hint) = lsp_store
5135 .lsp_data
5136 .get_mut(&buffer_id)
5137 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5138 {
5139 match resolved_hint {
5140 Ok(resolved_hint) => {
5141 *old_inlay_hint = resolved_hint;
5142 }
5143 Err(e) => {
5144 old_inlay_hint.resolve_state =
5145 ResolveState::CanResolve(server_id, resolve_data);
5146 log::error!("Inlay hint resolve failed: {e:#}");
5147 }
5148 }
5149 }
5150 })
5151 .ok();
5152 })
5153 .shared(),
5154 );
5155 debug_assert!(
5156 previous_task.is_none(),
5157 "Did not change hint's resolve state after spawning its resolve"
5158 );
5159 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5160 None
5161 }
5162
5163 fn resolve_inlay_hint(
5164 &self,
5165 mut hint: InlayHint,
5166 buffer: Entity<Buffer>,
5167 server_id: LanguageServerId,
5168 cx: &mut Context<Self>,
5169 ) -> Task<anyhow::Result<InlayHint>> {
5170 if let Some((upstream_client, project_id)) = self.upstream_client() {
5171 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5172 {
5173 hint.resolve_state = ResolveState::Resolved;
5174 return Task::ready(Ok(hint));
5175 }
5176 let request = proto::ResolveInlayHint {
5177 project_id,
5178 buffer_id: buffer.read(cx).remote_id().into(),
5179 language_server_id: server_id.0 as u64,
5180 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5181 };
5182 cx.background_spawn(async move {
5183 let response = upstream_client
5184 .request(request)
5185 .await
5186 .context("inlay hints proto request")?;
5187 match response.hint {
5188 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5189 .context("inlay hints proto resolve response conversion"),
5190 None => Ok(hint),
5191 }
5192 })
5193 } else {
5194 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5195 self.language_server_for_local_buffer(buffer, server_id, cx)
5196 .map(|(_, server)| server.clone())
5197 }) else {
5198 return Task::ready(Ok(hint));
5199 };
5200 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5201 return Task::ready(Ok(hint));
5202 }
5203 let buffer_snapshot = buffer.read(cx).snapshot();
5204 cx.spawn(async move |_, cx| {
5205 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5206 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5207 );
5208 let resolved_hint = resolve_task
5209 .await
5210 .into_response()
5211 .context("inlay hint resolve LSP request")?;
5212 let resolved_hint = InlayHints::lsp_to_project_hint(
5213 resolved_hint,
5214 &buffer,
5215 server_id,
5216 ResolveState::Resolved,
5217 false,
5218 cx,
5219 )
5220 .await?;
5221 Ok(resolved_hint)
5222 })
5223 }
5224 }
5225
5226 pub fn resolve_color_presentation(
5227 &mut self,
5228 mut color: DocumentColor,
5229 buffer: Entity<Buffer>,
5230 server_id: LanguageServerId,
5231 cx: &mut Context<Self>,
5232 ) -> Task<Result<DocumentColor>> {
5233 if color.resolved {
5234 return Task::ready(Ok(color));
5235 }
5236
5237 if let Some((upstream_client, project_id)) = self.upstream_client() {
5238 let start = color.lsp_range.start;
5239 let end = color.lsp_range.end;
5240 let request = proto::GetColorPresentation {
5241 project_id,
5242 server_id: server_id.to_proto(),
5243 buffer_id: buffer.read(cx).remote_id().into(),
5244 color: Some(proto::ColorInformation {
5245 red: color.color.red,
5246 green: color.color.green,
5247 blue: color.color.blue,
5248 alpha: color.color.alpha,
5249 lsp_range_start: Some(proto::PointUtf16 {
5250 row: start.line,
5251 column: start.character,
5252 }),
5253 lsp_range_end: Some(proto::PointUtf16 {
5254 row: end.line,
5255 column: end.character,
5256 }),
5257 }),
5258 };
5259 cx.background_spawn(async move {
5260 let response = upstream_client
5261 .request(request)
5262 .await
5263 .context("color presentation proto request")?;
5264 color.resolved = true;
5265 color.color_presentations = response
5266 .presentations
5267 .into_iter()
5268 .map(|presentation| ColorPresentation {
5269 label: SharedString::from(presentation.label),
5270 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5271 additional_text_edits: presentation
5272 .additional_text_edits
5273 .into_iter()
5274 .filter_map(deserialize_lsp_edit)
5275 .collect(),
5276 })
5277 .collect();
5278 Ok(color)
5279 })
5280 } else {
5281 let path = match buffer
5282 .update(cx, |buffer, cx| {
5283 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5284 })
5285 .context("buffer with the missing path")
5286 {
5287 Ok(path) => path,
5288 Err(e) => return Task::ready(Err(e)),
5289 };
5290 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5291 self.language_server_for_local_buffer(buffer, server_id, cx)
5292 .map(|(_, server)| server.clone())
5293 }) else {
5294 return Task::ready(Ok(color));
5295 };
5296 cx.background_spawn(async move {
5297 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5298 lsp::ColorPresentationParams {
5299 text_document: make_text_document_identifier(&path)?,
5300 color: color.color,
5301 range: color.lsp_range,
5302 work_done_progress_params: Default::default(),
5303 partial_result_params: Default::default(),
5304 },
5305 );
5306 color.color_presentations = resolve_task
5307 .await
5308 .into_response()
5309 .context("color presentation resolve LSP request")?
5310 .into_iter()
5311 .map(|presentation| ColorPresentation {
5312 label: SharedString::from(presentation.label),
5313 text_edit: presentation.text_edit,
5314 additional_text_edits: presentation
5315 .additional_text_edits
5316 .unwrap_or_default(),
5317 })
5318 .collect();
5319 color.resolved = true;
5320 Ok(color)
5321 })
5322 }
5323 }
5324
5325 pub(crate) fn linked_edits(
5326 &mut self,
5327 buffer: &Entity<Buffer>,
5328 position: Anchor,
5329 cx: &mut Context<Self>,
5330 ) -> Task<Result<Vec<Range<Anchor>>>> {
5331 let snapshot = buffer.read(cx).snapshot();
5332 let scope = snapshot.language_scope_at(position);
5333 let Some(server_id) = self
5334 .as_local()
5335 .and_then(|local| {
5336 buffer.update(cx, |buffer, cx| {
5337 local
5338 .language_servers_for_buffer(buffer, cx)
5339 .filter(|(_, server)| {
5340 LinkedEditingRange::check_server_capabilities(server.capabilities())
5341 })
5342 .filter(|(adapter, _)| {
5343 scope
5344 .as_ref()
5345 .map(|scope| scope.language_allowed(&adapter.name))
5346 .unwrap_or(true)
5347 })
5348 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5349 .next()
5350 })
5351 })
5352 .or_else(|| {
5353 self.upstream_client()
5354 .is_some()
5355 .then_some(LanguageServerToQuery::FirstCapable)
5356 })
5357 .filter(|_| {
5358 maybe!({
5359 let language = buffer.read(cx).language_at(position)?;
5360 Some(
5361 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5362 .linked_edits,
5363 )
5364 }) == Some(true)
5365 })
5366 else {
5367 return Task::ready(Ok(Vec::new()));
5368 };
5369
5370 self.request_lsp(
5371 buffer.clone(),
5372 server_id,
5373 LinkedEditingRange { position },
5374 cx,
5375 )
5376 }
5377
5378 fn apply_on_type_formatting(
5379 &mut self,
5380 buffer: Entity<Buffer>,
5381 position: Anchor,
5382 trigger: String,
5383 cx: &mut Context<Self>,
5384 ) -> Task<Result<Option<Transaction>>> {
5385 if let Some((client, project_id)) = self.upstream_client() {
5386 if !self.check_if_capable_for_proto_request(
5387 &buffer,
5388 |capabilities| {
5389 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5390 },
5391 cx,
5392 ) {
5393 return Task::ready(Ok(None));
5394 }
5395 let request = proto::OnTypeFormatting {
5396 project_id,
5397 buffer_id: buffer.read(cx).remote_id().into(),
5398 position: Some(serialize_anchor(&position)),
5399 trigger,
5400 version: serialize_version(&buffer.read(cx).version()),
5401 };
5402 cx.background_spawn(async move {
5403 client
5404 .request(request)
5405 .await?
5406 .transaction
5407 .map(language::proto::deserialize_transaction)
5408 .transpose()
5409 })
5410 } else if let Some(local) = self.as_local_mut() {
5411 let buffer_id = buffer.read(cx).remote_id();
5412 local.buffers_being_formatted.insert(buffer_id);
5413 cx.spawn(async move |this, cx| {
5414 let _cleanup = defer({
5415 let this = this.clone();
5416 let mut cx = cx.clone();
5417 move || {
5418 this.update(&mut cx, |this, _| {
5419 if let Some(local) = this.as_local_mut() {
5420 local.buffers_being_formatted.remove(&buffer_id);
5421 }
5422 })
5423 .ok();
5424 }
5425 });
5426
5427 buffer
5428 .update(cx, |buffer, _| {
5429 buffer.wait_for_edits(Some(position.timestamp))
5430 })?
5431 .await?;
5432 this.update(cx, |this, cx| {
5433 let position = position.to_point_utf16(buffer.read(cx));
5434 this.on_type_format(buffer, position, trigger, false, cx)
5435 })?
5436 .await
5437 })
5438 } else {
5439 Task::ready(Err(anyhow!("No upstream client or local language server")))
5440 }
5441 }
5442
5443 pub fn on_type_format<T: ToPointUtf16>(
5444 &mut self,
5445 buffer: Entity<Buffer>,
5446 position: T,
5447 trigger: String,
5448 push_to_history: bool,
5449 cx: &mut Context<Self>,
5450 ) -> Task<Result<Option<Transaction>>> {
5451 let position = position.to_point_utf16(buffer.read(cx));
5452 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5453 }
5454
5455 fn on_type_format_impl(
5456 &mut self,
5457 buffer: Entity<Buffer>,
5458 position: PointUtf16,
5459 trigger: String,
5460 push_to_history: bool,
5461 cx: &mut Context<Self>,
5462 ) -> Task<Result<Option<Transaction>>> {
5463 let options = buffer.update(cx, |buffer, cx| {
5464 lsp_command::lsp_formatting_options(
5465 language_settings(
5466 buffer.language_at(position).map(|l| l.name()),
5467 buffer.file(),
5468 cx,
5469 )
5470 .as_ref(),
5471 )
5472 });
5473
5474 cx.spawn(async move |this, cx| {
5475 if let Some(waiter) =
5476 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5477 {
5478 waiter.await?;
5479 }
5480 cx.update(|cx| {
5481 this.update(cx, |this, cx| {
5482 this.request_lsp(
5483 buffer.clone(),
5484 LanguageServerToQuery::FirstCapable,
5485 OnTypeFormatting {
5486 position,
5487 trigger,
5488 options,
5489 push_to_history,
5490 },
5491 cx,
5492 )
5493 })
5494 })??
5495 .await
5496 })
5497 }
5498
5499 pub fn definitions(
5500 &mut self,
5501 buffer: &Entity<Buffer>,
5502 position: PointUtf16,
5503 cx: &mut Context<Self>,
5504 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5505 if let Some((upstream_client, project_id)) = self.upstream_client() {
5506 let request = GetDefinitions { position };
5507 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5508 return Task::ready(Ok(None));
5509 }
5510 let request_task = upstream_client.request_lsp(
5511 project_id,
5512 None,
5513 LSP_REQUEST_TIMEOUT,
5514 cx.background_executor().clone(),
5515 request.to_proto(project_id, buffer.read(cx)),
5516 );
5517 let buffer = buffer.clone();
5518 cx.spawn(async move |weak_lsp_store, cx| {
5519 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5520 return Ok(None);
5521 };
5522 let Some(responses) = request_task.await? else {
5523 return Ok(None);
5524 };
5525 let actions = join_all(responses.payload.into_iter().map(|response| {
5526 GetDefinitions { position }.response_from_proto(
5527 response.response,
5528 lsp_store.clone(),
5529 buffer.clone(),
5530 cx.clone(),
5531 )
5532 }))
5533 .await;
5534
5535 Ok(Some(
5536 actions
5537 .into_iter()
5538 .collect::<Result<Vec<Vec<_>>>>()?
5539 .into_iter()
5540 .flatten()
5541 .dedup()
5542 .collect(),
5543 ))
5544 })
5545 } else {
5546 let definitions_task = self.request_multiple_lsp_locally(
5547 buffer,
5548 Some(position),
5549 GetDefinitions { position },
5550 cx,
5551 );
5552 cx.background_spawn(async move {
5553 Ok(Some(
5554 definitions_task
5555 .await
5556 .into_iter()
5557 .flat_map(|(_, definitions)| definitions)
5558 .dedup()
5559 .collect(),
5560 ))
5561 })
5562 }
5563 }
5564
5565 pub fn declarations(
5566 &mut self,
5567 buffer: &Entity<Buffer>,
5568 position: PointUtf16,
5569 cx: &mut Context<Self>,
5570 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5571 if let Some((upstream_client, project_id)) = self.upstream_client() {
5572 let request = GetDeclarations { position };
5573 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5574 return Task::ready(Ok(None));
5575 }
5576 let request_task = upstream_client.request_lsp(
5577 project_id,
5578 None,
5579 LSP_REQUEST_TIMEOUT,
5580 cx.background_executor().clone(),
5581 request.to_proto(project_id, buffer.read(cx)),
5582 );
5583 let buffer = buffer.clone();
5584 cx.spawn(async move |weak_lsp_store, cx| {
5585 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5586 return Ok(None);
5587 };
5588 let Some(responses) = request_task.await? else {
5589 return Ok(None);
5590 };
5591 let actions = join_all(responses.payload.into_iter().map(|response| {
5592 GetDeclarations { position }.response_from_proto(
5593 response.response,
5594 lsp_store.clone(),
5595 buffer.clone(),
5596 cx.clone(),
5597 )
5598 }))
5599 .await;
5600
5601 Ok(Some(
5602 actions
5603 .into_iter()
5604 .collect::<Result<Vec<Vec<_>>>>()?
5605 .into_iter()
5606 .flatten()
5607 .dedup()
5608 .collect(),
5609 ))
5610 })
5611 } else {
5612 let declarations_task = self.request_multiple_lsp_locally(
5613 buffer,
5614 Some(position),
5615 GetDeclarations { position },
5616 cx,
5617 );
5618 cx.background_spawn(async move {
5619 Ok(Some(
5620 declarations_task
5621 .await
5622 .into_iter()
5623 .flat_map(|(_, declarations)| declarations)
5624 .dedup()
5625 .collect(),
5626 ))
5627 })
5628 }
5629 }
5630
5631 pub fn type_definitions(
5632 &mut self,
5633 buffer: &Entity<Buffer>,
5634 position: PointUtf16,
5635 cx: &mut Context<Self>,
5636 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5637 if let Some((upstream_client, project_id)) = self.upstream_client() {
5638 let request = GetTypeDefinitions { position };
5639 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5640 return Task::ready(Ok(None));
5641 }
5642 let request_task = upstream_client.request_lsp(
5643 project_id,
5644 None,
5645 LSP_REQUEST_TIMEOUT,
5646 cx.background_executor().clone(),
5647 request.to_proto(project_id, buffer.read(cx)),
5648 );
5649 let buffer = buffer.clone();
5650 cx.spawn(async move |weak_lsp_store, cx| {
5651 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5652 return Ok(None);
5653 };
5654 let Some(responses) = request_task.await? else {
5655 return Ok(None);
5656 };
5657 let actions = join_all(responses.payload.into_iter().map(|response| {
5658 GetTypeDefinitions { position }.response_from_proto(
5659 response.response,
5660 lsp_store.clone(),
5661 buffer.clone(),
5662 cx.clone(),
5663 )
5664 }))
5665 .await;
5666
5667 Ok(Some(
5668 actions
5669 .into_iter()
5670 .collect::<Result<Vec<Vec<_>>>>()?
5671 .into_iter()
5672 .flatten()
5673 .dedup()
5674 .collect(),
5675 ))
5676 })
5677 } else {
5678 let type_definitions_task = self.request_multiple_lsp_locally(
5679 buffer,
5680 Some(position),
5681 GetTypeDefinitions { position },
5682 cx,
5683 );
5684 cx.background_spawn(async move {
5685 Ok(Some(
5686 type_definitions_task
5687 .await
5688 .into_iter()
5689 .flat_map(|(_, type_definitions)| type_definitions)
5690 .dedup()
5691 .collect(),
5692 ))
5693 })
5694 }
5695 }
5696
5697 pub fn implementations(
5698 &mut self,
5699 buffer: &Entity<Buffer>,
5700 position: PointUtf16,
5701 cx: &mut Context<Self>,
5702 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5703 if let Some((upstream_client, project_id)) = self.upstream_client() {
5704 let request = GetImplementations { position };
5705 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5706 return Task::ready(Ok(None));
5707 }
5708 let request_task = upstream_client.request_lsp(
5709 project_id,
5710 None,
5711 LSP_REQUEST_TIMEOUT,
5712 cx.background_executor().clone(),
5713 request.to_proto(project_id, buffer.read(cx)),
5714 );
5715 let buffer = buffer.clone();
5716 cx.spawn(async move |weak_lsp_store, cx| {
5717 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5718 return Ok(None);
5719 };
5720 let Some(responses) = request_task.await? else {
5721 return Ok(None);
5722 };
5723 let actions = join_all(responses.payload.into_iter().map(|response| {
5724 GetImplementations { position }.response_from_proto(
5725 response.response,
5726 lsp_store.clone(),
5727 buffer.clone(),
5728 cx.clone(),
5729 )
5730 }))
5731 .await;
5732
5733 Ok(Some(
5734 actions
5735 .into_iter()
5736 .collect::<Result<Vec<Vec<_>>>>()?
5737 .into_iter()
5738 .flatten()
5739 .dedup()
5740 .collect(),
5741 ))
5742 })
5743 } else {
5744 let implementations_task = self.request_multiple_lsp_locally(
5745 buffer,
5746 Some(position),
5747 GetImplementations { position },
5748 cx,
5749 );
5750 cx.background_spawn(async move {
5751 Ok(Some(
5752 implementations_task
5753 .await
5754 .into_iter()
5755 .flat_map(|(_, implementations)| implementations)
5756 .dedup()
5757 .collect(),
5758 ))
5759 })
5760 }
5761 }
5762
5763 pub fn references(
5764 &mut self,
5765 buffer: &Entity<Buffer>,
5766 position: PointUtf16,
5767 cx: &mut Context<Self>,
5768 ) -> Task<Result<Option<Vec<Location>>>> {
5769 if let Some((upstream_client, project_id)) = self.upstream_client() {
5770 let request = GetReferences { position };
5771 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5772 return Task::ready(Ok(None));
5773 }
5774
5775 let request_task = upstream_client.request_lsp(
5776 project_id,
5777 None,
5778 LSP_REQUEST_TIMEOUT,
5779 cx.background_executor().clone(),
5780 request.to_proto(project_id, buffer.read(cx)),
5781 );
5782 let buffer = buffer.clone();
5783 cx.spawn(async move |weak_lsp_store, cx| {
5784 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5785 return Ok(None);
5786 };
5787 let Some(responses) = request_task.await? else {
5788 return Ok(None);
5789 };
5790
5791 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5792 GetReferences { position }.response_from_proto(
5793 lsp_response.response,
5794 lsp_store.clone(),
5795 buffer.clone(),
5796 cx.clone(),
5797 )
5798 }))
5799 .await
5800 .into_iter()
5801 .collect::<Result<Vec<Vec<_>>>>()?
5802 .into_iter()
5803 .flatten()
5804 .dedup()
5805 .collect();
5806 Ok(Some(locations))
5807 })
5808 } else {
5809 let references_task = self.request_multiple_lsp_locally(
5810 buffer,
5811 Some(position),
5812 GetReferences { position },
5813 cx,
5814 );
5815 cx.background_spawn(async move {
5816 Ok(Some(
5817 references_task
5818 .await
5819 .into_iter()
5820 .flat_map(|(_, references)| references)
5821 .dedup()
5822 .collect(),
5823 ))
5824 })
5825 }
5826 }
5827
5828 pub fn code_actions(
5829 &mut self,
5830 buffer: &Entity<Buffer>,
5831 range: Range<Anchor>,
5832 kinds: Option<Vec<CodeActionKind>>,
5833 cx: &mut Context<Self>,
5834 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5835 if let Some((upstream_client, project_id)) = self.upstream_client() {
5836 let request = GetCodeActions {
5837 range: range.clone(),
5838 kinds: kinds.clone(),
5839 };
5840 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5841 return Task::ready(Ok(None));
5842 }
5843 let request_task = upstream_client.request_lsp(
5844 project_id,
5845 None,
5846 LSP_REQUEST_TIMEOUT,
5847 cx.background_executor().clone(),
5848 request.to_proto(project_id, buffer.read(cx)),
5849 );
5850 let buffer = buffer.clone();
5851 cx.spawn(async move |weak_lsp_store, cx| {
5852 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5853 return Ok(None);
5854 };
5855 let Some(responses) = request_task.await? else {
5856 return Ok(None);
5857 };
5858 let actions = join_all(responses.payload.into_iter().map(|response| {
5859 GetCodeActions {
5860 range: range.clone(),
5861 kinds: kinds.clone(),
5862 }
5863 .response_from_proto(
5864 response.response,
5865 lsp_store.clone(),
5866 buffer.clone(),
5867 cx.clone(),
5868 )
5869 }))
5870 .await;
5871
5872 Ok(Some(
5873 actions
5874 .into_iter()
5875 .collect::<Result<Vec<Vec<_>>>>()?
5876 .into_iter()
5877 .flatten()
5878 .collect(),
5879 ))
5880 })
5881 } else {
5882 let all_actions_task = self.request_multiple_lsp_locally(
5883 buffer,
5884 Some(range.start),
5885 GetCodeActions { range, kinds },
5886 cx,
5887 );
5888 cx.background_spawn(async move {
5889 Ok(Some(
5890 all_actions_task
5891 .await
5892 .into_iter()
5893 .flat_map(|(_, actions)| actions)
5894 .collect(),
5895 ))
5896 })
5897 }
5898 }
5899
5900 pub fn code_lens_actions(
5901 &mut self,
5902 buffer: &Entity<Buffer>,
5903 cx: &mut Context<Self>,
5904 ) -> CodeLensTask {
5905 let version_queried_for = buffer.read(cx).version();
5906 let buffer_id = buffer.read(cx).remote_id();
5907 let existing_servers = self.as_local().map(|local| {
5908 local
5909 .buffers_opened_in_servers
5910 .get(&buffer_id)
5911 .cloned()
5912 .unwrap_or_default()
5913 });
5914
5915 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5916 if let Some(cached_lens) = &lsp_data.code_lens {
5917 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5918 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5919 existing_servers != cached_lens.lens.keys().copied().collect()
5920 });
5921 if !has_different_servers {
5922 return Task::ready(Ok(Some(
5923 cached_lens.lens.values().flatten().cloned().collect(),
5924 )))
5925 .shared();
5926 }
5927 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5928 if !version_queried_for.changed_since(updating_for) {
5929 return running_update.clone();
5930 }
5931 }
5932 }
5933 }
5934
5935 let lens_lsp_data = self
5936 .latest_lsp_data(buffer, cx)
5937 .code_lens
5938 .get_or_insert_default();
5939 let buffer = buffer.clone();
5940 let query_version_queried_for = version_queried_for.clone();
5941 let new_task = cx
5942 .spawn(async move |lsp_store, cx| {
5943 cx.background_executor()
5944 .timer(Duration::from_millis(30))
5945 .await;
5946 let fetched_lens = lsp_store
5947 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5948 .map_err(Arc::new)?
5949 .await
5950 .context("fetching code lens")
5951 .map_err(Arc::new);
5952 let fetched_lens = match fetched_lens {
5953 Ok(fetched_lens) => fetched_lens,
5954 Err(e) => {
5955 lsp_store
5956 .update(cx, |lsp_store, _| {
5957 if let Some(lens_lsp_data) = lsp_store
5958 .lsp_data
5959 .get_mut(&buffer_id)
5960 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5961 {
5962 lens_lsp_data.update = None;
5963 }
5964 })
5965 .ok();
5966 return Err(e);
5967 }
5968 };
5969
5970 lsp_store
5971 .update(cx, |lsp_store, _| {
5972 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5973 let code_lens = lsp_data.code_lens.as_mut()?;
5974 if let Some(fetched_lens) = fetched_lens {
5975 if lsp_data.buffer_version == query_version_queried_for {
5976 code_lens.lens.extend(fetched_lens);
5977 } else if !lsp_data
5978 .buffer_version
5979 .changed_since(&query_version_queried_for)
5980 {
5981 lsp_data.buffer_version = query_version_queried_for;
5982 code_lens.lens = fetched_lens;
5983 }
5984 }
5985 code_lens.update = None;
5986 Some(code_lens.lens.values().flatten().cloned().collect())
5987 })
5988 .map_err(Arc::new)
5989 })
5990 .shared();
5991 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5992 new_task
5993 }
5994
5995 fn fetch_code_lens(
5996 &mut self,
5997 buffer: &Entity<Buffer>,
5998 cx: &mut Context<Self>,
5999 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6000 if let Some((upstream_client, project_id)) = self.upstream_client() {
6001 let request = GetCodeLens;
6002 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6003 return Task::ready(Ok(None));
6004 }
6005 let request_task = upstream_client.request_lsp(
6006 project_id,
6007 None,
6008 LSP_REQUEST_TIMEOUT,
6009 cx.background_executor().clone(),
6010 request.to_proto(project_id, buffer.read(cx)),
6011 );
6012 let buffer = buffer.clone();
6013 cx.spawn(async move |weak_lsp_store, cx| {
6014 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6015 return Ok(None);
6016 };
6017 let Some(responses) = request_task.await? else {
6018 return Ok(None);
6019 };
6020
6021 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6022 let lsp_store = lsp_store.clone();
6023 let buffer = buffer.clone();
6024 let cx = cx.clone();
6025 async move {
6026 (
6027 LanguageServerId::from_proto(response.server_id),
6028 GetCodeLens
6029 .response_from_proto(response.response, lsp_store, buffer, cx)
6030 .await,
6031 )
6032 }
6033 }))
6034 .await;
6035
6036 let mut has_errors = false;
6037 let code_lens_actions = code_lens_actions
6038 .into_iter()
6039 .filter_map(|(server_id, code_lens)| match code_lens {
6040 Ok(code_lens) => Some((server_id, code_lens)),
6041 Err(e) => {
6042 has_errors = true;
6043 log::error!("{e:#}");
6044 None
6045 }
6046 })
6047 .collect::<HashMap<_, _>>();
6048 anyhow::ensure!(
6049 !has_errors || !code_lens_actions.is_empty(),
6050 "Failed to fetch code lens"
6051 );
6052 Ok(Some(code_lens_actions))
6053 })
6054 } else {
6055 let code_lens_actions_task =
6056 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6057 cx.background_spawn(async move {
6058 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6059 })
6060 }
6061 }
6062
6063 #[inline(never)]
6064 pub fn completions(
6065 &self,
6066 buffer: &Entity<Buffer>,
6067 position: PointUtf16,
6068 context: CompletionContext,
6069 cx: &mut Context<Self>,
6070 ) -> Task<Result<Vec<CompletionResponse>>> {
6071 let language_registry = self.languages.clone();
6072
6073 if let Some((upstream_client, project_id)) = self.upstream_client() {
6074 let snapshot = buffer.read(cx).snapshot();
6075 let offset = position.to_offset(&snapshot);
6076 let scope = snapshot.language_scope_at(offset);
6077 let capable_lsps = self.all_capable_for_proto_request(
6078 buffer,
6079 |server_name, capabilities| {
6080 capabilities.completion_provider.is_some()
6081 && scope
6082 .as_ref()
6083 .map(|scope| scope.language_allowed(server_name))
6084 .unwrap_or(true)
6085 },
6086 cx,
6087 );
6088 if capable_lsps.is_empty() {
6089 return Task::ready(Ok(Vec::new()));
6090 }
6091
6092 let language = buffer.read(cx).language().cloned();
6093
6094 // In the future, we should provide project guests with the names of LSP adapters,
6095 // so that they can use the correct LSP adapter when computing labels. For now,
6096 // guests just use the first LSP adapter associated with the buffer's language.
6097 let lsp_adapter = language.as_ref().and_then(|language| {
6098 language_registry
6099 .lsp_adapters(&language.name())
6100 .first()
6101 .cloned()
6102 });
6103
6104 let buffer = buffer.clone();
6105
6106 cx.spawn(async move |this, cx| {
6107 let requests = join_all(
6108 capable_lsps
6109 .into_iter()
6110 .map(|id| {
6111 let request = GetCompletions {
6112 position,
6113 context: context.clone(),
6114 server_id: Some(id),
6115 };
6116 let buffer = buffer.clone();
6117 let language = language.clone();
6118 let lsp_adapter = lsp_adapter.clone();
6119 let upstream_client = upstream_client.clone();
6120 let response = this
6121 .update(cx, |this, cx| {
6122 this.send_lsp_proto_request(
6123 buffer,
6124 upstream_client,
6125 project_id,
6126 request,
6127 cx,
6128 )
6129 })
6130 .log_err();
6131 async move {
6132 let response = response?.await.log_err()?;
6133
6134 let completions = populate_labels_for_completions(
6135 response.completions,
6136 language,
6137 lsp_adapter,
6138 )
6139 .await;
6140
6141 Some(CompletionResponse {
6142 completions,
6143 display_options: CompletionDisplayOptions::default(),
6144 is_incomplete: response.is_incomplete,
6145 })
6146 }
6147 })
6148 .collect::<Vec<_>>(),
6149 );
6150 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6151 })
6152 } else if let Some(local) = self.as_local() {
6153 let snapshot = buffer.read(cx).snapshot();
6154 let offset = position.to_offset(&snapshot);
6155 let scope = snapshot.language_scope_at(offset);
6156 let language = snapshot.language().cloned();
6157 let completion_settings = language_settings(
6158 language.as_ref().map(|language| language.name()),
6159 buffer.read(cx).file(),
6160 cx,
6161 )
6162 .completions
6163 .clone();
6164 if !completion_settings.lsp {
6165 return Task::ready(Ok(Vec::new()));
6166 }
6167
6168 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6169 local
6170 .language_servers_for_buffer(buffer, cx)
6171 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6172 .filter(|(adapter, _)| {
6173 scope
6174 .as_ref()
6175 .map(|scope| scope.language_allowed(&adapter.name))
6176 .unwrap_or(true)
6177 })
6178 .map(|(_, server)| server.server_id())
6179 .collect()
6180 });
6181
6182 let buffer = buffer.clone();
6183 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6184 let lsp_timeout = if lsp_timeout > 0 {
6185 Some(Duration::from_millis(lsp_timeout))
6186 } else {
6187 None
6188 };
6189 cx.spawn(async move |this, cx| {
6190 let mut tasks = Vec::with_capacity(server_ids.len());
6191 this.update(cx, |lsp_store, cx| {
6192 for server_id in server_ids {
6193 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6194 let lsp_timeout = lsp_timeout
6195 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6196 let mut timeout = cx.background_spawn(async move {
6197 match lsp_timeout {
6198 Some(lsp_timeout) => {
6199 lsp_timeout.await;
6200 true
6201 },
6202 None => false,
6203 }
6204 }).fuse();
6205 let mut lsp_request = lsp_store.request_lsp(
6206 buffer.clone(),
6207 LanguageServerToQuery::Other(server_id),
6208 GetCompletions {
6209 position,
6210 context: context.clone(),
6211 server_id: Some(server_id),
6212 },
6213 cx,
6214 ).fuse();
6215 let new_task = cx.background_spawn(async move {
6216 select_biased! {
6217 response = lsp_request => anyhow::Ok(Some(response?)),
6218 timeout_happened = timeout => {
6219 if timeout_happened {
6220 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6221 Ok(None)
6222 } else {
6223 let completions = lsp_request.await?;
6224 Ok(Some(completions))
6225 }
6226 },
6227 }
6228 });
6229 tasks.push((lsp_adapter, new_task));
6230 }
6231 })?;
6232
6233 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6234 let completion_response = task.await.ok()??;
6235 let completions = populate_labels_for_completions(
6236 completion_response.completions,
6237 language.clone(),
6238 lsp_adapter,
6239 )
6240 .await;
6241 Some(CompletionResponse {
6242 completions,
6243 display_options: CompletionDisplayOptions::default(),
6244 is_incomplete: completion_response.is_incomplete,
6245 })
6246 });
6247
6248 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6249
6250 Ok(responses.into_iter().flatten().collect())
6251 })
6252 } else {
6253 Task::ready(Err(anyhow!("No upstream client or local language server")))
6254 }
6255 }
6256
6257 pub fn resolve_completions(
6258 &self,
6259 buffer: Entity<Buffer>,
6260 completion_indices: Vec<usize>,
6261 completions: Rc<RefCell<Box<[Completion]>>>,
6262 cx: &mut Context<Self>,
6263 ) -> Task<Result<bool>> {
6264 let client = self.upstream_client();
6265 let buffer_id = buffer.read(cx).remote_id();
6266 let buffer_snapshot = buffer.read(cx).snapshot();
6267
6268 if !self.check_if_capable_for_proto_request(
6269 &buffer,
6270 GetCompletions::can_resolve_completions,
6271 cx,
6272 ) {
6273 return Task::ready(Ok(false));
6274 }
6275 cx.spawn(async move |lsp_store, cx| {
6276 let mut did_resolve = false;
6277 if let Some((client, project_id)) = client {
6278 for completion_index in completion_indices {
6279 let server_id = {
6280 let completion = &completions.borrow()[completion_index];
6281 completion.source.server_id()
6282 };
6283 if let Some(server_id) = server_id {
6284 if Self::resolve_completion_remote(
6285 project_id,
6286 server_id,
6287 buffer_id,
6288 completions.clone(),
6289 completion_index,
6290 client.clone(),
6291 )
6292 .await
6293 .log_err()
6294 .is_some()
6295 {
6296 did_resolve = true;
6297 }
6298 } else {
6299 resolve_word_completion(
6300 &buffer_snapshot,
6301 &mut completions.borrow_mut()[completion_index],
6302 );
6303 }
6304 }
6305 } else {
6306 for completion_index in completion_indices {
6307 let server_id = {
6308 let completion = &completions.borrow()[completion_index];
6309 completion.source.server_id()
6310 };
6311 if let Some(server_id) = server_id {
6312 let server_and_adapter = lsp_store
6313 .read_with(cx, |lsp_store, _| {
6314 let server = lsp_store.language_server_for_id(server_id)?;
6315 let adapter =
6316 lsp_store.language_server_adapter_for_id(server.server_id())?;
6317 Some((server, adapter))
6318 })
6319 .ok()
6320 .flatten();
6321 let Some((server, adapter)) = server_and_adapter else {
6322 continue;
6323 };
6324
6325 let resolved = Self::resolve_completion_local(
6326 server,
6327 completions.clone(),
6328 completion_index,
6329 )
6330 .await
6331 .log_err()
6332 .is_some();
6333 if resolved {
6334 Self::regenerate_completion_labels(
6335 adapter,
6336 &buffer_snapshot,
6337 completions.clone(),
6338 completion_index,
6339 )
6340 .await
6341 .log_err();
6342 did_resolve = true;
6343 }
6344 } else {
6345 resolve_word_completion(
6346 &buffer_snapshot,
6347 &mut completions.borrow_mut()[completion_index],
6348 );
6349 }
6350 }
6351 }
6352
6353 Ok(did_resolve)
6354 })
6355 }
6356
6357 async fn resolve_completion_local(
6358 server: Arc<lsp::LanguageServer>,
6359 completions: Rc<RefCell<Box<[Completion]>>>,
6360 completion_index: usize,
6361 ) -> Result<()> {
6362 let server_id = server.server_id();
6363 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6364 return Ok(());
6365 }
6366
6367 let request = {
6368 let completion = &completions.borrow()[completion_index];
6369 match &completion.source {
6370 CompletionSource::Lsp {
6371 lsp_completion,
6372 resolved,
6373 server_id: completion_server_id,
6374 ..
6375 } => {
6376 if *resolved {
6377 return Ok(());
6378 }
6379 anyhow::ensure!(
6380 server_id == *completion_server_id,
6381 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6382 );
6383 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6384 }
6385 CompletionSource::BufferWord { .. }
6386 | CompletionSource::Dap { .. }
6387 | CompletionSource::Custom => {
6388 return Ok(());
6389 }
6390 }
6391 };
6392 let resolved_completion = request
6393 .await
6394 .into_response()
6395 .context("resolve completion")?;
6396
6397 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6398 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6399
6400 let mut completions = completions.borrow_mut();
6401 let completion = &mut completions[completion_index];
6402 if let CompletionSource::Lsp {
6403 lsp_completion,
6404 resolved,
6405 server_id: completion_server_id,
6406 ..
6407 } = &mut completion.source
6408 {
6409 if *resolved {
6410 return Ok(());
6411 }
6412 anyhow::ensure!(
6413 server_id == *completion_server_id,
6414 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6415 );
6416 *lsp_completion = Box::new(resolved_completion);
6417 *resolved = true;
6418 }
6419 Ok(())
6420 }
6421
6422 async fn regenerate_completion_labels(
6423 adapter: Arc<CachedLspAdapter>,
6424 snapshot: &BufferSnapshot,
6425 completions: Rc<RefCell<Box<[Completion]>>>,
6426 completion_index: usize,
6427 ) -> Result<()> {
6428 let completion_item = completions.borrow()[completion_index]
6429 .source
6430 .lsp_completion(true)
6431 .map(Cow::into_owned);
6432 if let Some(lsp_documentation) = completion_item
6433 .as_ref()
6434 .and_then(|completion_item| completion_item.documentation.clone())
6435 {
6436 let mut completions = completions.borrow_mut();
6437 let completion = &mut completions[completion_index];
6438 completion.documentation = Some(lsp_documentation.into());
6439 } else {
6440 let mut completions = completions.borrow_mut();
6441 let completion = &mut completions[completion_index];
6442 completion.documentation = Some(CompletionDocumentation::Undocumented);
6443 }
6444
6445 let mut new_label = match completion_item {
6446 Some(completion_item) => {
6447 // 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
6448 // So we have to update the label here anyway...
6449 let language = snapshot.language();
6450 match language {
6451 Some(language) => {
6452 adapter
6453 .labels_for_completions(
6454 std::slice::from_ref(&completion_item),
6455 language,
6456 )
6457 .await?
6458 }
6459 None => Vec::new(),
6460 }
6461 .pop()
6462 .flatten()
6463 .unwrap_or_else(|| {
6464 CodeLabel::fallback_for_completion(
6465 &completion_item,
6466 language.map(|language| language.as_ref()),
6467 )
6468 })
6469 }
6470 None => CodeLabel::plain(
6471 completions.borrow()[completion_index].new_text.clone(),
6472 None,
6473 ),
6474 };
6475 ensure_uniform_list_compatible_label(&mut new_label);
6476
6477 let mut completions = completions.borrow_mut();
6478 let completion = &mut completions[completion_index];
6479 if completion.label.filter_text() == new_label.filter_text() {
6480 completion.label = new_label;
6481 } else {
6482 log::error!(
6483 "Resolved completion changed display label from {} to {}. \
6484 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6485 completion.label.text(),
6486 new_label.text(),
6487 completion.label.filter_text(),
6488 new_label.filter_text()
6489 );
6490 }
6491
6492 Ok(())
6493 }
6494
6495 async fn resolve_completion_remote(
6496 project_id: u64,
6497 server_id: LanguageServerId,
6498 buffer_id: BufferId,
6499 completions: Rc<RefCell<Box<[Completion]>>>,
6500 completion_index: usize,
6501 client: AnyProtoClient,
6502 ) -> Result<()> {
6503 let lsp_completion = {
6504 let completion = &completions.borrow()[completion_index];
6505 match &completion.source {
6506 CompletionSource::Lsp {
6507 lsp_completion,
6508 resolved,
6509 server_id: completion_server_id,
6510 ..
6511 } => {
6512 anyhow::ensure!(
6513 server_id == *completion_server_id,
6514 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6515 );
6516 if *resolved {
6517 return Ok(());
6518 }
6519 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6520 }
6521 CompletionSource::Custom
6522 | CompletionSource::Dap { .. }
6523 | CompletionSource::BufferWord { .. } => {
6524 return Ok(());
6525 }
6526 }
6527 };
6528 let request = proto::ResolveCompletionDocumentation {
6529 project_id,
6530 language_server_id: server_id.0 as u64,
6531 lsp_completion,
6532 buffer_id: buffer_id.into(),
6533 };
6534
6535 let response = client
6536 .request(request)
6537 .await
6538 .context("completion documentation resolve proto request")?;
6539 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6540
6541 let documentation = if response.documentation.is_empty() {
6542 CompletionDocumentation::Undocumented
6543 } else if response.documentation_is_markdown {
6544 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6545 } else if response.documentation.lines().count() <= 1 {
6546 CompletionDocumentation::SingleLine(response.documentation.into())
6547 } else {
6548 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6549 };
6550
6551 let mut completions = completions.borrow_mut();
6552 let completion = &mut completions[completion_index];
6553 completion.documentation = Some(documentation);
6554 if let CompletionSource::Lsp {
6555 insert_range,
6556 lsp_completion,
6557 resolved,
6558 server_id: completion_server_id,
6559 lsp_defaults: _,
6560 } = &mut completion.source
6561 {
6562 let completion_insert_range = response
6563 .old_insert_start
6564 .and_then(deserialize_anchor)
6565 .zip(response.old_insert_end.and_then(deserialize_anchor));
6566 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6567
6568 if *resolved {
6569 return Ok(());
6570 }
6571 anyhow::ensure!(
6572 server_id == *completion_server_id,
6573 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6574 );
6575 *lsp_completion = Box::new(resolved_lsp_completion);
6576 *resolved = true;
6577 }
6578
6579 let replace_range = response
6580 .old_replace_start
6581 .and_then(deserialize_anchor)
6582 .zip(response.old_replace_end.and_then(deserialize_anchor));
6583 if let Some((old_replace_start, old_replace_end)) = replace_range
6584 && !response.new_text.is_empty()
6585 {
6586 completion.new_text = response.new_text;
6587 completion.replace_range = old_replace_start..old_replace_end;
6588 }
6589
6590 Ok(())
6591 }
6592
6593 pub fn apply_additional_edits_for_completion(
6594 &self,
6595 buffer_handle: Entity<Buffer>,
6596 completions: Rc<RefCell<Box<[Completion]>>>,
6597 completion_index: usize,
6598 push_to_history: bool,
6599 cx: &mut Context<Self>,
6600 ) -> Task<Result<Option<Transaction>>> {
6601 if let Some((client, project_id)) = self.upstream_client() {
6602 let buffer = buffer_handle.read(cx);
6603 let buffer_id = buffer.remote_id();
6604 cx.spawn(async move |_, cx| {
6605 let request = {
6606 let completion = completions.borrow()[completion_index].clone();
6607 proto::ApplyCompletionAdditionalEdits {
6608 project_id,
6609 buffer_id: buffer_id.into(),
6610 completion: Some(Self::serialize_completion(&CoreCompletion {
6611 replace_range: completion.replace_range,
6612 new_text: completion.new_text,
6613 source: completion.source,
6614 })),
6615 }
6616 };
6617
6618 if let Some(transaction) = client.request(request).await?.transaction {
6619 let transaction = language::proto::deserialize_transaction(transaction)?;
6620 buffer_handle
6621 .update(cx, |buffer, _| {
6622 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6623 })?
6624 .await?;
6625 if push_to_history {
6626 buffer_handle.update(cx, |buffer, _| {
6627 buffer.push_transaction(transaction.clone(), Instant::now());
6628 buffer.finalize_last_transaction();
6629 })?;
6630 }
6631 Ok(Some(transaction))
6632 } else {
6633 Ok(None)
6634 }
6635 })
6636 } else {
6637 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6638 let completion = &completions.borrow()[completion_index];
6639 let server_id = completion.source.server_id()?;
6640 Some(
6641 self.language_server_for_local_buffer(buffer, server_id, cx)?
6642 .1
6643 .clone(),
6644 )
6645 }) else {
6646 return Task::ready(Ok(None));
6647 };
6648
6649 cx.spawn(async move |this, cx| {
6650 Self::resolve_completion_local(
6651 server.clone(),
6652 completions.clone(),
6653 completion_index,
6654 )
6655 .await
6656 .context("resolving completion")?;
6657 let completion = completions.borrow()[completion_index].clone();
6658 let additional_text_edits = completion
6659 .source
6660 .lsp_completion(true)
6661 .as_ref()
6662 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6663 if let Some(edits) = additional_text_edits {
6664 let edits = this
6665 .update(cx, |this, cx| {
6666 this.as_local_mut().unwrap().edits_from_lsp(
6667 &buffer_handle,
6668 edits,
6669 server.server_id(),
6670 None,
6671 cx,
6672 )
6673 })?
6674 .await?;
6675
6676 buffer_handle.update(cx, |buffer, cx| {
6677 buffer.finalize_last_transaction();
6678 buffer.start_transaction();
6679
6680 for (range, text) in edits {
6681 let primary = &completion.replace_range;
6682
6683 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6684 // and the primary completion is just an insertion (empty range), then this is likely
6685 // an auto-import scenario and should not be considered overlapping
6686 // https://github.com/zed-industries/zed/issues/26136
6687 let is_file_start_auto_import = {
6688 let snapshot = buffer.snapshot();
6689 let primary_start_point = primary.start.to_point(&snapshot);
6690 let range_start_point = range.start.to_point(&snapshot);
6691
6692 let result = primary_start_point.row == 0
6693 && primary_start_point.column == 0
6694 && range_start_point.row == 0
6695 && range_start_point.column == 0;
6696
6697 result
6698 };
6699
6700 let has_overlap = if is_file_start_auto_import {
6701 false
6702 } else {
6703 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6704 && primary.end.cmp(&range.start, buffer).is_ge();
6705 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6706 && range.end.cmp(&primary.end, buffer).is_ge();
6707 let result = start_within || end_within;
6708 result
6709 };
6710
6711 //Skip additional edits which overlap with the primary completion edit
6712 //https://github.com/zed-industries/zed/pull/1871
6713 if !has_overlap {
6714 buffer.edit([(range, text)], None, cx);
6715 }
6716 }
6717
6718 let transaction = if buffer.end_transaction(cx).is_some() {
6719 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6720 if !push_to_history {
6721 buffer.forget_transaction(transaction.id);
6722 }
6723 Some(transaction)
6724 } else {
6725 None
6726 };
6727 Ok(transaction)
6728 })?
6729 } else {
6730 Ok(None)
6731 }
6732 })
6733 }
6734 }
6735
6736 pub fn pull_diagnostics(
6737 &mut self,
6738 buffer: Entity<Buffer>,
6739 cx: &mut Context<Self>,
6740 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6741 let buffer_id = buffer.read(cx).remote_id();
6742
6743 if let Some((client, upstream_project_id)) = self.upstream_client() {
6744 let mut suitable_capabilities = None;
6745 // Are we capable for proto request?
6746 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6747 &buffer,
6748 |capabilities| {
6749 if let Some(caps) = &capabilities.diagnostic_provider {
6750 suitable_capabilities = Some(caps.clone());
6751 true
6752 } else {
6753 false
6754 }
6755 },
6756 cx,
6757 );
6758 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6759 let Some(dynamic_caps) = suitable_capabilities else {
6760 return Task::ready(Ok(None));
6761 };
6762 assert!(any_server_has_diagnostics_provider);
6763
6764 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6765 let request = GetDocumentDiagnostics {
6766 previous_result_id: None,
6767 identifier,
6768 registration_id: None,
6769 };
6770 let request_task = client.request_lsp(
6771 upstream_project_id,
6772 None,
6773 LSP_REQUEST_TIMEOUT,
6774 cx.background_executor().clone(),
6775 request.to_proto(upstream_project_id, buffer.read(cx)),
6776 );
6777 cx.background_spawn(async move {
6778 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6779 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6780 // Do not attempt to further process the dummy responses here.
6781 let _response = request_task.await?;
6782 Ok(None)
6783 })
6784 } else {
6785 let servers = buffer.update(cx, |buffer, cx| {
6786 self.running_language_servers_for_local_buffer(buffer, cx)
6787 .map(|(_, server)| server.clone())
6788 .collect::<Vec<_>>()
6789 });
6790
6791 let pull_diagnostics = servers
6792 .into_iter()
6793 .flat_map(|server| {
6794 let result = maybe!({
6795 let local = self.as_local()?;
6796 let server_id = server.server_id();
6797 let providers_with_identifiers = local
6798 .language_server_dynamic_registrations
6799 .get(&server_id)
6800 .into_iter()
6801 .flat_map(|registrations| registrations.diagnostics.clone())
6802 .collect::<Vec<_>>();
6803 Some(
6804 providers_with_identifiers
6805 .into_iter()
6806 .map(|(registration_id, dynamic_caps)| {
6807 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6808 let registration_id = registration_id.map(SharedString::from);
6809 let result_id = self.result_id_for_buffer_pull(
6810 server_id,
6811 buffer_id,
6812 ®istration_id,
6813 cx,
6814 );
6815 self.request_lsp(
6816 buffer.clone(),
6817 LanguageServerToQuery::Other(server_id),
6818 GetDocumentDiagnostics {
6819 previous_result_id: result_id,
6820 registration_id,
6821 identifier,
6822 },
6823 cx,
6824 )
6825 })
6826 .collect::<Vec<_>>(),
6827 )
6828 });
6829
6830 result.unwrap_or_default()
6831 })
6832 .collect::<Vec<_>>();
6833
6834 cx.background_spawn(async move {
6835 let mut responses = Vec::new();
6836 for diagnostics in join_all(pull_diagnostics).await {
6837 responses.extend(diagnostics?);
6838 }
6839 Ok(Some(responses))
6840 })
6841 }
6842 }
6843
6844 pub fn applicable_inlay_chunks(
6845 &mut self,
6846 buffer: &Entity<Buffer>,
6847 ranges: &[Range<text::Anchor>],
6848 cx: &mut Context<Self>,
6849 ) -> Vec<Range<BufferRow>> {
6850 self.latest_lsp_data(buffer, cx)
6851 .inlay_hints
6852 .applicable_chunks(ranges)
6853 .map(|chunk| chunk.row_range())
6854 .collect()
6855 }
6856
6857 pub fn invalidate_inlay_hints<'a>(
6858 &'a mut self,
6859 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6860 ) {
6861 for buffer_id in for_buffers {
6862 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6863 lsp_data.inlay_hints.clear();
6864 }
6865 }
6866 }
6867
6868 pub fn inlay_hints(
6869 &mut self,
6870 invalidate: InvalidationStrategy,
6871 buffer: Entity<Buffer>,
6872 ranges: Vec<Range<text::Anchor>>,
6873 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6874 cx: &mut Context<Self>,
6875 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6876 let next_hint_id = self.next_hint_id.clone();
6877 let lsp_data = self.latest_lsp_data(&buffer, cx);
6878 let query_version = lsp_data.buffer_version.clone();
6879 let mut lsp_refresh_requested = false;
6880 let for_server = if let InvalidationStrategy::RefreshRequested {
6881 server_id,
6882 request_id,
6883 } = invalidate
6884 {
6885 let invalidated = lsp_data
6886 .inlay_hints
6887 .invalidate_for_server_refresh(server_id, request_id);
6888 lsp_refresh_requested = invalidated;
6889 Some(server_id)
6890 } else {
6891 None
6892 };
6893 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6894 let known_chunks = known_chunks
6895 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6896 .map(|(_, known_chunks)| known_chunks)
6897 .unwrap_or_default();
6898
6899 let mut hint_fetch_tasks = Vec::new();
6900 let mut cached_inlay_hints = None;
6901 let mut ranges_to_query = None;
6902 let applicable_chunks = existing_inlay_hints
6903 .applicable_chunks(ranges.as_slice())
6904 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6905 .collect::<Vec<_>>();
6906 if applicable_chunks.is_empty() {
6907 return HashMap::default();
6908 }
6909
6910 for row_chunk in applicable_chunks {
6911 match (
6912 existing_inlay_hints
6913 .cached_hints(&row_chunk)
6914 .filter(|_| !lsp_refresh_requested)
6915 .cloned(),
6916 existing_inlay_hints
6917 .fetched_hints(&row_chunk)
6918 .as_ref()
6919 .filter(|_| !lsp_refresh_requested)
6920 .cloned(),
6921 ) {
6922 (None, None) => {
6923 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6924 continue;
6925 };
6926 ranges_to_query
6927 .get_or_insert_with(Vec::new)
6928 .push((row_chunk, chunk_range));
6929 }
6930 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6931 (Some(cached_hints), None) => {
6932 for (server_id, cached_hints) in cached_hints {
6933 if for_server.is_none_or(|for_server| for_server == server_id) {
6934 cached_inlay_hints
6935 .get_or_insert_with(HashMap::default)
6936 .entry(row_chunk.row_range())
6937 .or_insert_with(HashMap::default)
6938 .entry(server_id)
6939 .or_insert_with(Vec::new)
6940 .extend(cached_hints);
6941 }
6942 }
6943 }
6944 (Some(cached_hints), Some(fetched_hints)) => {
6945 hint_fetch_tasks.push((row_chunk, fetched_hints));
6946 for (server_id, cached_hints) in cached_hints {
6947 if for_server.is_none_or(|for_server| for_server == server_id) {
6948 cached_inlay_hints
6949 .get_or_insert_with(HashMap::default)
6950 .entry(row_chunk.row_range())
6951 .or_insert_with(HashMap::default)
6952 .entry(server_id)
6953 .or_insert_with(Vec::new)
6954 .extend(cached_hints);
6955 }
6956 }
6957 }
6958 }
6959 }
6960
6961 if hint_fetch_tasks.is_empty()
6962 && ranges_to_query
6963 .as_ref()
6964 .is_none_or(|ranges| ranges.is_empty())
6965 && let Some(cached_inlay_hints) = cached_inlay_hints
6966 {
6967 cached_inlay_hints
6968 .into_iter()
6969 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6970 .collect()
6971 } else {
6972 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6973 let next_hint_id = next_hint_id.clone();
6974 let buffer = buffer.clone();
6975 let query_version = query_version.clone();
6976 let new_inlay_hints = cx
6977 .spawn(async move |lsp_store, cx| {
6978 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6979 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6980 })?;
6981 new_fetch_task
6982 .await
6983 .and_then(|new_hints_by_server| {
6984 lsp_store.update(cx, |lsp_store, cx| {
6985 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6986 let update_cache = lsp_data.buffer_version == query_version;
6987 if new_hints_by_server.is_empty() {
6988 if update_cache {
6989 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6990 }
6991 HashMap::default()
6992 } else {
6993 new_hints_by_server
6994 .into_iter()
6995 .map(|(server_id, new_hints)| {
6996 let new_hints = new_hints
6997 .into_iter()
6998 .map(|new_hint| {
6999 (
7000 InlayId::Hint(next_hint_id.fetch_add(
7001 1,
7002 atomic::Ordering::AcqRel,
7003 )),
7004 new_hint,
7005 )
7006 })
7007 .collect::<Vec<_>>();
7008 if update_cache {
7009 lsp_data.inlay_hints.insert_new_hints(
7010 chunk,
7011 server_id,
7012 new_hints.clone(),
7013 );
7014 }
7015 (server_id, new_hints)
7016 })
7017 .collect()
7018 }
7019 })
7020 })
7021 .map_err(Arc::new)
7022 })
7023 .shared();
7024
7025 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7026 *fetch_task = Some(new_inlay_hints.clone());
7027 hint_fetch_tasks.push((chunk, new_inlay_hints));
7028 }
7029
7030 cached_inlay_hints
7031 .unwrap_or_default()
7032 .into_iter()
7033 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7034 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7035 (
7036 chunk.row_range(),
7037 cx.spawn(async move |_, _| {
7038 hints_fetch.await.map_err(|e| {
7039 if e.error_code() != ErrorCode::Internal {
7040 anyhow!(e.error_code())
7041 } else {
7042 anyhow!("{e:#}")
7043 }
7044 })
7045 }),
7046 )
7047 }))
7048 .collect()
7049 }
7050 }
7051
7052 fn fetch_inlay_hints(
7053 &mut self,
7054 for_server: Option<LanguageServerId>,
7055 buffer: &Entity<Buffer>,
7056 range: Range<Anchor>,
7057 cx: &mut Context<Self>,
7058 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7059 let request = InlayHints {
7060 range: range.clone(),
7061 };
7062 if let Some((upstream_client, project_id)) = self.upstream_client() {
7063 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7064 return Task::ready(Ok(HashMap::default()));
7065 }
7066 let request_task = upstream_client.request_lsp(
7067 project_id,
7068 for_server.map(|id| id.to_proto()),
7069 LSP_REQUEST_TIMEOUT,
7070 cx.background_executor().clone(),
7071 request.to_proto(project_id, buffer.read(cx)),
7072 );
7073 let buffer = buffer.clone();
7074 cx.spawn(async move |weak_lsp_store, cx| {
7075 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7076 return Ok(HashMap::default());
7077 };
7078 let Some(responses) = request_task.await? else {
7079 return Ok(HashMap::default());
7080 };
7081
7082 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7083 let lsp_store = lsp_store.clone();
7084 let buffer = buffer.clone();
7085 let cx = cx.clone();
7086 let request = request.clone();
7087 async move {
7088 (
7089 LanguageServerId::from_proto(response.server_id),
7090 request
7091 .response_from_proto(response.response, lsp_store, buffer, cx)
7092 .await,
7093 )
7094 }
7095 }))
7096 .await;
7097
7098 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7099 let mut has_errors = false;
7100 let inlay_hints = inlay_hints
7101 .into_iter()
7102 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7103 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7104 Err(e) => {
7105 has_errors = true;
7106 log::error!("{e:#}");
7107 None
7108 }
7109 })
7110 .map(|(server_id, mut new_hints)| {
7111 new_hints.retain(|hint| {
7112 hint.position.is_valid(&buffer_snapshot)
7113 && range.start.is_valid(&buffer_snapshot)
7114 && range.end.is_valid(&buffer_snapshot)
7115 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7116 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7117 });
7118 (server_id, new_hints)
7119 })
7120 .collect::<HashMap<_, _>>();
7121 anyhow::ensure!(
7122 !has_errors || !inlay_hints.is_empty(),
7123 "Failed to fetch inlay hints"
7124 );
7125 Ok(inlay_hints)
7126 })
7127 } else {
7128 let inlay_hints_task = match for_server {
7129 Some(server_id) => {
7130 let server_task = self.request_lsp(
7131 buffer.clone(),
7132 LanguageServerToQuery::Other(server_id),
7133 request,
7134 cx,
7135 );
7136 cx.background_spawn(async move {
7137 let mut responses = Vec::new();
7138 match server_task.await {
7139 Ok(response) => responses.push((server_id, response)),
7140 // rust-analyzer likes to error with this when its still loading up
7141 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7142 Err(e) => log::error!(
7143 "Error handling response for inlay hints request: {e:#}"
7144 ),
7145 }
7146 responses
7147 })
7148 }
7149 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7150 };
7151 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7152 cx.background_spawn(async move {
7153 Ok(inlay_hints_task
7154 .await
7155 .into_iter()
7156 .map(|(server_id, mut new_hints)| {
7157 new_hints.retain(|hint| {
7158 hint.position.is_valid(&buffer_snapshot)
7159 && range.start.is_valid(&buffer_snapshot)
7160 && range.end.is_valid(&buffer_snapshot)
7161 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7162 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7163 });
7164 (server_id, new_hints)
7165 })
7166 .collect())
7167 })
7168 }
7169 }
7170
7171 pub fn pull_diagnostics_for_buffer(
7172 &mut self,
7173 buffer: Entity<Buffer>,
7174 cx: &mut Context<Self>,
7175 ) -> Task<anyhow::Result<()>> {
7176 let diagnostics = self.pull_diagnostics(buffer, cx);
7177 cx.spawn(async move |lsp_store, cx| {
7178 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7179 return Ok(());
7180 };
7181 lsp_store.update(cx, |lsp_store, cx| {
7182 if lsp_store.as_local().is_none() {
7183 return;
7184 }
7185
7186 let mut unchanged_buffers = HashMap::default();
7187 let server_diagnostics_updates = diagnostics
7188 .into_iter()
7189 .filter_map(|diagnostics_set| match diagnostics_set {
7190 LspPullDiagnostics::Response {
7191 server_id,
7192 uri,
7193 diagnostics,
7194 registration_id,
7195 } => Some((server_id, uri, diagnostics, registration_id)),
7196 LspPullDiagnostics::Default => None,
7197 })
7198 .fold(
7199 HashMap::default(),
7200 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7201 let (result_id, diagnostics) = match diagnostics {
7202 PulledDiagnostics::Unchanged { result_id } => {
7203 unchanged_buffers
7204 .entry(new_registration_id.clone())
7205 .or_insert_with(HashSet::default)
7206 .insert(uri.clone());
7207 (Some(result_id), Vec::new())
7208 }
7209 PulledDiagnostics::Changed {
7210 result_id,
7211 diagnostics,
7212 } => (result_id, diagnostics),
7213 };
7214 let disk_based_sources = Cow::Owned(
7215 lsp_store
7216 .language_server_adapter_for_id(server_id)
7217 .as_ref()
7218 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7219 .unwrap_or(&[])
7220 .to_vec(),
7221 );
7222 acc.entry(server_id)
7223 .or_insert_with(HashMap::default)
7224 .entry(new_registration_id.clone())
7225 .or_insert_with(Vec::new)
7226 .push(DocumentDiagnosticsUpdate {
7227 server_id,
7228 diagnostics: lsp::PublishDiagnosticsParams {
7229 uri,
7230 diagnostics,
7231 version: None,
7232 },
7233 result_id,
7234 disk_based_sources,
7235 registration_id: new_registration_id,
7236 });
7237 acc
7238 },
7239 );
7240
7241 for diagnostic_updates in server_diagnostics_updates.into_values() {
7242 for (registration_id, diagnostic_updates) in diagnostic_updates {
7243 lsp_store
7244 .merge_lsp_diagnostics(
7245 DiagnosticSourceKind::Pulled,
7246 diagnostic_updates,
7247 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7248 DiagnosticSourceKind::Pulled => {
7249 old_diagnostic.registration_id != registration_id
7250 || unchanged_buffers
7251 .get(&old_diagnostic.registration_id)
7252 .is_some_and(|unchanged_buffers| {
7253 unchanged_buffers.contains(&document_uri)
7254 })
7255 }
7256 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7257 true
7258 }
7259 },
7260 cx,
7261 )
7262 .log_err();
7263 }
7264 }
7265 })
7266 })
7267 }
7268
7269 pub fn document_colors(
7270 &mut self,
7271 known_cache_version: Option<usize>,
7272 buffer: Entity<Buffer>,
7273 cx: &mut Context<Self>,
7274 ) -> Option<DocumentColorTask> {
7275 let version_queried_for = buffer.read(cx).version();
7276 let buffer_id = buffer.read(cx).remote_id();
7277
7278 let current_language_servers = self.as_local().map(|local| {
7279 local
7280 .buffers_opened_in_servers
7281 .get(&buffer_id)
7282 .cloned()
7283 .unwrap_or_default()
7284 });
7285
7286 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7287 if let Some(cached_colors) = &lsp_data.document_colors {
7288 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7289 let has_different_servers =
7290 current_language_servers.is_some_and(|current_language_servers| {
7291 current_language_servers
7292 != cached_colors.colors.keys().copied().collect()
7293 });
7294 if !has_different_servers {
7295 let cache_version = cached_colors.cache_version;
7296 if Some(cache_version) == known_cache_version {
7297 return None;
7298 } else {
7299 return Some(
7300 Task::ready(Ok(DocumentColors {
7301 colors: cached_colors
7302 .colors
7303 .values()
7304 .flatten()
7305 .cloned()
7306 .collect(),
7307 cache_version: Some(cache_version),
7308 }))
7309 .shared(),
7310 );
7311 }
7312 }
7313 }
7314 }
7315 }
7316
7317 let color_lsp_data = self
7318 .latest_lsp_data(&buffer, cx)
7319 .document_colors
7320 .get_or_insert_default();
7321 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7322 && !version_queried_for.changed_since(updating_for)
7323 {
7324 return Some(running_update.clone());
7325 }
7326 let buffer_version_queried_for = version_queried_for.clone();
7327 let new_task = cx
7328 .spawn(async move |lsp_store, cx| {
7329 cx.background_executor()
7330 .timer(Duration::from_millis(30))
7331 .await;
7332 let fetched_colors = lsp_store
7333 .update(cx, |lsp_store, cx| {
7334 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7335 })?
7336 .await
7337 .context("fetching document colors")
7338 .map_err(Arc::new);
7339 let fetched_colors = match fetched_colors {
7340 Ok(fetched_colors) => {
7341 if Some(true)
7342 == buffer
7343 .update(cx, |buffer, _| {
7344 buffer.version() != buffer_version_queried_for
7345 })
7346 .ok()
7347 {
7348 return Ok(DocumentColors::default());
7349 }
7350 fetched_colors
7351 }
7352 Err(e) => {
7353 lsp_store
7354 .update(cx, |lsp_store, _| {
7355 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7356 if let Some(document_colors) = &mut lsp_data.document_colors {
7357 document_colors.colors_update = None;
7358 }
7359 }
7360 })
7361 .ok();
7362 return Err(e);
7363 }
7364 };
7365
7366 lsp_store
7367 .update(cx, |lsp_store, cx| {
7368 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7369 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7370
7371 if let Some(fetched_colors) = fetched_colors {
7372 if lsp_data.buffer_version == buffer_version_queried_for {
7373 lsp_colors.colors.extend(fetched_colors);
7374 lsp_colors.cache_version += 1;
7375 } else if !lsp_data
7376 .buffer_version
7377 .changed_since(&buffer_version_queried_for)
7378 {
7379 lsp_data.buffer_version = buffer_version_queried_for;
7380 lsp_colors.colors = fetched_colors;
7381 lsp_colors.cache_version += 1;
7382 }
7383 }
7384 lsp_colors.colors_update = None;
7385 let colors = lsp_colors
7386 .colors
7387 .values()
7388 .flatten()
7389 .cloned()
7390 .collect::<HashSet<_>>();
7391 DocumentColors {
7392 colors,
7393 cache_version: Some(lsp_colors.cache_version),
7394 }
7395 })
7396 .map_err(Arc::new)
7397 })
7398 .shared();
7399 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7400 Some(new_task)
7401 }
7402
7403 fn fetch_document_colors_for_buffer(
7404 &mut self,
7405 buffer: &Entity<Buffer>,
7406 cx: &mut Context<Self>,
7407 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7408 if let Some((client, project_id)) = self.upstream_client() {
7409 let request = GetDocumentColor {};
7410 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7411 return Task::ready(Ok(None));
7412 }
7413
7414 let request_task = client.request_lsp(
7415 project_id,
7416 None,
7417 LSP_REQUEST_TIMEOUT,
7418 cx.background_executor().clone(),
7419 request.to_proto(project_id, buffer.read(cx)),
7420 );
7421 let buffer = buffer.clone();
7422 cx.spawn(async move |lsp_store, cx| {
7423 let Some(lsp_store) = lsp_store.upgrade() else {
7424 return Ok(None);
7425 };
7426 let colors = join_all(
7427 request_task
7428 .await
7429 .log_err()
7430 .flatten()
7431 .map(|response| response.payload)
7432 .unwrap_or_default()
7433 .into_iter()
7434 .map(|color_response| {
7435 let response = request.response_from_proto(
7436 color_response.response,
7437 lsp_store.clone(),
7438 buffer.clone(),
7439 cx.clone(),
7440 );
7441 async move {
7442 (
7443 LanguageServerId::from_proto(color_response.server_id),
7444 response.await.log_err().unwrap_or_default(),
7445 )
7446 }
7447 }),
7448 )
7449 .await
7450 .into_iter()
7451 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7452 acc.entry(server_id)
7453 .or_insert_with(HashSet::default)
7454 .extend(colors);
7455 acc
7456 });
7457 Ok(Some(colors))
7458 })
7459 } else {
7460 let document_colors_task =
7461 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7462 cx.background_spawn(async move {
7463 Ok(Some(
7464 document_colors_task
7465 .await
7466 .into_iter()
7467 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7468 acc.entry(server_id)
7469 .or_insert_with(HashSet::default)
7470 .extend(colors);
7471 acc
7472 })
7473 .into_iter()
7474 .collect(),
7475 ))
7476 })
7477 }
7478 }
7479
7480 pub fn signature_help<T: ToPointUtf16>(
7481 &mut self,
7482 buffer: &Entity<Buffer>,
7483 position: T,
7484 cx: &mut Context<Self>,
7485 ) -> Task<Option<Vec<SignatureHelp>>> {
7486 let position = position.to_point_utf16(buffer.read(cx));
7487
7488 if let Some((client, upstream_project_id)) = self.upstream_client() {
7489 let request = GetSignatureHelp { position };
7490 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7491 return Task::ready(None);
7492 }
7493 let request_task = client.request_lsp(
7494 upstream_project_id,
7495 None,
7496 LSP_REQUEST_TIMEOUT,
7497 cx.background_executor().clone(),
7498 request.to_proto(upstream_project_id, buffer.read(cx)),
7499 );
7500 let buffer = buffer.clone();
7501 cx.spawn(async move |weak_lsp_store, cx| {
7502 let lsp_store = weak_lsp_store.upgrade()?;
7503 let signatures = join_all(
7504 request_task
7505 .await
7506 .log_err()
7507 .flatten()
7508 .map(|response| response.payload)
7509 .unwrap_or_default()
7510 .into_iter()
7511 .map(|response| {
7512 let response = GetSignatureHelp { position }.response_from_proto(
7513 response.response,
7514 lsp_store.clone(),
7515 buffer.clone(),
7516 cx.clone(),
7517 );
7518 async move { response.await.log_err().flatten() }
7519 }),
7520 )
7521 .await
7522 .into_iter()
7523 .flatten()
7524 .collect();
7525 Some(signatures)
7526 })
7527 } else {
7528 let all_actions_task = self.request_multiple_lsp_locally(
7529 buffer,
7530 Some(position),
7531 GetSignatureHelp { position },
7532 cx,
7533 );
7534 cx.background_spawn(async move {
7535 Some(
7536 all_actions_task
7537 .await
7538 .into_iter()
7539 .flat_map(|(_, actions)| actions)
7540 .collect::<Vec<_>>(),
7541 )
7542 })
7543 }
7544 }
7545
7546 pub fn hover(
7547 &mut self,
7548 buffer: &Entity<Buffer>,
7549 position: PointUtf16,
7550 cx: &mut Context<Self>,
7551 ) -> Task<Option<Vec<Hover>>> {
7552 if let Some((client, upstream_project_id)) = self.upstream_client() {
7553 let request = GetHover { position };
7554 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7555 return Task::ready(None);
7556 }
7557 let request_task = client.request_lsp(
7558 upstream_project_id,
7559 None,
7560 LSP_REQUEST_TIMEOUT,
7561 cx.background_executor().clone(),
7562 request.to_proto(upstream_project_id, buffer.read(cx)),
7563 );
7564 let buffer = buffer.clone();
7565 cx.spawn(async move |weak_lsp_store, cx| {
7566 let lsp_store = weak_lsp_store.upgrade()?;
7567 let hovers = join_all(
7568 request_task
7569 .await
7570 .log_err()
7571 .flatten()
7572 .map(|response| response.payload)
7573 .unwrap_or_default()
7574 .into_iter()
7575 .map(|response| {
7576 let response = GetHover { position }.response_from_proto(
7577 response.response,
7578 lsp_store.clone(),
7579 buffer.clone(),
7580 cx.clone(),
7581 );
7582 async move {
7583 response
7584 .await
7585 .log_err()
7586 .flatten()
7587 .and_then(remove_empty_hover_blocks)
7588 }
7589 }),
7590 )
7591 .await
7592 .into_iter()
7593 .flatten()
7594 .collect();
7595 Some(hovers)
7596 })
7597 } else {
7598 let all_actions_task = self.request_multiple_lsp_locally(
7599 buffer,
7600 Some(position),
7601 GetHover { position },
7602 cx,
7603 );
7604 cx.background_spawn(async move {
7605 Some(
7606 all_actions_task
7607 .await
7608 .into_iter()
7609 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7610 .collect::<Vec<Hover>>(),
7611 )
7612 })
7613 }
7614 }
7615
7616 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7617 let language_registry = self.languages.clone();
7618
7619 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7620 let request = upstream_client.request(proto::GetProjectSymbols {
7621 project_id: *project_id,
7622 query: query.to_string(),
7623 });
7624 cx.foreground_executor().spawn(async move {
7625 let response = request.await?;
7626 let mut symbols = Vec::new();
7627 let core_symbols = response
7628 .symbols
7629 .into_iter()
7630 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7631 .collect::<Vec<_>>();
7632 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7633 .await;
7634 Ok(symbols)
7635 })
7636 } else if let Some(local) = self.as_local() {
7637 struct WorkspaceSymbolsResult {
7638 server_id: LanguageServerId,
7639 lsp_adapter: Arc<CachedLspAdapter>,
7640 worktree: WeakEntity<Worktree>,
7641 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7642 }
7643
7644 let mut requests = Vec::new();
7645 let mut requested_servers = BTreeSet::new();
7646 for (seed, state) in local.language_server_ids.iter() {
7647 let Some(worktree_handle) = self
7648 .worktree_store
7649 .read(cx)
7650 .worktree_for_id(seed.worktree_id, cx)
7651 else {
7652 continue;
7653 };
7654 let worktree = worktree_handle.read(cx);
7655 if !worktree.is_visible() {
7656 continue;
7657 }
7658
7659 if !requested_servers.insert(state.id) {
7660 continue;
7661 }
7662
7663 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7664 Some(LanguageServerState::Running {
7665 adapter, server, ..
7666 }) => (adapter.clone(), server),
7667
7668 _ => continue,
7669 };
7670 let supports_workspace_symbol_request =
7671 match server.capabilities().workspace_symbol_provider {
7672 Some(OneOf::Left(supported)) => supported,
7673 Some(OneOf::Right(_)) => true,
7674 None => false,
7675 };
7676 if !supports_workspace_symbol_request {
7677 continue;
7678 }
7679 let worktree_handle = worktree_handle.clone();
7680 let server_id = server.server_id();
7681 requests.push(
7682 server
7683 .request::<lsp::request::WorkspaceSymbolRequest>(
7684 lsp::WorkspaceSymbolParams {
7685 query: query.to_string(),
7686 ..Default::default()
7687 },
7688 )
7689 .map(move |response| {
7690 let lsp_symbols = response.into_response()
7691 .context("workspace symbols request")
7692 .log_err()
7693 .flatten()
7694 .map(|symbol_response| match symbol_response {
7695 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7696 flat_responses.into_iter().map(|lsp_symbol| {
7697 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7698 }).collect::<Vec<_>>()
7699 }
7700 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7701 nested_responses.into_iter().filter_map(|lsp_symbol| {
7702 let location = match lsp_symbol.location {
7703 OneOf::Left(location) => location,
7704 OneOf::Right(_) => {
7705 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7706 return None
7707 }
7708 };
7709 Some((lsp_symbol.name, lsp_symbol.kind, location))
7710 }).collect::<Vec<_>>()
7711 }
7712 }).unwrap_or_default();
7713
7714 WorkspaceSymbolsResult {
7715 server_id,
7716 lsp_adapter,
7717 worktree: worktree_handle.downgrade(),
7718 lsp_symbols,
7719 }
7720 }),
7721 );
7722 }
7723
7724 cx.spawn(async move |this, cx| {
7725 let responses = futures::future::join_all(requests).await;
7726 let this = match this.upgrade() {
7727 Some(this) => this,
7728 None => return Ok(Vec::new()),
7729 };
7730
7731 let mut symbols = Vec::new();
7732 for result in responses {
7733 let core_symbols = this.update(cx, |this, cx| {
7734 result
7735 .lsp_symbols
7736 .into_iter()
7737 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7738 let abs_path = symbol_location.uri.to_file_path().ok()?;
7739 let source_worktree = result.worktree.upgrade()?;
7740 let source_worktree_id = source_worktree.read(cx).id();
7741
7742 let path = if let Some((tree, rel_path)) =
7743 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7744 {
7745 let worktree_id = tree.read(cx).id();
7746 SymbolLocation::InProject(ProjectPath {
7747 worktree_id,
7748 path: rel_path,
7749 })
7750 } else {
7751 SymbolLocation::OutsideProject {
7752 signature: this.symbol_signature(&abs_path),
7753 abs_path: abs_path.into(),
7754 }
7755 };
7756
7757 Some(CoreSymbol {
7758 source_language_server_id: result.server_id,
7759 language_server_name: result.lsp_adapter.name.clone(),
7760 source_worktree_id,
7761 path,
7762 kind: symbol_kind,
7763 name: symbol_name,
7764 range: range_from_lsp(symbol_location.range),
7765 })
7766 })
7767 .collect()
7768 })?;
7769
7770 populate_labels_for_symbols(
7771 core_symbols,
7772 &language_registry,
7773 Some(result.lsp_adapter),
7774 &mut symbols,
7775 )
7776 .await;
7777 }
7778
7779 Ok(symbols)
7780 })
7781 } else {
7782 Task::ready(Err(anyhow!("No upstream client or local language server")))
7783 }
7784 }
7785
7786 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7787 let mut summary = DiagnosticSummary::default();
7788 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7789 summary.error_count += path_summary.error_count;
7790 summary.warning_count += path_summary.warning_count;
7791 }
7792 summary
7793 }
7794
7795 /// Returns the diagnostic summary for a specific project path.
7796 pub fn diagnostic_summary_for_path(
7797 &self,
7798 project_path: &ProjectPath,
7799 _: &App,
7800 ) -> DiagnosticSummary {
7801 if let Some(summaries) = self
7802 .diagnostic_summaries
7803 .get(&project_path.worktree_id)
7804 .and_then(|map| map.get(&project_path.path))
7805 {
7806 let (error_count, warning_count) = summaries.iter().fold(
7807 (0, 0),
7808 |(error_count, warning_count), (_language_server_id, summary)| {
7809 (
7810 error_count + summary.error_count,
7811 warning_count + summary.warning_count,
7812 )
7813 },
7814 );
7815
7816 DiagnosticSummary {
7817 error_count,
7818 warning_count,
7819 }
7820 } else {
7821 DiagnosticSummary::default()
7822 }
7823 }
7824
7825 pub fn diagnostic_summaries<'a>(
7826 &'a self,
7827 include_ignored: bool,
7828 cx: &'a App,
7829 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7830 self.worktree_store
7831 .read(cx)
7832 .visible_worktrees(cx)
7833 .filter_map(|worktree| {
7834 let worktree = worktree.read(cx);
7835 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7836 })
7837 .flat_map(move |(worktree, summaries)| {
7838 let worktree_id = worktree.id();
7839 summaries
7840 .iter()
7841 .filter(move |(path, _)| {
7842 include_ignored
7843 || worktree
7844 .entry_for_path(path.as_ref())
7845 .is_some_and(|entry| !entry.is_ignored)
7846 })
7847 .flat_map(move |(path, summaries)| {
7848 summaries.iter().map(move |(server_id, summary)| {
7849 (
7850 ProjectPath {
7851 worktree_id,
7852 path: path.clone(),
7853 },
7854 *server_id,
7855 *summary,
7856 )
7857 })
7858 })
7859 })
7860 }
7861
7862 pub fn on_buffer_edited(
7863 &mut self,
7864 buffer: Entity<Buffer>,
7865 cx: &mut Context<Self>,
7866 ) -> Option<()> {
7867 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7868 Some(
7869 self.as_local()?
7870 .language_servers_for_buffer(buffer, cx)
7871 .map(|i| i.1.clone())
7872 .collect(),
7873 )
7874 })?;
7875
7876 let buffer = buffer.read(cx);
7877 let file = File::from_dyn(buffer.file())?;
7878 let abs_path = file.as_local()?.abs_path(cx);
7879 let uri = lsp::Uri::from_file_path(&abs_path)
7880 .ok()
7881 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7882 .log_err()?;
7883 let next_snapshot = buffer.text_snapshot();
7884 for language_server in language_servers {
7885 let language_server = language_server.clone();
7886
7887 let buffer_snapshots = self
7888 .as_local_mut()?
7889 .buffer_snapshots
7890 .get_mut(&buffer.remote_id())
7891 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7892 let previous_snapshot = buffer_snapshots.last()?;
7893
7894 let build_incremental_change = || {
7895 buffer
7896 .edits_since::<Dimensions<PointUtf16, usize>>(
7897 previous_snapshot.snapshot.version(),
7898 )
7899 .map(|edit| {
7900 let edit_start = edit.new.start.0;
7901 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7902 let new_text = next_snapshot
7903 .text_for_range(edit.new.start.1..edit.new.end.1)
7904 .collect();
7905 lsp::TextDocumentContentChangeEvent {
7906 range: Some(lsp::Range::new(
7907 point_to_lsp(edit_start),
7908 point_to_lsp(edit_end),
7909 )),
7910 range_length: None,
7911 text: new_text,
7912 }
7913 })
7914 .collect()
7915 };
7916
7917 let document_sync_kind = language_server
7918 .capabilities()
7919 .text_document_sync
7920 .as_ref()
7921 .and_then(|sync| match sync {
7922 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7923 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7924 });
7925
7926 let content_changes: Vec<_> = match document_sync_kind {
7927 Some(lsp::TextDocumentSyncKind::FULL) => {
7928 vec![lsp::TextDocumentContentChangeEvent {
7929 range: None,
7930 range_length: None,
7931 text: next_snapshot.text(),
7932 }]
7933 }
7934 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7935 _ => {
7936 #[cfg(any(test, feature = "test-support"))]
7937 {
7938 build_incremental_change()
7939 }
7940
7941 #[cfg(not(any(test, feature = "test-support")))]
7942 {
7943 continue;
7944 }
7945 }
7946 };
7947
7948 let next_version = previous_snapshot.version + 1;
7949 buffer_snapshots.push(LspBufferSnapshot {
7950 version: next_version,
7951 snapshot: next_snapshot.clone(),
7952 });
7953
7954 language_server
7955 .notify::<lsp::notification::DidChangeTextDocument>(
7956 lsp::DidChangeTextDocumentParams {
7957 text_document: lsp::VersionedTextDocumentIdentifier::new(
7958 uri.clone(),
7959 next_version,
7960 ),
7961 content_changes,
7962 },
7963 )
7964 .ok();
7965 self.pull_workspace_diagnostics(language_server.server_id());
7966 }
7967
7968 None
7969 }
7970
7971 pub fn on_buffer_saved(
7972 &mut self,
7973 buffer: Entity<Buffer>,
7974 cx: &mut Context<Self>,
7975 ) -> Option<()> {
7976 let file = File::from_dyn(buffer.read(cx).file())?;
7977 let worktree_id = file.worktree_id(cx);
7978 let abs_path = file.as_local()?.abs_path(cx);
7979 let text_document = lsp::TextDocumentIdentifier {
7980 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7981 };
7982 let local = self.as_local()?;
7983
7984 for server in local.language_servers_for_worktree(worktree_id) {
7985 if let Some(include_text) = include_text(server.as_ref()) {
7986 let text = if include_text {
7987 Some(buffer.read(cx).text())
7988 } else {
7989 None
7990 };
7991 server
7992 .notify::<lsp::notification::DidSaveTextDocument>(
7993 lsp::DidSaveTextDocumentParams {
7994 text_document: text_document.clone(),
7995 text,
7996 },
7997 )
7998 .ok();
7999 }
8000 }
8001
8002 let language_servers = buffer.update(cx, |buffer, cx| {
8003 local.language_server_ids_for_buffer(buffer, cx)
8004 });
8005 for language_server_id in language_servers {
8006 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8007 }
8008
8009 None
8010 }
8011
8012 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8013 maybe!(async move {
8014 let mut refreshed_servers = HashSet::default();
8015 let servers = lsp_store
8016 .update(cx, |lsp_store, cx| {
8017 let local = lsp_store.as_local()?;
8018
8019 let servers = local
8020 .language_server_ids
8021 .iter()
8022 .filter_map(|(seed, state)| {
8023 let worktree = lsp_store
8024 .worktree_store
8025 .read(cx)
8026 .worktree_for_id(seed.worktree_id, cx);
8027 let delegate: Arc<dyn LspAdapterDelegate> =
8028 worktree.map(|worktree| {
8029 LocalLspAdapterDelegate::new(
8030 local.languages.clone(),
8031 &local.environment,
8032 cx.weak_entity(),
8033 &worktree,
8034 local.http_client.clone(),
8035 local.fs.clone(),
8036 cx,
8037 )
8038 })?;
8039 let server_id = state.id;
8040
8041 let states = local.language_servers.get(&server_id)?;
8042
8043 match states {
8044 LanguageServerState::Starting { .. } => None,
8045 LanguageServerState::Running {
8046 adapter, server, ..
8047 } => {
8048 let adapter = adapter.clone();
8049 let server = server.clone();
8050 refreshed_servers.insert(server.name());
8051 let toolchain = seed.toolchain.clone();
8052 Some(cx.spawn(async move |_, cx| {
8053 let settings =
8054 LocalLspStore::workspace_configuration_for_adapter(
8055 adapter.adapter.clone(),
8056 &delegate,
8057 toolchain,
8058 None,
8059 cx,
8060 )
8061 .await
8062 .ok()?;
8063 server
8064 .notify::<lsp::notification::DidChangeConfiguration>(
8065 lsp::DidChangeConfigurationParams { settings },
8066 )
8067 .ok()?;
8068 Some(())
8069 }))
8070 }
8071 }
8072 })
8073 .collect::<Vec<_>>();
8074
8075 Some(servers)
8076 })
8077 .ok()
8078 .flatten()?;
8079
8080 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8081 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8082 // to stop and unregister its language server wrapper.
8083 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8084 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8085 let _: Vec<Option<()>> = join_all(servers).await;
8086
8087 Some(())
8088 })
8089 .await;
8090 }
8091
8092 fn maintain_workspace_config(
8093 external_refresh_requests: watch::Receiver<()>,
8094 cx: &mut Context<Self>,
8095 ) -> Task<Result<()>> {
8096 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8097 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8098
8099 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8100 *settings_changed_tx.borrow_mut() = ();
8101 });
8102
8103 let mut joint_future =
8104 futures::stream::select(settings_changed_rx, external_refresh_requests);
8105 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8106 // - 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).
8107 // - 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.
8108 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8109 // - 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,
8110 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8111 cx.spawn(async move |this, cx| {
8112 while let Some(()) = joint_future.next().await {
8113 this.update(cx, |this, cx| {
8114 this.refresh_server_tree(cx);
8115 })
8116 .ok();
8117
8118 Self::refresh_workspace_configurations(&this, cx).await;
8119 }
8120
8121 drop(settings_observation);
8122 anyhow::Ok(())
8123 })
8124 }
8125
8126 pub fn running_language_servers_for_local_buffer<'a>(
8127 &'a self,
8128 buffer: &Buffer,
8129 cx: &mut App,
8130 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8131 let local = self.as_local();
8132 let language_server_ids = local
8133 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8134 .unwrap_or_default();
8135
8136 language_server_ids
8137 .into_iter()
8138 .filter_map(
8139 move |server_id| match local?.language_servers.get(&server_id)? {
8140 LanguageServerState::Running {
8141 adapter, server, ..
8142 } => Some((adapter, server)),
8143 _ => None,
8144 },
8145 )
8146 }
8147
8148 pub fn language_servers_for_local_buffer(
8149 &self,
8150 buffer: &Buffer,
8151 cx: &mut App,
8152 ) -> Vec<LanguageServerId> {
8153 let local = self.as_local();
8154 local
8155 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8156 .unwrap_or_default()
8157 }
8158
8159 pub fn language_server_for_local_buffer<'a>(
8160 &'a self,
8161 buffer: &'a Buffer,
8162 server_id: LanguageServerId,
8163 cx: &'a mut App,
8164 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8165 self.as_local()?
8166 .language_servers_for_buffer(buffer, cx)
8167 .find(|(_, s)| s.server_id() == server_id)
8168 }
8169
8170 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8171 self.diagnostic_summaries.remove(&id_to_remove);
8172 if let Some(local) = self.as_local_mut() {
8173 let to_remove = local.remove_worktree(id_to_remove, cx);
8174 for server in to_remove {
8175 self.language_server_statuses.remove(&server);
8176 }
8177 }
8178 }
8179
8180 pub fn shared(
8181 &mut self,
8182 project_id: u64,
8183 downstream_client: AnyProtoClient,
8184 _: &mut Context<Self>,
8185 ) {
8186 self.downstream_client = Some((downstream_client.clone(), project_id));
8187
8188 for (server_id, status) in &self.language_server_statuses {
8189 if let Some(server) = self.language_server_for_id(*server_id) {
8190 downstream_client
8191 .send(proto::StartLanguageServer {
8192 project_id,
8193 server: Some(proto::LanguageServer {
8194 id: server_id.to_proto(),
8195 name: status.name.to_string(),
8196 worktree_id: status.worktree.map(|id| id.to_proto()),
8197 }),
8198 capabilities: serde_json::to_string(&server.capabilities())
8199 .expect("serializing server LSP capabilities"),
8200 })
8201 .log_err();
8202 }
8203 }
8204 }
8205
8206 pub fn disconnected_from_host(&mut self) {
8207 self.downstream_client.take();
8208 }
8209
8210 pub fn disconnected_from_ssh_remote(&mut self) {
8211 if let LspStoreMode::Remote(RemoteLspStore {
8212 upstream_client, ..
8213 }) = &mut self.mode
8214 {
8215 upstream_client.take();
8216 }
8217 }
8218
8219 pub(crate) fn set_language_server_statuses_from_proto(
8220 &mut self,
8221 project: WeakEntity<Project>,
8222 language_servers: Vec<proto::LanguageServer>,
8223 server_capabilities: Vec<String>,
8224 cx: &mut Context<Self>,
8225 ) {
8226 let lsp_logs = cx
8227 .try_global::<GlobalLogStore>()
8228 .map(|lsp_store| lsp_store.0.clone());
8229
8230 self.language_server_statuses = language_servers
8231 .into_iter()
8232 .zip(server_capabilities)
8233 .map(|(server, server_capabilities)| {
8234 let server_id = LanguageServerId(server.id as usize);
8235 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8236 self.lsp_server_capabilities
8237 .insert(server_id, server_capabilities);
8238 }
8239
8240 let name = LanguageServerName::from_proto(server.name);
8241 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8242
8243 if let Some(lsp_logs) = &lsp_logs {
8244 lsp_logs.update(cx, |lsp_logs, cx| {
8245 lsp_logs.add_language_server(
8246 // Only remote clients get their language servers set from proto
8247 LanguageServerKind::Remote {
8248 project: project.clone(),
8249 },
8250 server_id,
8251 Some(name.clone()),
8252 worktree,
8253 None,
8254 cx,
8255 );
8256 });
8257 }
8258
8259 (
8260 server_id,
8261 LanguageServerStatus {
8262 name,
8263 pending_work: Default::default(),
8264 has_pending_diagnostic_updates: false,
8265 progress_tokens: Default::default(),
8266 worktree,
8267 binary: None,
8268 configuration: None,
8269 workspace_folders: BTreeSet::new(),
8270 },
8271 )
8272 })
8273 .collect();
8274 }
8275
8276 #[cfg(test)]
8277 pub fn update_diagnostic_entries(
8278 &mut self,
8279 server_id: LanguageServerId,
8280 abs_path: PathBuf,
8281 result_id: Option<SharedString>,
8282 version: Option<i32>,
8283 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8284 cx: &mut Context<Self>,
8285 ) -> anyhow::Result<()> {
8286 self.merge_diagnostic_entries(
8287 vec![DocumentDiagnosticsUpdate {
8288 diagnostics: DocumentDiagnostics {
8289 diagnostics,
8290 document_abs_path: abs_path,
8291 version,
8292 },
8293 result_id,
8294 server_id,
8295 disk_based_sources: Cow::Borrowed(&[]),
8296 registration_id: None,
8297 }],
8298 |_, _, _| false,
8299 cx,
8300 )?;
8301 Ok(())
8302 }
8303
8304 pub fn merge_diagnostic_entries<'a>(
8305 &mut self,
8306 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8307 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8308 cx: &mut Context<Self>,
8309 ) -> anyhow::Result<()> {
8310 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8311 let mut updated_diagnostics_paths = HashMap::default();
8312 for mut update in diagnostic_updates {
8313 let abs_path = &update.diagnostics.document_abs_path;
8314 let server_id = update.server_id;
8315 let Some((worktree, relative_path)) =
8316 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8317 else {
8318 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8319 return Ok(());
8320 };
8321
8322 let worktree_id = worktree.read(cx).id();
8323 let project_path = ProjectPath {
8324 worktree_id,
8325 path: relative_path,
8326 };
8327
8328 let document_uri = lsp::Uri::from_file_path(abs_path)
8329 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8330 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8331 let snapshot = buffer_handle.read(cx).snapshot();
8332 let buffer = buffer_handle.read(cx);
8333 let reused_diagnostics = buffer
8334 .buffer_diagnostics(Some(server_id))
8335 .iter()
8336 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8337 .map(|v| {
8338 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8339 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8340 DiagnosticEntry {
8341 range: start..end,
8342 diagnostic: v.diagnostic.clone(),
8343 }
8344 })
8345 .collect::<Vec<_>>();
8346
8347 self.as_local_mut()
8348 .context("cannot merge diagnostics on a remote LspStore")?
8349 .update_buffer_diagnostics(
8350 &buffer_handle,
8351 server_id,
8352 Some(update.registration_id),
8353 update.result_id,
8354 update.diagnostics.version,
8355 update.diagnostics.diagnostics.clone(),
8356 reused_diagnostics.clone(),
8357 cx,
8358 )?;
8359
8360 update.diagnostics.diagnostics.extend(reused_diagnostics);
8361 } else if let Some(local) = self.as_local() {
8362 let reused_diagnostics = local
8363 .diagnostics
8364 .get(&worktree_id)
8365 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8366 .and_then(|diagnostics_by_server_id| {
8367 diagnostics_by_server_id
8368 .binary_search_by_key(&server_id, |e| e.0)
8369 .ok()
8370 .map(|ix| &diagnostics_by_server_id[ix].1)
8371 })
8372 .into_iter()
8373 .flatten()
8374 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8375
8376 update
8377 .diagnostics
8378 .diagnostics
8379 .extend(reused_diagnostics.cloned());
8380 }
8381
8382 let updated = worktree.update(cx, |worktree, cx| {
8383 self.update_worktree_diagnostics(
8384 worktree.id(),
8385 server_id,
8386 project_path.path.clone(),
8387 update.diagnostics.diagnostics,
8388 cx,
8389 )
8390 })?;
8391 match updated {
8392 ControlFlow::Continue(new_summary) => {
8393 if let Some((project_id, new_summary)) = new_summary {
8394 match &mut diagnostics_summary {
8395 Some(diagnostics_summary) => {
8396 diagnostics_summary
8397 .more_summaries
8398 .push(proto::DiagnosticSummary {
8399 path: project_path.path.as_ref().to_proto(),
8400 language_server_id: server_id.0 as u64,
8401 error_count: new_summary.error_count,
8402 warning_count: new_summary.warning_count,
8403 })
8404 }
8405 None => {
8406 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8407 project_id,
8408 worktree_id: worktree_id.to_proto(),
8409 summary: Some(proto::DiagnosticSummary {
8410 path: project_path.path.as_ref().to_proto(),
8411 language_server_id: server_id.0 as u64,
8412 error_count: new_summary.error_count,
8413 warning_count: new_summary.warning_count,
8414 }),
8415 more_summaries: Vec::new(),
8416 })
8417 }
8418 }
8419 }
8420 updated_diagnostics_paths
8421 .entry(server_id)
8422 .or_insert_with(Vec::new)
8423 .push(project_path);
8424 }
8425 ControlFlow::Break(()) => {}
8426 }
8427 }
8428
8429 if let Some((diagnostics_summary, (downstream_client, _))) =
8430 diagnostics_summary.zip(self.downstream_client.as_ref())
8431 {
8432 downstream_client.send(diagnostics_summary).log_err();
8433 }
8434 for (server_id, paths) in updated_diagnostics_paths {
8435 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8436 }
8437 Ok(())
8438 }
8439
8440 fn update_worktree_diagnostics(
8441 &mut self,
8442 worktree_id: WorktreeId,
8443 server_id: LanguageServerId,
8444 path_in_worktree: Arc<RelPath>,
8445 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8446 _: &mut Context<Worktree>,
8447 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8448 let local = match &mut self.mode {
8449 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8450 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8451 };
8452
8453 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8454 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8455 let summaries_by_server_id = summaries_for_tree
8456 .entry(path_in_worktree.clone())
8457 .or_default();
8458
8459 let old_summary = summaries_by_server_id
8460 .remove(&server_id)
8461 .unwrap_or_default();
8462
8463 let new_summary = DiagnosticSummary::new(&diagnostics);
8464 if diagnostics.is_empty() {
8465 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8466 {
8467 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8468 diagnostics_by_server_id.remove(ix);
8469 }
8470 if diagnostics_by_server_id.is_empty() {
8471 diagnostics_for_tree.remove(&path_in_worktree);
8472 }
8473 }
8474 } else {
8475 summaries_by_server_id.insert(server_id, new_summary);
8476 let diagnostics_by_server_id = diagnostics_for_tree
8477 .entry(path_in_worktree.clone())
8478 .or_default();
8479 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8480 Ok(ix) => {
8481 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8482 }
8483 Err(ix) => {
8484 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8485 }
8486 }
8487 }
8488
8489 if !old_summary.is_empty() || !new_summary.is_empty() {
8490 if let Some((_, project_id)) = &self.downstream_client {
8491 Ok(ControlFlow::Continue(Some((
8492 *project_id,
8493 proto::DiagnosticSummary {
8494 path: path_in_worktree.to_proto(),
8495 language_server_id: server_id.0 as u64,
8496 error_count: new_summary.error_count as u32,
8497 warning_count: new_summary.warning_count as u32,
8498 },
8499 ))))
8500 } else {
8501 Ok(ControlFlow::Continue(None))
8502 }
8503 } else {
8504 Ok(ControlFlow::Break(()))
8505 }
8506 }
8507
8508 pub fn open_buffer_for_symbol(
8509 &mut self,
8510 symbol: &Symbol,
8511 cx: &mut Context<Self>,
8512 ) -> Task<Result<Entity<Buffer>>> {
8513 if let Some((client, project_id)) = self.upstream_client() {
8514 let request = client.request(proto::OpenBufferForSymbol {
8515 project_id,
8516 symbol: Some(Self::serialize_symbol(symbol)),
8517 });
8518 cx.spawn(async move |this, cx| {
8519 let response = request.await?;
8520 let buffer_id = BufferId::new(response.buffer_id)?;
8521 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8522 .await
8523 })
8524 } else if let Some(local) = self.as_local() {
8525 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8526 seed.worktree_id == symbol.source_worktree_id
8527 && state.id == symbol.source_language_server_id
8528 && symbol.language_server_name == seed.name
8529 });
8530 if !is_valid {
8531 return Task::ready(Err(anyhow!(
8532 "language server for worktree and language not found"
8533 )));
8534 };
8535
8536 let symbol_abs_path = match &symbol.path {
8537 SymbolLocation::InProject(project_path) => self
8538 .worktree_store
8539 .read(cx)
8540 .absolutize(&project_path, cx)
8541 .context("no such worktree"),
8542 SymbolLocation::OutsideProject {
8543 abs_path,
8544 signature: _,
8545 } => Ok(abs_path.to_path_buf()),
8546 };
8547 let symbol_abs_path = match symbol_abs_path {
8548 Ok(abs_path) => abs_path,
8549 Err(err) => return Task::ready(Err(err)),
8550 };
8551 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8552 uri
8553 } else {
8554 return Task::ready(Err(anyhow!("invalid symbol path")));
8555 };
8556
8557 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8558 } else {
8559 Task::ready(Err(anyhow!("no upstream client or local store")))
8560 }
8561 }
8562
8563 pub(crate) fn open_local_buffer_via_lsp(
8564 &mut self,
8565 abs_path: lsp::Uri,
8566 language_server_id: LanguageServerId,
8567 cx: &mut Context<Self>,
8568 ) -> Task<Result<Entity<Buffer>>> {
8569 cx.spawn(async move |lsp_store, cx| {
8570 // Escape percent-encoded string.
8571 let current_scheme = abs_path.scheme().to_owned();
8572 // Uri is immutable, so we can't modify the scheme
8573
8574 let abs_path = abs_path
8575 .to_file_path()
8576 .map_err(|()| anyhow!("can't convert URI to path"))?;
8577 let p = abs_path.clone();
8578 let yarn_worktree = lsp_store
8579 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8580 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8581 cx.spawn(async move |this, cx| {
8582 let t = this
8583 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8584 .ok()?;
8585 t.await
8586 })
8587 }),
8588 None => Task::ready(None),
8589 })?
8590 .await;
8591 let (worktree_root_target, known_relative_path) =
8592 if let Some((zip_root, relative_path)) = yarn_worktree {
8593 (zip_root, Some(relative_path))
8594 } else {
8595 (Arc::<Path>::from(abs_path.as_path()), None)
8596 };
8597 let (worktree, relative_path) = if let Some(result) =
8598 lsp_store.update(cx, |lsp_store, cx| {
8599 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8600 worktree_store.find_worktree(&worktree_root_target, cx)
8601 })
8602 })? {
8603 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8604 (result.0, relative_path)
8605 } else {
8606 let worktree = lsp_store
8607 .update(cx, |lsp_store, cx| {
8608 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8609 worktree_store.create_worktree(&worktree_root_target, false, cx)
8610 })
8611 })?
8612 .await?;
8613 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8614 lsp_store
8615 .update(cx, |lsp_store, cx| {
8616 if let Some(local) = lsp_store.as_local_mut() {
8617 local.register_language_server_for_invisible_worktree(
8618 &worktree,
8619 language_server_id,
8620 cx,
8621 )
8622 }
8623 })
8624 .ok();
8625 }
8626 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8627 let relative_path = if let Some(known_path) = known_relative_path {
8628 known_path
8629 } else {
8630 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8631 .into_arc()
8632 };
8633 (worktree, relative_path)
8634 };
8635 let project_path = ProjectPath {
8636 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8637 path: relative_path,
8638 };
8639 lsp_store
8640 .update(cx, |lsp_store, cx| {
8641 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8642 buffer_store.open_buffer(project_path, cx)
8643 })
8644 })?
8645 .await
8646 })
8647 }
8648
8649 fn request_multiple_lsp_locally<P, R>(
8650 &mut self,
8651 buffer: &Entity<Buffer>,
8652 position: Option<P>,
8653 request: R,
8654 cx: &mut Context<Self>,
8655 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8656 where
8657 P: ToOffset,
8658 R: LspCommand + Clone,
8659 <R::LspRequest as lsp::request::Request>::Result: Send,
8660 <R::LspRequest as lsp::request::Request>::Params: Send,
8661 {
8662 let Some(local) = self.as_local() else {
8663 return Task::ready(Vec::new());
8664 };
8665
8666 let snapshot = buffer.read(cx).snapshot();
8667 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8668
8669 let server_ids = buffer.update(cx, |buffer, cx| {
8670 local
8671 .language_servers_for_buffer(buffer, cx)
8672 .filter(|(adapter, _)| {
8673 scope
8674 .as_ref()
8675 .map(|scope| scope.language_allowed(&adapter.name))
8676 .unwrap_or(true)
8677 })
8678 .map(|(_, server)| server.server_id())
8679 .filter(|server_id| {
8680 self.as_local().is_none_or(|local| {
8681 local
8682 .buffers_opened_in_servers
8683 .get(&snapshot.remote_id())
8684 .is_some_and(|servers| servers.contains(server_id))
8685 })
8686 })
8687 .collect::<Vec<_>>()
8688 });
8689
8690 let mut response_results = server_ids
8691 .into_iter()
8692 .map(|server_id| {
8693 let task = self.request_lsp(
8694 buffer.clone(),
8695 LanguageServerToQuery::Other(server_id),
8696 request.clone(),
8697 cx,
8698 );
8699 async move { (server_id, task.await) }
8700 })
8701 .collect::<FuturesUnordered<_>>();
8702
8703 cx.background_spawn(async move {
8704 let mut responses = Vec::with_capacity(response_results.len());
8705 while let Some((server_id, response_result)) = response_results.next().await {
8706 match response_result {
8707 Ok(response) => responses.push((server_id, response)),
8708 // rust-analyzer likes to error with this when its still loading up
8709 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8710 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8711 }
8712 }
8713 responses
8714 })
8715 }
8716
8717 async fn handle_lsp_get_completions(
8718 this: Entity<Self>,
8719 envelope: TypedEnvelope<proto::GetCompletions>,
8720 mut cx: AsyncApp,
8721 ) -> Result<proto::GetCompletionsResponse> {
8722 let sender_id = envelope.original_sender_id().unwrap_or_default();
8723
8724 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8725 let buffer_handle = this.update(&mut cx, |this, cx| {
8726 this.buffer_store.read(cx).get_existing(buffer_id)
8727 })??;
8728 let request = GetCompletions::from_proto(
8729 envelope.payload,
8730 this.clone(),
8731 buffer_handle.clone(),
8732 cx.clone(),
8733 )
8734 .await?;
8735
8736 let server_to_query = match request.server_id {
8737 Some(server_id) => LanguageServerToQuery::Other(server_id),
8738 None => LanguageServerToQuery::FirstCapable,
8739 };
8740
8741 let response = this
8742 .update(&mut cx, |this, cx| {
8743 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8744 })?
8745 .await?;
8746 this.update(&mut cx, |this, cx| {
8747 Ok(GetCompletions::response_to_proto(
8748 response,
8749 this,
8750 sender_id,
8751 &buffer_handle.read(cx).version(),
8752 cx,
8753 ))
8754 })?
8755 }
8756
8757 async fn handle_lsp_command<T: LspCommand>(
8758 this: Entity<Self>,
8759 envelope: TypedEnvelope<T::ProtoRequest>,
8760 mut cx: AsyncApp,
8761 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8762 where
8763 <T::LspRequest as lsp::request::Request>::Params: Send,
8764 <T::LspRequest as lsp::request::Request>::Result: Send,
8765 {
8766 let sender_id = envelope.original_sender_id().unwrap_or_default();
8767 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8768 let buffer_handle = this.update(&mut cx, |this, cx| {
8769 this.buffer_store.read(cx).get_existing(buffer_id)
8770 })??;
8771 let request = T::from_proto(
8772 envelope.payload,
8773 this.clone(),
8774 buffer_handle.clone(),
8775 cx.clone(),
8776 )
8777 .await?;
8778 let response = this
8779 .update(&mut cx, |this, cx| {
8780 this.request_lsp(
8781 buffer_handle.clone(),
8782 LanguageServerToQuery::FirstCapable,
8783 request,
8784 cx,
8785 )
8786 })?
8787 .await?;
8788 this.update(&mut cx, |this, cx| {
8789 Ok(T::response_to_proto(
8790 response,
8791 this,
8792 sender_id,
8793 &buffer_handle.read(cx).version(),
8794 cx,
8795 ))
8796 })?
8797 }
8798
8799 async fn handle_lsp_query(
8800 lsp_store: Entity<Self>,
8801 envelope: TypedEnvelope<proto::LspQuery>,
8802 mut cx: AsyncApp,
8803 ) -> Result<proto::Ack> {
8804 use proto::lsp_query::Request;
8805 let sender_id = envelope.original_sender_id().unwrap_or_default();
8806 let lsp_query = envelope.payload;
8807 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8808 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8809 match lsp_query.request.context("invalid LSP query request")? {
8810 Request::GetReferences(get_references) => {
8811 let position = get_references.position.clone().and_then(deserialize_anchor);
8812 Self::query_lsp_locally::<GetReferences>(
8813 lsp_store,
8814 server_id,
8815 sender_id,
8816 lsp_request_id,
8817 get_references,
8818 position,
8819 &mut cx,
8820 )
8821 .await?;
8822 }
8823 Request::GetDocumentColor(get_document_color) => {
8824 Self::query_lsp_locally::<GetDocumentColor>(
8825 lsp_store,
8826 server_id,
8827 sender_id,
8828 lsp_request_id,
8829 get_document_color,
8830 None,
8831 &mut cx,
8832 )
8833 .await?;
8834 }
8835 Request::GetHover(get_hover) => {
8836 let position = get_hover.position.clone().and_then(deserialize_anchor);
8837 Self::query_lsp_locally::<GetHover>(
8838 lsp_store,
8839 server_id,
8840 sender_id,
8841 lsp_request_id,
8842 get_hover,
8843 position,
8844 &mut cx,
8845 )
8846 .await?;
8847 }
8848 Request::GetCodeActions(get_code_actions) => {
8849 Self::query_lsp_locally::<GetCodeActions>(
8850 lsp_store,
8851 server_id,
8852 sender_id,
8853 lsp_request_id,
8854 get_code_actions,
8855 None,
8856 &mut cx,
8857 )
8858 .await?;
8859 }
8860 Request::GetSignatureHelp(get_signature_help) => {
8861 let position = get_signature_help
8862 .position
8863 .clone()
8864 .and_then(deserialize_anchor);
8865 Self::query_lsp_locally::<GetSignatureHelp>(
8866 lsp_store,
8867 server_id,
8868 sender_id,
8869 lsp_request_id,
8870 get_signature_help,
8871 position,
8872 &mut cx,
8873 )
8874 .await?;
8875 }
8876 Request::GetCodeLens(get_code_lens) => {
8877 Self::query_lsp_locally::<GetCodeLens>(
8878 lsp_store,
8879 server_id,
8880 sender_id,
8881 lsp_request_id,
8882 get_code_lens,
8883 None,
8884 &mut cx,
8885 )
8886 .await?;
8887 }
8888 Request::GetDefinition(get_definition) => {
8889 let position = get_definition.position.clone().and_then(deserialize_anchor);
8890 Self::query_lsp_locally::<GetDefinitions>(
8891 lsp_store,
8892 server_id,
8893 sender_id,
8894 lsp_request_id,
8895 get_definition,
8896 position,
8897 &mut cx,
8898 )
8899 .await?;
8900 }
8901 Request::GetDeclaration(get_declaration) => {
8902 let position = get_declaration
8903 .position
8904 .clone()
8905 .and_then(deserialize_anchor);
8906 Self::query_lsp_locally::<GetDeclarations>(
8907 lsp_store,
8908 server_id,
8909 sender_id,
8910 lsp_request_id,
8911 get_declaration,
8912 position,
8913 &mut cx,
8914 )
8915 .await?;
8916 }
8917 Request::GetTypeDefinition(get_type_definition) => {
8918 let position = get_type_definition
8919 .position
8920 .clone()
8921 .and_then(deserialize_anchor);
8922 Self::query_lsp_locally::<GetTypeDefinitions>(
8923 lsp_store,
8924 server_id,
8925 sender_id,
8926 lsp_request_id,
8927 get_type_definition,
8928 position,
8929 &mut cx,
8930 )
8931 .await?;
8932 }
8933 Request::GetImplementation(get_implementation) => {
8934 let position = get_implementation
8935 .position
8936 .clone()
8937 .and_then(deserialize_anchor);
8938 Self::query_lsp_locally::<GetImplementations>(
8939 lsp_store,
8940 server_id,
8941 sender_id,
8942 lsp_request_id,
8943 get_implementation,
8944 position,
8945 &mut cx,
8946 )
8947 .await?;
8948 }
8949 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8950 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8951 let version = deserialize_version(get_document_diagnostics.buffer_version());
8952 let buffer = lsp_store.update(&mut cx, |this, cx| {
8953 this.buffer_store.read(cx).get_existing(buffer_id)
8954 })??;
8955 buffer
8956 .update(&mut cx, |buffer, _| {
8957 buffer.wait_for_version(version.clone())
8958 })?
8959 .await?;
8960 lsp_store.update(&mut cx, |lsp_store, cx| {
8961 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8962 let key = LspKey {
8963 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8964 server_queried: server_id,
8965 };
8966 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8967 ) {
8968 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8969 lsp_requests.clear();
8970 };
8971 }
8972
8973 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8974 existing_queries.insert(
8975 lsp_request_id,
8976 cx.spawn(async move |lsp_store, cx| {
8977 let diagnostics_pull = lsp_store
8978 .update(cx, |lsp_store, cx| {
8979 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8980 })
8981 .ok();
8982 if let Some(diagnostics_pull) = diagnostics_pull {
8983 match diagnostics_pull.await {
8984 Ok(()) => {}
8985 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8986 };
8987 }
8988 }),
8989 );
8990 })?;
8991 }
8992 Request::InlayHints(inlay_hints) => {
8993 let query_start = inlay_hints
8994 .start
8995 .clone()
8996 .and_then(deserialize_anchor)
8997 .context("invalid inlay hints range start")?;
8998 let query_end = inlay_hints
8999 .end
9000 .clone()
9001 .and_then(deserialize_anchor)
9002 .context("invalid inlay hints range end")?;
9003 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9004 &lsp_store,
9005 server_id,
9006 lsp_request_id,
9007 &inlay_hints,
9008 query_start..query_end,
9009 &mut cx,
9010 )
9011 .await
9012 .context("preparing inlay hints request")?;
9013 Self::query_lsp_locally::<InlayHints>(
9014 lsp_store,
9015 server_id,
9016 sender_id,
9017 lsp_request_id,
9018 inlay_hints,
9019 None,
9020 &mut cx,
9021 )
9022 .await
9023 .context("querying for inlay hints")?
9024 }
9025 }
9026 Ok(proto::Ack {})
9027 }
9028
9029 async fn handle_lsp_query_response(
9030 lsp_store: Entity<Self>,
9031 envelope: TypedEnvelope<proto::LspQueryResponse>,
9032 cx: AsyncApp,
9033 ) -> Result<()> {
9034 lsp_store.read_with(&cx, |lsp_store, _| {
9035 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9036 upstream_client.handle_lsp_response(envelope.clone());
9037 }
9038 })?;
9039 Ok(())
9040 }
9041
9042 async fn handle_apply_code_action(
9043 this: Entity<Self>,
9044 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9045 mut cx: AsyncApp,
9046 ) -> Result<proto::ApplyCodeActionResponse> {
9047 let sender_id = envelope.original_sender_id().unwrap_or_default();
9048 let action =
9049 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9050 let apply_code_action = this.update(&mut cx, |this, cx| {
9051 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9052 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9053 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9054 })??;
9055
9056 let project_transaction = apply_code_action.await?;
9057 let project_transaction = this.update(&mut cx, |this, cx| {
9058 this.buffer_store.update(cx, |buffer_store, cx| {
9059 buffer_store.serialize_project_transaction_for_peer(
9060 project_transaction,
9061 sender_id,
9062 cx,
9063 )
9064 })
9065 })?;
9066 Ok(proto::ApplyCodeActionResponse {
9067 transaction: Some(project_transaction),
9068 })
9069 }
9070
9071 async fn handle_register_buffer_with_language_servers(
9072 this: Entity<Self>,
9073 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9074 mut cx: AsyncApp,
9075 ) -> Result<proto::Ack> {
9076 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9077 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9078 this.update(&mut cx, |this, cx| {
9079 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9080 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9081 project_id: upstream_project_id,
9082 buffer_id: buffer_id.to_proto(),
9083 only_servers: envelope.payload.only_servers,
9084 });
9085 }
9086
9087 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9088 anyhow::bail!("buffer is not open");
9089 };
9090
9091 let handle = this.register_buffer_with_language_servers(
9092 &buffer,
9093 envelope
9094 .payload
9095 .only_servers
9096 .into_iter()
9097 .filter_map(|selector| {
9098 Some(match selector.selector? {
9099 proto::language_server_selector::Selector::ServerId(server_id) => {
9100 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9101 }
9102 proto::language_server_selector::Selector::Name(name) => {
9103 LanguageServerSelector::Name(LanguageServerName(
9104 SharedString::from(name),
9105 ))
9106 }
9107 })
9108 })
9109 .collect(),
9110 false,
9111 cx,
9112 );
9113 this.buffer_store().update(cx, |buffer_store, _| {
9114 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9115 });
9116
9117 Ok(())
9118 })??;
9119 Ok(proto::Ack {})
9120 }
9121
9122 async fn handle_rename_project_entry(
9123 this: Entity<Self>,
9124 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9125 mut cx: AsyncApp,
9126 ) -> Result<proto::ProjectEntryResponse> {
9127 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9128 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9129 let new_path =
9130 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9131
9132 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9133 .update(&mut cx, |this, cx| {
9134 let (worktree, entry) = this
9135 .worktree_store
9136 .read(cx)
9137 .worktree_and_entry_for_id(entry_id, cx)?;
9138 let new_worktree = this
9139 .worktree_store
9140 .read(cx)
9141 .worktree_for_id(new_worktree_id, cx)?;
9142 Some((
9143 this.worktree_store.clone(),
9144 worktree,
9145 new_worktree,
9146 entry.clone(),
9147 ))
9148 })?
9149 .context("worktree not found")?;
9150 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9151 (worktree.absolutize(&old_entry.path), worktree.id())
9152 })?;
9153 let new_abs_path =
9154 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9155
9156 let _transaction = Self::will_rename_entry(
9157 this.downgrade(),
9158 old_worktree_id,
9159 &old_abs_path,
9160 &new_abs_path,
9161 old_entry.is_dir(),
9162 cx.clone(),
9163 )
9164 .await;
9165 let response = WorktreeStore::handle_rename_project_entry(
9166 worktree_store,
9167 envelope.payload,
9168 cx.clone(),
9169 )
9170 .await;
9171 this.read_with(&cx, |this, _| {
9172 this.did_rename_entry(
9173 old_worktree_id,
9174 &old_abs_path,
9175 &new_abs_path,
9176 old_entry.is_dir(),
9177 );
9178 })
9179 .ok();
9180 response
9181 }
9182
9183 async fn handle_update_diagnostic_summary(
9184 this: Entity<Self>,
9185 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9186 mut cx: AsyncApp,
9187 ) -> Result<()> {
9188 this.update(&mut cx, |lsp_store, cx| {
9189 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9190 let mut updated_diagnostics_paths = HashMap::default();
9191 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9192 for message_summary in envelope
9193 .payload
9194 .summary
9195 .into_iter()
9196 .chain(envelope.payload.more_summaries)
9197 {
9198 let project_path = ProjectPath {
9199 worktree_id,
9200 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9201 };
9202 let path = project_path.path.clone();
9203 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9204 let summary = DiagnosticSummary {
9205 error_count: message_summary.error_count as usize,
9206 warning_count: message_summary.warning_count as usize,
9207 };
9208
9209 if summary.is_empty() {
9210 if let Some(worktree_summaries) =
9211 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9212 && let Some(summaries) = worktree_summaries.get_mut(&path)
9213 {
9214 summaries.remove(&server_id);
9215 if summaries.is_empty() {
9216 worktree_summaries.remove(&path);
9217 }
9218 }
9219 } else {
9220 lsp_store
9221 .diagnostic_summaries
9222 .entry(worktree_id)
9223 .or_default()
9224 .entry(path)
9225 .or_default()
9226 .insert(server_id, summary);
9227 }
9228
9229 if let Some((_, project_id)) = &lsp_store.downstream_client {
9230 match &mut diagnostics_summary {
9231 Some(diagnostics_summary) => {
9232 diagnostics_summary
9233 .more_summaries
9234 .push(proto::DiagnosticSummary {
9235 path: project_path.path.as_ref().to_proto(),
9236 language_server_id: server_id.0 as u64,
9237 error_count: summary.error_count as u32,
9238 warning_count: summary.warning_count as u32,
9239 })
9240 }
9241 None => {
9242 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9243 project_id: *project_id,
9244 worktree_id: worktree_id.to_proto(),
9245 summary: Some(proto::DiagnosticSummary {
9246 path: project_path.path.as_ref().to_proto(),
9247 language_server_id: server_id.0 as u64,
9248 error_count: summary.error_count as u32,
9249 warning_count: summary.warning_count as u32,
9250 }),
9251 more_summaries: Vec::new(),
9252 })
9253 }
9254 }
9255 }
9256 updated_diagnostics_paths
9257 .entry(server_id)
9258 .or_insert_with(Vec::new)
9259 .push(project_path);
9260 }
9261
9262 if let Some((diagnostics_summary, (downstream_client, _))) =
9263 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9264 {
9265 downstream_client.send(diagnostics_summary).log_err();
9266 }
9267 for (server_id, paths) in updated_diagnostics_paths {
9268 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9269 }
9270 Ok(())
9271 })?
9272 }
9273
9274 async fn handle_start_language_server(
9275 lsp_store: Entity<Self>,
9276 envelope: TypedEnvelope<proto::StartLanguageServer>,
9277 mut cx: AsyncApp,
9278 ) -> Result<()> {
9279 let server = envelope.payload.server.context("invalid server")?;
9280 let server_capabilities =
9281 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9282 .with_context(|| {
9283 format!(
9284 "incorrect server capabilities {}",
9285 envelope.payload.capabilities
9286 )
9287 })?;
9288 lsp_store.update(&mut cx, |lsp_store, cx| {
9289 let server_id = LanguageServerId(server.id as usize);
9290 let server_name = LanguageServerName::from_proto(server.name.clone());
9291 lsp_store
9292 .lsp_server_capabilities
9293 .insert(server_id, server_capabilities);
9294 lsp_store.language_server_statuses.insert(
9295 server_id,
9296 LanguageServerStatus {
9297 name: server_name.clone(),
9298 pending_work: Default::default(),
9299 has_pending_diagnostic_updates: false,
9300 progress_tokens: Default::default(),
9301 worktree: server.worktree_id.map(WorktreeId::from_proto),
9302 binary: None,
9303 configuration: None,
9304 workspace_folders: BTreeSet::new(),
9305 },
9306 );
9307 cx.emit(LspStoreEvent::LanguageServerAdded(
9308 server_id,
9309 server_name,
9310 server.worktree_id.map(WorktreeId::from_proto),
9311 ));
9312 cx.notify();
9313 })?;
9314 Ok(())
9315 }
9316
9317 async fn handle_update_language_server(
9318 lsp_store: Entity<Self>,
9319 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9320 mut cx: AsyncApp,
9321 ) -> Result<()> {
9322 lsp_store.update(&mut cx, |lsp_store, cx| {
9323 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9324
9325 match envelope.payload.variant.context("invalid variant")? {
9326 proto::update_language_server::Variant::WorkStart(payload) => {
9327 lsp_store.on_lsp_work_start(
9328 language_server_id,
9329 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9330 .context("invalid progress token value")?,
9331 LanguageServerProgress {
9332 title: payload.title,
9333 is_disk_based_diagnostics_progress: false,
9334 is_cancellable: payload.is_cancellable.unwrap_or(false),
9335 message: payload.message,
9336 percentage: payload.percentage.map(|p| p as usize),
9337 last_update_at: cx.background_executor().now(),
9338 },
9339 cx,
9340 );
9341 }
9342 proto::update_language_server::Variant::WorkProgress(payload) => {
9343 lsp_store.on_lsp_work_progress(
9344 language_server_id,
9345 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9346 .context("invalid progress token value")?,
9347 LanguageServerProgress {
9348 title: None,
9349 is_disk_based_diagnostics_progress: false,
9350 is_cancellable: payload.is_cancellable.unwrap_or(false),
9351 message: payload.message,
9352 percentage: payload.percentage.map(|p| p as usize),
9353 last_update_at: cx.background_executor().now(),
9354 },
9355 cx,
9356 );
9357 }
9358
9359 proto::update_language_server::Variant::WorkEnd(payload) => {
9360 lsp_store.on_lsp_work_end(
9361 language_server_id,
9362 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9363 .context("invalid progress token value")?,
9364 cx,
9365 );
9366 }
9367
9368 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9369 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9370 }
9371
9372 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9373 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9374 }
9375
9376 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9377 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9378 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9379 cx.emit(LspStoreEvent::LanguageServerUpdate {
9380 language_server_id,
9381 name: envelope
9382 .payload
9383 .server_name
9384 .map(SharedString::new)
9385 .map(LanguageServerName),
9386 message: non_lsp,
9387 });
9388 }
9389 }
9390
9391 Ok(())
9392 })?
9393 }
9394
9395 async fn handle_language_server_log(
9396 this: Entity<Self>,
9397 envelope: TypedEnvelope<proto::LanguageServerLog>,
9398 mut cx: AsyncApp,
9399 ) -> Result<()> {
9400 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9401 let log_type = envelope
9402 .payload
9403 .log_type
9404 .map(LanguageServerLogType::from_proto)
9405 .context("invalid language server log type")?;
9406
9407 let message = envelope.payload.message;
9408
9409 this.update(&mut cx, |_, cx| {
9410 cx.emit(LspStoreEvent::LanguageServerLog(
9411 language_server_id,
9412 log_type,
9413 message,
9414 ));
9415 })
9416 }
9417
9418 async fn handle_lsp_ext_cancel_flycheck(
9419 lsp_store: Entity<Self>,
9420 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9421 cx: AsyncApp,
9422 ) -> Result<proto::Ack> {
9423 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9424 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9425 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9426 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9427 } else {
9428 None
9429 }
9430 })?;
9431 if let Some(task) = task {
9432 task.context("handling lsp ext cancel flycheck")?;
9433 }
9434
9435 Ok(proto::Ack {})
9436 }
9437
9438 async fn handle_lsp_ext_run_flycheck(
9439 lsp_store: Entity<Self>,
9440 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9441 mut cx: AsyncApp,
9442 ) -> Result<proto::Ack> {
9443 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9444 lsp_store.update(&mut cx, |lsp_store, cx| {
9445 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9446 let text_document = if envelope.payload.current_file_only {
9447 let buffer_id = envelope
9448 .payload
9449 .buffer_id
9450 .map(|id| BufferId::new(id))
9451 .transpose()?;
9452 buffer_id
9453 .and_then(|buffer_id| {
9454 lsp_store
9455 .buffer_store()
9456 .read(cx)
9457 .get(buffer_id)
9458 .and_then(|buffer| {
9459 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9460 })
9461 .map(|path| make_text_document_identifier(&path))
9462 })
9463 .transpose()?
9464 } else {
9465 None
9466 };
9467 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9468 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9469 )?;
9470 }
9471 anyhow::Ok(())
9472 })??;
9473
9474 Ok(proto::Ack {})
9475 }
9476
9477 async fn handle_lsp_ext_clear_flycheck(
9478 lsp_store: Entity<Self>,
9479 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9480 cx: AsyncApp,
9481 ) -> Result<proto::Ack> {
9482 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9483 lsp_store
9484 .read_with(&cx, |lsp_store, _| {
9485 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9486 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9487 } else {
9488 None
9489 }
9490 })
9491 .context("handling lsp ext clear flycheck")?;
9492
9493 Ok(proto::Ack {})
9494 }
9495
9496 pub fn disk_based_diagnostics_started(
9497 &mut self,
9498 language_server_id: LanguageServerId,
9499 cx: &mut Context<Self>,
9500 ) {
9501 if let Some(language_server_status) =
9502 self.language_server_statuses.get_mut(&language_server_id)
9503 {
9504 language_server_status.has_pending_diagnostic_updates = true;
9505 }
9506
9507 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9508 cx.emit(LspStoreEvent::LanguageServerUpdate {
9509 language_server_id,
9510 name: self
9511 .language_server_adapter_for_id(language_server_id)
9512 .map(|adapter| adapter.name()),
9513 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9514 Default::default(),
9515 ),
9516 })
9517 }
9518
9519 pub fn disk_based_diagnostics_finished(
9520 &mut self,
9521 language_server_id: LanguageServerId,
9522 cx: &mut Context<Self>,
9523 ) {
9524 if let Some(language_server_status) =
9525 self.language_server_statuses.get_mut(&language_server_id)
9526 {
9527 language_server_status.has_pending_diagnostic_updates = false;
9528 }
9529
9530 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9531 cx.emit(LspStoreEvent::LanguageServerUpdate {
9532 language_server_id,
9533 name: self
9534 .language_server_adapter_for_id(language_server_id)
9535 .map(|adapter| adapter.name()),
9536 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9537 Default::default(),
9538 ),
9539 })
9540 }
9541
9542 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9543 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9544 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9545 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9546 // the language server might take some time to publish diagnostics.
9547 fn simulate_disk_based_diagnostics_events_if_needed(
9548 &mut self,
9549 language_server_id: LanguageServerId,
9550 cx: &mut Context<Self>,
9551 ) {
9552 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9553
9554 let Some(LanguageServerState::Running {
9555 simulate_disk_based_diagnostics_completion,
9556 adapter,
9557 ..
9558 }) = self
9559 .as_local_mut()
9560 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9561 else {
9562 return;
9563 };
9564
9565 if adapter.disk_based_diagnostics_progress_token.is_some() {
9566 return;
9567 }
9568
9569 let prev_task =
9570 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9571 cx.background_executor()
9572 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9573 .await;
9574
9575 this.update(cx, |this, cx| {
9576 this.disk_based_diagnostics_finished(language_server_id, cx);
9577
9578 if let Some(LanguageServerState::Running {
9579 simulate_disk_based_diagnostics_completion,
9580 ..
9581 }) = this.as_local_mut().and_then(|local_store| {
9582 local_store.language_servers.get_mut(&language_server_id)
9583 }) {
9584 *simulate_disk_based_diagnostics_completion = None;
9585 }
9586 })
9587 .ok();
9588 }));
9589
9590 if prev_task.is_none() {
9591 self.disk_based_diagnostics_started(language_server_id, cx);
9592 }
9593 }
9594
9595 pub fn language_server_statuses(
9596 &self,
9597 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9598 self.language_server_statuses
9599 .iter()
9600 .map(|(key, value)| (*key, value))
9601 }
9602
9603 pub(super) fn did_rename_entry(
9604 &self,
9605 worktree_id: WorktreeId,
9606 old_path: &Path,
9607 new_path: &Path,
9608 is_dir: bool,
9609 ) {
9610 maybe!({
9611 let local_store = self.as_local()?;
9612
9613 let old_uri = lsp::Uri::from_file_path(old_path)
9614 .ok()
9615 .map(|uri| uri.to_string())?;
9616 let new_uri = lsp::Uri::from_file_path(new_path)
9617 .ok()
9618 .map(|uri| uri.to_string())?;
9619
9620 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9621 let Some(filter) = local_store
9622 .language_server_paths_watched_for_rename
9623 .get(&language_server.server_id())
9624 else {
9625 continue;
9626 };
9627
9628 if filter.should_send_did_rename(&old_uri, is_dir) {
9629 language_server
9630 .notify::<DidRenameFiles>(RenameFilesParams {
9631 files: vec![FileRename {
9632 old_uri: old_uri.clone(),
9633 new_uri: new_uri.clone(),
9634 }],
9635 })
9636 .ok();
9637 }
9638 }
9639 Some(())
9640 });
9641 }
9642
9643 pub(super) fn will_rename_entry(
9644 this: WeakEntity<Self>,
9645 worktree_id: WorktreeId,
9646 old_path: &Path,
9647 new_path: &Path,
9648 is_dir: bool,
9649 cx: AsyncApp,
9650 ) -> Task<ProjectTransaction> {
9651 let old_uri = lsp::Uri::from_file_path(old_path)
9652 .ok()
9653 .map(|uri| uri.to_string());
9654 let new_uri = lsp::Uri::from_file_path(new_path)
9655 .ok()
9656 .map(|uri| uri.to_string());
9657 cx.spawn(async move |cx| {
9658 let mut tasks = vec![];
9659 this.update(cx, |this, cx| {
9660 let local_store = this.as_local()?;
9661 let old_uri = old_uri?;
9662 let new_uri = new_uri?;
9663 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9664 let Some(filter) = local_store
9665 .language_server_paths_watched_for_rename
9666 .get(&language_server.server_id())
9667 else {
9668 continue;
9669 };
9670
9671 if filter.should_send_will_rename(&old_uri, is_dir) {
9672 let apply_edit = cx.spawn({
9673 let old_uri = old_uri.clone();
9674 let new_uri = new_uri.clone();
9675 let language_server = language_server.clone();
9676 async move |this, cx| {
9677 let edit = language_server
9678 .request::<WillRenameFiles>(RenameFilesParams {
9679 files: vec![FileRename { old_uri, new_uri }],
9680 })
9681 .await
9682 .into_response()
9683 .context("will rename files")
9684 .log_err()
9685 .flatten()?;
9686
9687 let transaction = LocalLspStore::deserialize_workspace_edit(
9688 this.upgrade()?,
9689 edit,
9690 false,
9691 language_server.clone(),
9692 cx,
9693 )
9694 .await
9695 .ok()?;
9696 Some(transaction)
9697 }
9698 });
9699 tasks.push(apply_edit);
9700 }
9701 }
9702 Some(())
9703 })
9704 .ok()
9705 .flatten();
9706 let mut merged_transaction = ProjectTransaction::default();
9707 for task in tasks {
9708 // Await on tasks sequentially so that the order of application of edits is deterministic
9709 // (at least with regards to the order of registration of language servers)
9710 if let Some(transaction) = task.await {
9711 for (buffer, buffer_transaction) in transaction.0 {
9712 merged_transaction.0.insert(buffer, buffer_transaction);
9713 }
9714 }
9715 }
9716 merged_transaction
9717 })
9718 }
9719
9720 fn lsp_notify_abs_paths_changed(
9721 &mut self,
9722 server_id: LanguageServerId,
9723 changes: Vec<PathEvent>,
9724 ) {
9725 maybe!({
9726 let server = self.language_server_for_id(server_id)?;
9727 let changes = changes
9728 .into_iter()
9729 .filter_map(|event| {
9730 let typ = match event.kind? {
9731 PathEventKind::Created => lsp::FileChangeType::CREATED,
9732 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9733 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9734 };
9735 Some(lsp::FileEvent {
9736 uri: file_path_to_lsp_url(&event.path).log_err()?,
9737 typ,
9738 })
9739 })
9740 .collect::<Vec<_>>();
9741 if !changes.is_empty() {
9742 server
9743 .notify::<lsp::notification::DidChangeWatchedFiles>(
9744 lsp::DidChangeWatchedFilesParams { changes },
9745 )
9746 .ok();
9747 }
9748 Some(())
9749 });
9750 }
9751
9752 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9753 self.as_local()?.language_server_for_id(id)
9754 }
9755
9756 fn on_lsp_progress(
9757 &mut self,
9758 progress_params: lsp::ProgressParams,
9759 language_server_id: LanguageServerId,
9760 disk_based_diagnostics_progress_token: Option<String>,
9761 cx: &mut Context<Self>,
9762 ) {
9763 match progress_params.value {
9764 lsp::ProgressParamsValue::WorkDone(progress) => {
9765 self.handle_work_done_progress(
9766 progress,
9767 language_server_id,
9768 disk_based_diagnostics_progress_token,
9769 ProgressToken::from_lsp(progress_params.token),
9770 cx,
9771 );
9772 }
9773 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9774 let registration_id = match progress_params.token {
9775 lsp::NumberOrString::Number(_) => None,
9776 lsp::NumberOrString::String(token) => token
9777 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9778 .map(|(_, id)| id.to_owned()),
9779 };
9780 if let Some(LanguageServerState::Running {
9781 workspace_diagnostics_refresh_tasks,
9782 ..
9783 }) = self
9784 .as_local_mut()
9785 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9786 && let Some(workspace_diagnostics) =
9787 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9788 {
9789 workspace_diagnostics.progress_tx.try_send(()).ok();
9790 self.apply_workspace_diagnostic_report(
9791 language_server_id,
9792 report,
9793 registration_id.map(SharedString::from),
9794 cx,
9795 )
9796 }
9797 }
9798 }
9799 }
9800
9801 fn handle_work_done_progress(
9802 &mut self,
9803 progress: lsp::WorkDoneProgress,
9804 language_server_id: LanguageServerId,
9805 disk_based_diagnostics_progress_token: Option<String>,
9806 token: ProgressToken,
9807 cx: &mut Context<Self>,
9808 ) {
9809 let language_server_status =
9810 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9811 status
9812 } else {
9813 return;
9814 };
9815
9816 if !language_server_status.progress_tokens.contains(&token) {
9817 return;
9818 }
9819
9820 let is_disk_based_diagnostics_progress =
9821 if let (Some(disk_based_token), ProgressToken::String(token)) =
9822 (&disk_based_diagnostics_progress_token, &token)
9823 {
9824 token.starts_with(disk_based_token)
9825 } else {
9826 false
9827 };
9828
9829 match progress {
9830 lsp::WorkDoneProgress::Begin(report) => {
9831 if is_disk_based_diagnostics_progress {
9832 self.disk_based_diagnostics_started(language_server_id, cx);
9833 }
9834 self.on_lsp_work_start(
9835 language_server_id,
9836 token.clone(),
9837 LanguageServerProgress {
9838 title: Some(report.title),
9839 is_disk_based_diagnostics_progress,
9840 is_cancellable: report.cancellable.unwrap_or(false),
9841 message: report.message.clone(),
9842 percentage: report.percentage.map(|p| p as usize),
9843 last_update_at: cx.background_executor().now(),
9844 },
9845 cx,
9846 );
9847 }
9848 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9849 language_server_id,
9850 token,
9851 LanguageServerProgress {
9852 title: None,
9853 is_disk_based_diagnostics_progress,
9854 is_cancellable: report.cancellable.unwrap_or(false),
9855 message: report.message,
9856 percentage: report.percentage.map(|p| p as usize),
9857 last_update_at: cx.background_executor().now(),
9858 },
9859 cx,
9860 ),
9861 lsp::WorkDoneProgress::End(_) => {
9862 language_server_status.progress_tokens.remove(&token);
9863 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9864 if is_disk_based_diagnostics_progress {
9865 self.disk_based_diagnostics_finished(language_server_id, cx);
9866 }
9867 }
9868 }
9869 }
9870
9871 fn on_lsp_work_start(
9872 &mut self,
9873 language_server_id: LanguageServerId,
9874 token: ProgressToken,
9875 progress: LanguageServerProgress,
9876 cx: &mut Context<Self>,
9877 ) {
9878 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9879 status.pending_work.insert(token.clone(), progress.clone());
9880 cx.notify();
9881 }
9882 cx.emit(LspStoreEvent::LanguageServerUpdate {
9883 language_server_id,
9884 name: self
9885 .language_server_adapter_for_id(language_server_id)
9886 .map(|adapter| adapter.name()),
9887 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9888 token: Some(token.to_proto()),
9889 title: progress.title,
9890 message: progress.message,
9891 percentage: progress.percentage.map(|p| p as u32),
9892 is_cancellable: Some(progress.is_cancellable),
9893 }),
9894 })
9895 }
9896
9897 fn on_lsp_work_progress(
9898 &mut self,
9899 language_server_id: LanguageServerId,
9900 token: ProgressToken,
9901 progress: LanguageServerProgress,
9902 cx: &mut Context<Self>,
9903 ) {
9904 let mut did_update = false;
9905 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9906 match status.pending_work.entry(token.clone()) {
9907 btree_map::Entry::Vacant(entry) => {
9908 entry.insert(progress.clone());
9909 did_update = true;
9910 }
9911 btree_map::Entry::Occupied(mut entry) => {
9912 let entry = entry.get_mut();
9913 if (progress.last_update_at - entry.last_update_at)
9914 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9915 {
9916 entry.last_update_at = progress.last_update_at;
9917 if progress.message.is_some() {
9918 entry.message = progress.message.clone();
9919 }
9920 if progress.percentage.is_some() {
9921 entry.percentage = progress.percentage;
9922 }
9923 if progress.is_cancellable != entry.is_cancellable {
9924 entry.is_cancellable = progress.is_cancellable;
9925 }
9926 did_update = true;
9927 }
9928 }
9929 }
9930 }
9931
9932 if did_update {
9933 cx.emit(LspStoreEvent::LanguageServerUpdate {
9934 language_server_id,
9935 name: self
9936 .language_server_adapter_for_id(language_server_id)
9937 .map(|adapter| adapter.name()),
9938 message: proto::update_language_server::Variant::WorkProgress(
9939 proto::LspWorkProgress {
9940 token: Some(token.to_proto()),
9941 message: progress.message,
9942 percentage: progress.percentage.map(|p| p as u32),
9943 is_cancellable: Some(progress.is_cancellable),
9944 },
9945 ),
9946 })
9947 }
9948 }
9949
9950 fn on_lsp_work_end(
9951 &mut self,
9952 language_server_id: LanguageServerId,
9953 token: ProgressToken,
9954 cx: &mut Context<Self>,
9955 ) {
9956 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9957 if let Some(work) = status.pending_work.remove(&token)
9958 && !work.is_disk_based_diagnostics_progress
9959 {
9960 cx.emit(LspStoreEvent::RefreshInlayHints {
9961 server_id: language_server_id,
9962 request_id: None,
9963 });
9964 }
9965 cx.notify();
9966 }
9967
9968 cx.emit(LspStoreEvent::LanguageServerUpdate {
9969 language_server_id,
9970 name: self
9971 .language_server_adapter_for_id(language_server_id)
9972 .map(|adapter| adapter.name()),
9973 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9974 token: Some(token.to_proto()),
9975 }),
9976 })
9977 }
9978
9979 pub async fn handle_resolve_completion_documentation(
9980 this: Entity<Self>,
9981 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9982 mut cx: AsyncApp,
9983 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9984 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9985
9986 let completion = this
9987 .read_with(&cx, |this, cx| {
9988 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9989 let server = this
9990 .language_server_for_id(id)
9991 .with_context(|| format!("No language server {id}"))?;
9992
9993 anyhow::Ok(cx.background_spawn(async move {
9994 let can_resolve = server
9995 .capabilities()
9996 .completion_provider
9997 .as_ref()
9998 .and_then(|options| options.resolve_provider)
9999 .unwrap_or(false);
10000 if can_resolve {
10001 server
10002 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10003 .await
10004 .into_response()
10005 .context("resolve completion item")
10006 } else {
10007 anyhow::Ok(lsp_completion)
10008 }
10009 }))
10010 })??
10011 .await?;
10012
10013 let mut documentation_is_markdown = false;
10014 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10015 let documentation = match completion.documentation {
10016 Some(lsp::Documentation::String(text)) => text,
10017
10018 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10019 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10020 value
10021 }
10022
10023 _ => String::new(),
10024 };
10025
10026 // If we have a new buffer_id, that means we're talking to a new client
10027 // and want to check for new text_edits in the completion too.
10028 let mut old_replace_start = None;
10029 let mut old_replace_end = None;
10030 let mut old_insert_start = None;
10031 let mut old_insert_end = None;
10032 let mut new_text = String::default();
10033 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10034 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10035 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10036 anyhow::Ok(buffer.read(cx).snapshot())
10037 })??;
10038
10039 if let Some(text_edit) = completion.text_edit.as_ref() {
10040 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10041
10042 if let Some(mut edit) = edit {
10043 LineEnding::normalize(&mut edit.new_text);
10044
10045 new_text = edit.new_text;
10046 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10047 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10048 if let Some(insert_range) = edit.insert_range {
10049 old_insert_start = Some(serialize_anchor(&insert_range.start));
10050 old_insert_end = Some(serialize_anchor(&insert_range.end));
10051 }
10052 }
10053 }
10054 }
10055
10056 Ok(proto::ResolveCompletionDocumentationResponse {
10057 documentation,
10058 documentation_is_markdown,
10059 old_replace_start,
10060 old_replace_end,
10061 new_text,
10062 lsp_completion,
10063 old_insert_start,
10064 old_insert_end,
10065 })
10066 }
10067
10068 async fn handle_on_type_formatting(
10069 this: Entity<Self>,
10070 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10071 mut cx: AsyncApp,
10072 ) -> Result<proto::OnTypeFormattingResponse> {
10073 let on_type_formatting = this.update(&mut cx, |this, cx| {
10074 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10075 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10076 let position = envelope
10077 .payload
10078 .position
10079 .and_then(deserialize_anchor)
10080 .context("invalid position")?;
10081 anyhow::Ok(this.apply_on_type_formatting(
10082 buffer,
10083 position,
10084 envelope.payload.trigger.clone(),
10085 cx,
10086 ))
10087 })??;
10088
10089 let transaction = on_type_formatting
10090 .await?
10091 .as_ref()
10092 .map(language::proto::serialize_transaction);
10093 Ok(proto::OnTypeFormattingResponse { transaction })
10094 }
10095
10096 async fn handle_refresh_inlay_hints(
10097 lsp_store: Entity<Self>,
10098 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10099 mut cx: AsyncApp,
10100 ) -> Result<proto::Ack> {
10101 lsp_store.update(&mut cx, |_, cx| {
10102 cx.emit(LspStoreEvent::RefreshInlayHints {
10103 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10104 request_id: envelope.payload.request_id.map(|id| id as usize),
10105 });
10106 })?;
10107 Ok(proto::Ack {})
10108 }
10109
10110 async fn handle_pull_workspace_diagnostics(
10111 lsp_store: Entity<Self>,
10112 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10113 mut cx: AsyncApp,
10114 ) -> Result<proto::Ack> {
10115 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10116 lsp_store.update(&mut cx, |lsp_store, _| {
10117 lsp_store.pull_workspace_diagnostics(server_id);
10118 })?;
10119 Ok(proto::Ack {})
10120 }
10121
10122 async fn handle_get_color_presentation(
10123 lsp_store: Entity<Self>,
10124 envelope: TypedEnvelope<proto::GetColorPresentation>,
10125 mut cx: AsyncApp,
10126 ) -> Result<proto::GetColorPresentationResponse> {
10127 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10128 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10129 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10130 })??;
10131
10132 let color = envelope
10133 .payload
10134 .color
10135 .context("invalid color resolve request")?;
10136 let start = color
10137 .lsp_range_start
10138 .context("invalid color resolve request")?;
10139 let end = color
10140 .lsp_range_end
10141 .context("invalid color resolve request")?;
10142
10143 let color = DocumentColor {
10144 lsp_range: lsp::Range {
10145 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10146 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10147 },
10148 color: lsp::Color {
10149 red: color.red,
10150 green: color.green,
10151 blue: color.blue,
10152 alpha: color.alpha,
10153 },
10154 resolved: false,
10155 color_presentations: Vec::new(),
10156 };
10157 let resolved_color = lsp_store
10158 .update(&mut cx, |lsp_store, cx| {
10159 lsp_store.resolve_color_presentation(
10160 color,
10161 buffer.clone(),
10162 LanguageServerId(envelope.payload.server_id as usize),
10163 cx,
10164 )
10165 })?
10166 .await
10167 .context("resolving color presentation")?;
10168
10169 Ok(proto::GetColorPresentationResponse {
10170 presentations: resolved_color
10171 .color_presentations
10172 .into_iter()
10173 .map(|presentation| proto::ColorPresentation {
10174 label: presentation.label.to_string(),
10175 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10176 additional_text_edits: presentation
10177 .additional_text_edits
10178 .into_iter()
10179 .map(serialize_lsp_edit)
10180 .collect(),
10181 })
10182 .collect(),
10183 })
10184 }
10185
10186 async fn handle_resolve_inlay_hint(
10187 lsp_store: Entity<Self>,
10188 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10189 mut cx: AsyncApp,
10190 ) -> Result<proto::ResolveInlayHintResponse> {
10191 let proto_hint = envelope
10192 .payload
10193 .hint
10194 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10195 let hint = InlayHints::proto_to_project_hint(proto_hint)
10196 .context("resolved proto inlay hint conversion")?;
10197 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10198 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10199 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10200 })??;
10201 let response_hint = lsp_store
10202 .update(&mut cx, |lsp_store, cx| {
10203 lsp_store.resolve_inlay_hint(
10204 hint,
10205 buffer,
10206 LanguageServerId(envelope.payload.language_server_id as usize),
10207 cx,
10208 )
10209 })?
10210 .await
10211 .context("inlay hints fetch")?;
10212 Ok(proto::ResolveInlayHintResponse {
10213 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10214 })
10215 }
10216
10217 async fn handle_refresh_code_lens(
10218 this: Entity<Self>,
10219 _: TypedEnvelope<proto::RefreshCodeLens>,
10220 mut cx: AsyncApp,
10221 ) -> Result<proto::Ack> {
10222 this.update(&mut cx, |_, cx| {
10223 cx.emit(LspStoreEvent::RefreshCodeLens);
10224 })?;
10225 Ok(proto::Ack {})
10226 }
10227
10228 async fn handle_open_buffer_for_symbol(
10229 this: Entity<Self>,
10230 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10231 mut cx: AsyncApp,
10232 ) -> Result<proto::OpenBufferForSymbolResponse> {
10233 let peer_id = envelope.original_sender_id().unwrap_or_default();
10234 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10235 let symbol = Self::deserialize_symbol(symbol)?;
10236 this.read_with(&cx, |this, _| {
10237 if let SymbolLocation::OutsideProject {
10238 abs_path,
10239 signature,
10240 } = &symbol.path
10241 {
10242 let new_signature = this.symbol_signature(&abs_path);
10243 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10244 }
10245 Ok(())
10246 })??;
10247 let buffer = this
10248 .update(&mut cx, |this, cx| {
10249 this.open_buffer_for_symbol(
10250 &Symbol {
10251 language_server_name: symbol.language_server_name,
10252 source_worktree_id: symbol.source_worktree_id,
10253 source_language_server_id: symbol.source_language_server_id,
10254 path: symbol.path,
10255 name: symbol.name,
10256 kind: symbol.kind,
10257 range: symbol.range,
10258 label: CodeLabel::default(),
10259 },
10260 cx,
10261 )
10262 })?
10263 .await?;
10264
10265 this.update(&mut cx, |this, cx| {
10266 let is_private = buffer
10267 .read(cx)
10268 .file()
10269 .map(|f| f.is_private())
10270 .unwrap_or_default();
10271 if is_private {
10272 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10273 } else {
10274 this.buffer_store
10275 .update(cx, |buffer_store, cx| {
10276 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10277 })
10278 .detach_and_log_err(cx);
10279 let buffer_id = buffer.read(cx).remote_id().to_proto();
10280 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10281 }
10282 })?
10283 }
10284
10285 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10286 let mut hasher = Sha256::new();
10287 hasher.update(abs_path.to_string_lossy().as_bytes());
10288 hasher.update(self.nonce.to_be_bytes());
10289 hasher.finalize().as_slice().try_into().unwrap()
10290 }
10291
10292 pub async fn handle_get_project_symbols(
10293 this: Entity<Self>,
10294 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10295 mut cx: AsyncApp,
10296 ) -> Result<proto::GetProjectSymbolsResponse> {
10297 let symbols = this
10298 .update(&mut cx, |this, cx| {
10299 this.symbols(&envelope.payload.query, cx)
10300 })?
10301 .await?;
10302
10303 Ok(proto::GetProjectSymbolsResponse {
10304 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10305 })
10306 }
10307
10308 pub async fn handle_restart_language_servers(
10309 this: Entity<Self>,
10310 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10311 mut cx: AsyncApp,
10312 ) -> Result<proto::Ack> {
10313 this.update(&mut cx, |lsp_store, cx| {
10314 let buffers =
10315 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10316 lsp_store.restart_language_servers_for_buffers(
10317 buffers,
10318 envelope
10319 .payload
10320 .only_servers
10321 .into_iter()
10322 .filter_map(|selector| {
10323 Some(match selector.selector? {
10324 proto::language_server_selector::Selector::ServerId(server_id) => {
10325 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10326 }
10327 proto::language_server_selector::Selector::Name(name) => {
10328 LanguageServerSelector::Name(LanguageServerName(
10329 SharedString::from(name),
10330 ))
10331 }
10332 })
10333 })
10334 .collect(),
10335 cx,
10336 );
10337 })?;
10338
10339 Ok(proto::Ack {})
10340 }
10341
10342 pub async fn handle_stop_language_servers(
10343 lsp_store: Entity<Self>,
10344 envelope: TypedEnvelope<proto::StopLanguageServers>,
10345 mut cx: AsyncApp,
10346 ) -> Result<proto::Ack> {
10347 lsp_store.update(&mut cx, |lsp_store, cx| {
10348 if envelope.payload.all
10349 && envelope.payload.also_servers.is_empty()
10350 && envelope.payload.buffer_ids.is_empty()
10351 {
10352 lsp_store.stop_all_language_servers(cx);
10353 } else {
10354 let buffers =
10355 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10356 lsp_store
10357 .stop_language_servers_for_buffers(
10358 buffers,
10359 envelope
10360 .payload
10361 .also_servers
10362 .into_iter()
10363 .filter_map(|selector| {
10364 Some(match selector.selector? {
10365 proto::language_server_selector::Selector::ServerId(
10366 server_id,
10367 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10368 server_id,
10369 )),
10370 proto::language_server_selector::Selector::Name(name) => {
10371 LanguageServerSelector::Name(LanguageServerName(
10372 SharedString::from(name),
10373 ))
10374 }
10375 })
10376 })
10377 .collect(),
10378 cx,
10379 )
10380 .detach_and_log_err(cx);
10381 }
10382 })?;
10383
10384 Ok(proto::Ack {})
10385 }
10386
10387 pub async fn handle_cancel_language_server_work(
10388 lsp_store: Entity<Self>,
10389 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10390 mut cx: AsyncApp,
10391 ) -> Result<proto::Ack> {
10392 lsp_store.update(&mut cx, |lsp_store, cx| {
10393 if let Some(work) = envelope.payload.work {
10394 match work {
10395 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10396 let buffers =
10397 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10398 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10399 }
10400 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10401 let server_id = LanguageServerId::from_proto(work.language_server_id);
10402 let token = work
10403 .token
10404 .map(|token| {
10405 ProgressToken::from_proto(token)
10406 .context("invalid work progress token")
10407 })
10408 .transpose()?;
10409 lsp_store.cancel_language_server_work(server_id, token, cx);
10410 }
10411 }
10412 }
10413 anyhow::Ok(())
10414 })??;
10415
10416 Ok(proto::Ack {})
10417 }
10418
10419 fn buffer_ids_to_buffers(
10420 &mut self,
10421 buffer_ids: impl Iterator<Item = u64>,
10422 cx: &mut Context<Self>,
10423 ) -> Vec<Entity<Buffer>> {
10424 buffer_ids
10425 .into_iter()
10426 .flat_map(|buffer_id| {
10427 self.buffer_store
10428 .read(cx)
10429 .get(BufferId::new(buffer_id).log_err()?)
10430 })
10431 .collect::<Vec<_>>()
10432 }
10433
10434 async fn handle_apply_additional_edits_for_completion(
10435 this: Entity<Self>,
10436 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10437 mut cx: AsyncApp,
10438 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10439 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10440 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10441 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10442 let completion = Self::deserialize_completion(
10443 envelope.payload.completion.context("invalid completion")?,
10444 )?;
10445 anyhow::Ok((buffer, completion))
10446 })??;
10447
10448 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10449 this.apply_additional_edits_for_completion(
10450 buffer,
10451 Rc::new(RefCell::new(Box::new([Completion {
10452 replace_range: completion.replace_range,
10453 new_text: completion.new_text,
10454 source: completion.source,
10455 documentation: None,
10456 label: CodeLabel::default(),
10457 match_start: None,
10458 snippet_deduplication_key: None,
10459 insert_text_mode: None,
10460 icon_path: None,
10461 confirm: None,
10462 }]))),
10463 0,
10464 false,
10465 cx,
10466 )
10467 })?;
10468
10469 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10470 transaction: apply_additional_edits
10471 .await?
10472 .as_ref()
10473 .map(language::proto::serialize_transaction),
10474 })
10475 }
10476
10477 pub fn last_formatting_failure(&self) -> Option<&str> {
10478 self.last_formatting_failure.as_deref()
10479 }
10480
10481 pub fn reset_last_formatting_failure(&mut self) {
10482 self.last_formatting_failure = None;
10483 }
10484
10485 pub fn environment_for_buffer(
10486 &self,
10487 buffer: &Entity<Buffer>,
10488 cx: &mut Context<Self>,
10489 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10490 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10491 environment.update(cx, |env, cx| {
10492 env.buffer_environment(buffer, &self.worktree_store, cx)
10493 })
10494 } else {
10495 Task::ready(None).shared()
10496 }
10497 }
10498
10499 pub fn format(
10500 &mut self,
10501 buffers: HashSet<Entity<Buffer>>,
10502 target: LspFormatTarget,
10503 push_to_history: bool,
10504 trigger: FormatTrigger,
10505 cx: &mut Context<Self>,
10506 ) -> Task<anyhow::Result<ProjectTransaction>> {
10507 let logger = zlog::scoped!("format");
10508 if self.as_local().is_some() {
10509 zlog::trace!(logger => "Formatting locally");
10510 let logger = zlog::scoped!(logger => "local");
10511 let buffers = buffers
10512 .into_iter()
10513 .map(|buffer_handle| {
10514 let buffer = buffer_handle.read(cx);
10515 let buffer_abs_path = File::from_dyn(buffer.file())
10516 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10517
10518 (buffer_handle, buffer_abs_path, buffer.remote_id())
10519 })
10520 .collect::<Vec<_>>();
10521
10522 cx.spawn(async move |lsp_store, cx| {
10523 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10524
10525 for (handle, abs_path, id) in buffers {
10526 let env = lsp_store
10527 .update(cx, |lsp_store, cx| {
10528 lsp_store.environment_for_buffer(&handle, cx)
10529 })?
10530 .await;
10531
10532 let ranges = match &target {
10533 LspFormatTarget::Buffers => None,
10534 LspFormatTarget::Ranges(ranges) => {
10535 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10536 }
10537 };
10538
10539 formattable_buffers.push(FormattableBuffer {
10540 handle,
10541 abs_path,
10542 env,
10543 ranges,
10544 });
10545 }
10546 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10547
10548 let format_timer = zlog::time!(logger => "Formatting buffers");
10549 let result = LocalLspStore::format_locally(
10550 lsp_store.clone(),
10551 formattable_buffers,
10552 push_to_history,
10553 trigger,
10554 logger,
10555 cx,
10556 )
10557 .await;
10558 format_timer.end();
10559
10560 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10561
10562 lsp_store.update(cx, |lsp_store, _| {
10563 lsp_store.update_last_formatting_failure(&result);
10564 })?;
10565
10566 result
10567 })
10568 } else if let Some((client, project_id)) = self.upstream_client() {
10569 zlog::trace!(logger => "Formatting remotely");
10570 let logger = zlog::scoped!(logger => "remote");
10571 // Don't support formatting ranges via remote
10572 match target {
10573 LspFormatTarget::Buffers => {}
10574 LspFormatTarget::Ranges(_) => {
10575 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10576 return Task::ready(Ok(ProjectTransaction::default()));
10577 }
10578 }
10579
10580 let buffer_store = self.buffer_store();
10581 cx.spawn(async move |lsp_store, cx| {
10582 zlog::trace!(logger => "Sending remote format request");
10583 let request_timer = zlog::time!(logger => "remote format request");
10584 let result = client
10585 .request(proto::FormatBuffers {
10586 project_id,
10587 trigger: trigger as i32,
10588 buffer_ids: buffers
10589 .iter()
10590 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10591 .collect::<Result<_>>()?,
10592 })
10593 .await
10594 .and_then(|result| result.transaction.context("missing transaction"));
10595 request_timer.end();
10596
10597 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10598
10599 lsp_store.update(cx, |lsp_store, _| {
10600 lsp_store.update_last_formatting_failure(&result);
10601 })?;
10602
10603 let transaction_response = result?;
10604 let _timer = zlog::time!(logger => "deserializing project transaction");
10605 buffer_store
10606 .update(cx, |buffer_store, cx| {
10607 buffer_store.deserialize_project_transaction(
10608 transaction_response,
10609 push_to_history,
10610 cx,
10611 )
10612 })?
10613 .await
10614 })
10615 } else {
10616 zlog::trace!(logger => "Not formatting");
10617 Task::ready(Ok(ProjectTransaction::default()))
10618 }
10619 }
10620
10621 async fn handle_format_buffers(
10622 this: Entity<Self>,
10623 envelope: TypedEnvelope<proto::FormatBuffers>,
10624 mut cx: AsyncApp,
10625 ) -> Result<proto::FormatBuffersResponse> {
10626 let sender_id = envelope.original_sender_id().unwrap_or_default();
10627 let format = this.update(&mut cx, |this, cx| {
10628 let mut buffers = HashSet::default();
10629 for buffer_id in &envelope.payload.buffer_ids {
10630 let buffer_id = BufferId::new(*buffer_id)?;
10631 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10632 }
10633 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10634 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10635 })??;
10636
10637 let project_transaction = format.await?;
10638 let project_transaction = this.update(&mut cx, |this, cx| {
10639 this.buffer_store.update(cx, |buffer_store, cx| {
10640 buffer_store.serialize_project_transaction_for_peer(
10641 project_transaction,
10642 sender_id,
10643 cx,
10644 )
10645 })
10646 })?;
10647 Ok(proto::FormatBuffersResponse {
10648 transaction: Some(project_transaction),
10649 })
10650 }
10651
10652 async fn handle_apply_code_action_kind(
10653 this: Entity<Self>,
10654 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10655 mut cx: AsyncApp,
10656 ) -> Result<proto::ApplyCodeActionKindResponse> {
10657 let sender_id = envelope.original_sender_id().unwrap_or_default();
10658 let format = this.update(&mut cx, |this, cx| {
10659 let mut buffers = HashSet::default();
10660 for buffer_id in &envelope.payload.buffer_ids {
10661 let buffer_id = BufferId::new(*buffer_id)?;
10662 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10663 }
10664 let kind = match envelope.payload.kind.as_str() {
10665 "" => CodeActionKind::EMPTY,
10666 "quickfix" => CodeActionKind::QUICKFIX,
10667 "refactor" => CodeActionKind::REFACTOR,
10668 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10669 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10670 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10671 "source" => CodeActionKind::SOURCE,
10672 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10673 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10674 _ => anyhow::bail!(
10675 "Invalid code action kind {}",
10676 envelope.payload.kind.as_str()
10677 ),
10678 };
10679 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10680 })??;
10681
10682 let project_transaction = format.await?;
10683 let project_transaction = this.update(&mut cx, |this, cx| {
10684 this.buffer_store.update(cx, |buffer_store, cx| {
10685 buffer_store.serialize_project_transaction_for_peer(
10686 project_transaction,
10687 sender_id,
10688 cx,
10689 )
10690 })
10691 })?;
10692 Ok(proto::ApplyCodeActionKindResponse {
10693 transaction: Some(project_transaction),
10694 })
10695 }
10696
10697 async fn shutdown_language_server(
10698 server_state: Option<LanguageServerState>,
10699 name: LanguageServerName,
10700 cx: &mut AsyncApp,
10701 ) {
10702 let server = match server_state {
10703 Some(LanguageServerState::Starting { startup, .. }) => {
10704 let mut timer = cx
10705 .background_executor()
10706 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10707 .fuse();
10708
10709 select! {
10710 server = startup.fuse() => server,
10711 () = timer => {
10712 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10713 None
10714 },
10715 }
10716 }
10717
10718 Some(LanguageServerState::Running { server, .. }) => Some(server),
10719
10720 None => None,
10721 };
10722
10723 if let Some(server) = server
10724 && let Some(shutdown) = server.shutdown()
10725 {
10726 shutdown.await;
10727 }
10728 }
10729
10730 // Returns a list of all of the worktrees which no longer have a language server and the root path
10731 // for the stopped server
10732 fn stop_local_language_server(
10733 &mut self,
10734 server_id: LanguageServerId,
10735 cx: &mut Context<Self>,
10736 ) -> Task<()> {
10737 let local = match &mut self.mode {
10738 LspStoreMode::Local(local) => local,
10739 _ => {
10740 return Task::ready(());
10741 }
10742 };
10743
10744 // Remove this server ID from all entries in the given worktree.
10745 local
10746 .language_server_ids
10747 .retain(|_, state| state.id != server_id);
10748 self.buffer_store.update(cx, |buffer_store, cx| {
10749 for buffer in buffer_store.buffers() {
10750 buffer.update(cx, |buffer, cx| {
10751 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10752 buffer.set_completion_triggers(server_id, Default::default(), cx);
10753 });
10754 }
10755 });
10756
10757 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10758 summaries.retain(|path, summaries_by_server_id| {
10759 if summaries_by_server_id.remove(&server_id).is_some() {
10760 if let Some((client, project_id)) = self.downstream_client.clone() {
10761 client
10762 .send(proto::UpdateDiagnosticSummary {
10763 project_id,
10764 worktree_id: worktree_id.to_proto(),
10765 summary: Some(proto::DiagnosticSummary {
10766 path: path.as_ref().to_proto(),
10767 language_server_id: server_id.0 as u64,
10768 error_count: 0,
10769 warning_count: 0,
10770 }),
10771 more_summaries: Vec::new(),
10772 })
10773 .log_err();
10774 }
10775 !summaries_by_server_id.is_empty()
10776 } else {
10777 true
10778 }
10779 });
10780 }
10781
10782 let local = self.as_local_mut().unwrap();
10783 for diagnostics in local.diagnostics.values_mut() {
10784 diagnostics.retain(|_, diagnostics_by_server_id| {
10785 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10786 diagnostics_by_server_id.remove(ix);
10787 !diagnostics_by_server_id.is_empty()
10788 } else {
10789 true
10790 }
10791 });
10792 }
10793 local.language_server_watched_paths.remove(&server_id);
10794
10795 let server_state = local.language_servers.remove(&server_id);
10796 self.cleanup_lsp_data(server_id);
10797 let name = self
10798 .language_server_statuses
10799 .remove(&server_id)
10800 .map(|status| status.name)
10801 .or_else(|| {
10802 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10803 Some(adapter.name())
10804 } else {
10805 None
10806 }
10807 });
10808
10809 if let Some(name) = name {
10810 log::info!("stopping language server {name}");
10811 self.languages
10812 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10813 cx.notify();
10814
10815 return cx.spawn(async move |lsp_store, cx| {
10816 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10817 lsp_store
10818 .update(cx, |lsp_store, cx| {
10819 lsp_store
10820 .languages
10821 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10822 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10823 cx.notify();
10824 })
10825 .ok();
10826 });
10827 }
10828
10829 if server_state.is_some() {
10830 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10831 }
10832 Task::ready(())
10833 }
10834
10835 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10836 if let Some((client, project_id)) = self.upstream_client() {
10837 let request = client.request(proto::StopLanguageServers {
10838 project_id,
10839 buffer_ids: Vec::new(),
10840 also_servers: Vec::new(),
10841 all: true,
10842 });
10843 cx.background_spawn(request).detach_and_log_err(cx);
10844 } else {
10845 let Some(local) = self.as_local_mut() else {
10846 return;
10847 };
10848 let language_servers_to_stop = local
10849 .language_server_ids
10850 .values()
10851 .map(|state| state.id)
10852 .collect();
10853 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10854 let tasks = language_servers_to_stop
10855 .into_iter()
10856 .map(|server| self.stop_local_language_server(server, cx))
10857 .collect::<Vec<_>>();
10858 cx.background_spawn(async move {
10859 futures::future::join_all(tasks).await;
10860 })
10861 .detach();
10862 }
10863 }
10864
10865 pub fn restart_language_servers_for_buffers(
10866 &mut self,
10867 buffers: Vec<Entity<Buffer>>,
10868 only_restart_servers: HashSet<LanguageServerSelector>,
10869 cx: &mut Context<Self>,
10870 ) {
10871 if let Some((client, project_id)) = self.upstream_client() {
10872 let request = client.request(proto::RestartLanguageServers {
10873 project_id,
10874 buffer_ids: buffers
10875 .into_iter()
10876 .map(|b| b.read(cx).remote_id().to_proto())
10877 .collect(),
10878 only_servers: only_restart_servers
10879 .into_iter()
10880 .map(|selector| {
10881 let selector = match selector {
10882 LanguageServerSelector::Id(language_server_id) => {
10883 proto::language_server_selector::Selector::ServerId(
10884 language_server_id.to_proto(),
10885 )
10886 }
10887 LanguageServerSelector::Name(language_server_name) => {
10888 proto::language_server_selector::Selector::Name(
10889 language_server_name.to_string(),
10890 )
10891 }
10892 };
10893 proto::LanguageServerSelector {
10894 selector: Some(selector),
10895 }
10896 })
10897 .collect(),
10898 all: false,
10899 });
10900 cx.background_spawn(request).detach_and_log_err(cx);
10901 } else {
10902 let stop_task = if only_restart_servers.is_empty() {
10903 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10904 } else {
10905 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10906 };
10907 cx.spawn(async move |lsp_store, cx| {
10908 stop_task.await;
10909 lsp_store
10910 .update(cx, |lsp_store, cx| {
10911 for buffer in buffers {
10912 lsp_store.register_buffer_with_language_servers(
10913 &buffer,
10914 only_restart_servers.clone(),
10915 true,
10916 cx,
10917 );
10918 }
10919 })
10920 .ok()
10921 })
10922 .detach();
10923 }
10924 }
10925
10926 pub fn stop_language_servers_for_buffers(
10927 &mut self,
10928 buffers: Vec<Entity<Buffer>>,
10929 also_stop_servers: HashSet<LanguageServerSelector>,
10930 cx: &mut Context<Self>,
10931 ) -> Task<Result<()>> {
10932 if let Some((client, project_id)) = self.upstream_client() {
10933 let request = client.request(proto::StopLanguageServers {
10934 project_id,
10935 buffer_ids: buffers
10936 .into_iter()
10937 .map(|b| b.read(cx).remote_id().to_proto())
10938 .collect(),
10939 also_servers: also_stop_servers
10940 .into_iter()
10941 .map(|selector| {
10942 let selector = match selector {
10943 LanguageServerSelector::Id(language_server_id) => {
10944 proto::language_server_selector::Selector::ServerId(
10945 language_server_id.to_proto(),
10946 )
10947 }
10948 LanguageServerSelector::Name(language_server_name) => {
10949 proto::language_server_selector::Selector::Name(
10950 language_server_name.to_string(),
10951 )
10952 }
10953 };
10954 proto::LanguageServerSelector {
10955 selector: Some(selector),
10956 }
10957 })
10958 .collect(),
10959 all: false,
10960 });
10961 cx.background_spawn(async move {
10962 let _ = request.await?;
10963 Ok(())
10964 })
10965 } else {
10966 let task =
10967 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10968 cx.background_spawn(async move {
10969 task.await;
10970 Ok(())
10971 })
10972 }
10973 }
10974
10975 fn stop_local_language_servers_for_buffers(
10976 &mut self,
10977 buffers: &[Entity<Buffer>],
10978 also_stop_servers: HashSet<LanguageServerSelector>,
10979 cx: &mut Context<Self>,
10980 ) -> Task<()> {
10981 let Some(local) = self.as_local_mut() else {
10982 return Task::ready(());
10983 };
10984 let mut language_server_names_to_stop = BTreeSet::default();
10985 let mut language_servers_to_stop = also_stop_servers
10986 .into_iter()
10987 .flat_map(|selector| match selector {
10988 LanguageServerSelector::Id(id) => Some(id),
10989 LanguageServerSelector::Name(name) => {
10990 language_server_names_to_stop.insert(name);
10991 None
10992 }
10993 })
10994 .collect::<BTreeSet<_>>();
10995
10996 let mut covered_worktrees = HashSet::default();
10997 for buffer in buffers {
10998 buffer.update(cx, |buffer, cx| {
10999 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11000 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11001 && covered_worktrees.insert(worktree_id)
11002 {
11003 language_server_names_to_stop.retain(|name| {
11004 let old_ids_count = language_servers_to_stop.len();
11005 let all_language_servers_with_this_name = local
11006 .language_server_ids
11007 .iter()
11008 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11009 language_servers_to_stop.extend(all_language_servers_with_this_name);
11010 old_ids_count == language_servers_to_stop.len()
11011 });
11012 }
11013 });
11014 }
11015 for name in language_server_names_to_stop {
11016 language_servers_to_stop.extend(
11017 local
11018 .language_server_ids
11019 .iter()
11020 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11021 );
11022 }
11023
11024 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11025 let tasks = language_servers_to_stop
11026 .into_iter()
11027 .map(|server| self.stop_local_language_server(server, cx))
11028 .collect::<Vec<_>>();
11029
11030 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11031 }
11032
11033 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11034 let (worktree, relative_path) =
11035 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11036
11037 let project_path = ProjectPath {
11038 worktree_id: worktree.read(cx).id(),
11039 path: relative_path,
11040 };
11041
11042 Some(
11043 self.buffer_store()
11044 .read(cx)
11045 .get_by_path(&project_path)?
11046 .read(cx),
11047 )
11048 }
11049
11050 #[cfg(any(test, feature = "test-support"))]
11051 pub fn update_diagnostics(
11052 &mut self,
11053 server_id: LanguageServerId,
11054 diagnostics: lsp::PublishDiagnosticsParams,
11055 result_id: Option<SharedString>,
11056 source_kind: DiagnosticSourceKind,
11057 disk_based_sources: &[String],
11058 cx: &mut Context<Self>,
11059 ) -> Result<()> {
11060 self.merge_lsp_diagnostics(
11061 source_kind,
11062 vec![DocumentDiagnosticsUpdate {
11063 diagnostics,
11064 result_id,
11065 server_id,
11066 disk_based_sources: Cow::Borrowed(disk_based_sources),
11067 registration_id: None,
11068 }],
11069 |_, _, _| false,
11070 cx,
11071 )
11072 }
11073
11074 pub fn merge_lsp_diagnostics(
11075 &mut self,
11076 source_kind: DiagnosticSourceKind,
11077 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11078 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11079 cx: &mut Context<Self>,
11080 ) -> Result<()> {
11081 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11082 let updates = lsp_diagnostics
11083 .into_iter()
11084 .filter_map(|update| {
11085 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11086 Some(DocumentDiagnosticsUpdate {
11087 diagnostics: self.lsp_to_document_diagnostics(
11088 abs_path,
11089 source_kind,
11090 update.server_id,
11091 update.diagnostics,
11092 &update.disk_based_sources,
11093 update.registration_id.clone(),
11094 ),
11095 result_id: update.result_id,
11096 server_id: update.server_id,
11097 disk_based_sources: update.disk_based_sources,
11098 registration_id: update.registration_id,
11099 })
11100 })
11101 .collect();
11102 self.merge_diagnostic_entries(updates, merge, cx)?;
11103 Ok(())
11104 }
11105
11106 fn lsp_to_document_diagnostics(
11107 &mut self,
11108 document_abs_path: PathBuf,
11109 source_kind: DiagnosticSourceKind,
11110 server_id: LanguageServerId,
11111 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11112 disk_based_sources: &[String],
11113 registration_id: Option<SharedString>,
11114 ) -> DocumentDiagnostics {
11115 let mut diagnostics = Vec::default();
11116 let mut primary_diagnostic_group_ids = HashMap::default();
11117 let mut sources_by_group_id = HashMap::default();
11118 let mut supporting_diagnostics = HashMap::default();
11119
11120 let adapter = self.language_server_adapter_for_id(server_id);
11121
11122 // Ensure that primary diagnostics are always the most severe
11123 lsp_diagnostics
11124 .diagnostics
11125 .sort_by_key(|item| item.severity);
11126
11127 for diagnostic in &lsp_diagnostics.diagnostics {
11128 let source = diagnostic.source.as_ref();
11129 let range = range_from_lsp(diagnostic.range);
11130 let is_supporting = diagnostic
11131 .related_information
11132 .as_ref()
11133 .is_some_and(|infos| {
11134 infos.iter().any(|info| {
11135 primary_diagnostic_group_ids.contains_key(&(
11136 source,
11137 diagnostic.code.clone(),
11138 range_from_lsp(info.location.range),
11139 ))
11140 })
11141 });
11142
11143 let is_unnecessary = diagnostic
11144 .tags
11145 .as_ref()
11146 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11147
11148 let underline = self
11149 .language_server_adapter_for_id(server_id)
11150 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11151
11152 if is_supporting {
11153 supporting_diagnostics.insert(
11154 (source, diagnostic.code.clone(), range),
11155 (diagnostic.severity, is_unnecessary),
11156 );
11157 } else {
11158 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11159 let is_disk_based =
11160 source.is_some_and(|source| disk_based_sources.contains(source));
11161
11162 sources_by_group_id.insert(group_id, source);
11163 primary_diagnostic_group_ids
11164 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11165
11166 diagnostics.push(DiagnosticEntry {
11167 range,
11168 diagnostic: Diagnostic {
11169 source: diagnostic.source.clone(),
11170 source_kind,
11171 code: diagnostic.code.clone(),
11172 code_description: diagnostic
11173 .code_description
11174 .as_ref()
11175 .and_then(|d| d.href.clone()),
11176 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11177 markdown: adapter.as_ref().and_then(|adapter| {
11178 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11179 }),
11180 message: diagnostic.message.trim().to_string(),
11181 group_id,
11182 is_primary: true,
11183 is_disk_based,
11184 is_unnecessary,
11185 underline,
11186 data: diagnostic.data.clone(),
11187 registration_id: registration_id.clone(),
11188 },
11189 });
11190 if let Some(infos) = &diagnostic.related_information {
11191 for info in infos {
11192 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11193 let range = range_from_lsp(info.location.range);
11194 diagnostics.push(DiagnosticEntry {
11195 range,
11196 diagnostic: Diagnostic {
11197 source: diagnostic.source.clone(),
11198 source_kind,
11199 code: diagnostic.code.clone(),
11200 code_description: diagnostic
11201 .code_description
11202 .as_ref()
11203 .and_then(|d| d.href.clone()),
11204 severity: DiagnosticSeverity::INFORMATION,
11205 markdown: adapter.as_ref().and_then(|adapter| {
11206 adapter.diagnostic_message_to_markdown(&info.message)
11207 }),
11208 message: info.message.trim().to_string(),
11209 group_id,
11210 is_primary: false,
11211 is_disk_based,
11212 is_unnecessary: false,
11213 underline,
11214 data: diagnostic.data.clone(),
11215 registration_id: registration_id.clone(),
11216 },
11217 });
11218 }
11219 }
11220 }
11221 }
11222 }
11223
11224 for entry in &mut diagnostics {
11225 let diagnostic = &mut entry.diagnostic;
11226 if !diagnostic.is_primary {
11227 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11228 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11229 source,
11230 diagnostic.code.clone(),
11231 entry.range.clone(),
11232 )) {
11233 if let Some(severity) = severity {
11234 diagnostic.severity = severity;
11235 }
11236 diagnostic.is_unnecessary = is_unnecessary;
11237 }
11238 }
11239 }
11240
11241 DocumentDiagnostics {
11242 diagnostics,
11243 document_abs_path,
11244 version: lsp_diagnostics.version,
11245 }
11246 }
11247
11248 fn insert_newly_running_language_server(
11249 &mut self,
11250 adapter: Arc<CachedLspAdapter>,
11251 language_server: Arc<LanguageServer>,
11252 server_id: LanguageServerId,
11253 key: LanguageServerSeed,
11254 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11255 cx: &mut Context<Self>,
11256 ) {
11257 let Some(local) = self.as_local_mut() else {
11258 return;
11259 };
11260 // If the language server for this key doesn't match the server id, don't store the
11261 // server. Which will cause it to be dropped, killing the process
11262 if local
11263 .language_server_ids
11264 .get(&key)
11265 .map(|state| state.id != server_id)
11266 .unwrap_or(false)
11267 {
11268 return;
11269 }
11270
11271 // Update language_servers collection with Running variant of LanguageServerState
11272 // indicating that the server is up and running and ready
11273 let workspace_folders = workspace_folders.lock().clone();
11274 language_server.set_workspace_folders(workspace_folders);
11275
11276 let workspace_diagnostics_refresh_tasks = language_server
11277 .capabilities()
11278 .diagnostic_provider
11279 .and_then(|provider| {
11280 local
11281 .language_server_dynamic_registrations
11282 .entry(server_id)
11283 .or_default()
11284 .diagnostics
11285 .entry(None)
11286 .or_insert(provider.clone());
11287 let workspace_refresher =
11288 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11289
11290 Some((None, workspace_refresher))
11291 })
11292 .into_iter()
11293 .collect();
11294 local.language_servers.insert(
11295 server_id,
11296 LanguageServerState::Running {
11297 workspace_diagnostics_refresh_tasks,
11298 adapter: adapter.clone(),
11299 server: language_server.clone(),
11300 simulate_disk_based_diagnostics_completion: None,
11301 },
11302 );
11303 local
11304 .languages
11305 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11306 if let Some(file_ops_caps) = language_server
11307 .capabilities()
11308 .workspace
11309 .as_ref()
11310 .and_then(|ws| ws.file_operations.as_ref())
11311 {
11312 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11313 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11314 if did_rename_caps.or(will_rename_caps).is_some() {
11315 let watcher = RenamePathsWatchedForServer::default()
11316 .with_did_rename_patterns(did_rename_caps)
11317 .with_will_rename_patterns(will_rename_caps);
11318 local
11319 .language_server_paths_watched_for_rename
11320 .insert(server_id, watcher);
11321 }
11322 }
11323
11324 self.language_server_statuses.insert(
11325 server_id,
11326 LanguageServerStatus {
11327 name: language_server.name(),
11328 pending_work: Default::default(),
11329 has_pending_diagnostic_updates: false,
11330 progress_tokens: Default::default(),
11331 worktree: Some(key.worktree_id),
11332 binary: Some(language_server.binary().clone()),
11333 configuration: Some(language_server.configuration().clone()),
11334 workspace_folders: language_server.workspace_folders(),
11335 },
11336 );
11337
11338 cx.emit(LspStoreEvent::LanguageServerAdded(
11339 server_id,
11340 language_server.name(),
11341 Some(key.worktree_id),
11342 ));
11343
11344 let server_capabilities = language_server.capabilities();
11345 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11346 downstream_client
11347 .send(proto::StartLanguageServer {
11348 project_id: *project_id,
11349 server: Some(proto::LanguageServer {
11350 id: server_id.to_proto(),
11351 name: language_server.name().to_string(),
11352 worktree_id: Some(key.worktree_id.to_proto()),
11353 }),
11354 capabilities: serde_json::to_string(&server_capabilities)
11355 .expect("serializing server LSP capabilities"),
11356 })
11357 .log_err();
11358 }
11359 self.lsp_server_capabilities
11360 .insert(server_id, server_capabilities);
11361
11362 // Tell the language server about every open buffer in the worktree that matches the language.
11363 // Also check for buffers in worktrees that reused this server
11364 let mut worktrees_using_server = vec![key.worktree_id];
11365 if let Some(local) = self.as_local() {
11366 // Find all worktrees that have this server in their language server tree
11367 for (worktree_id, servers) in &local.lsp_tree.instances {
11368 if *worktree_id != key.worktree_id {
11369 for server_map in servers.roots.values() {
11370 if server_map
11371 .values()
11372 .any(|(node, _)| node.id() == Some(server_id))
11373 {
11374 worktrees_using_server.push(*worktree_id);
11375 }
11376 }
11377 }
11378 }
11379 }
11380
11381 let mut buffer_paths_registered = Vec::new();
11382 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11383 let mut lsp_adapters = HashMap::default();
11384 for buffer_handle in buffer_store.buffers() {
11385 let buffer = buffer_handle.read(cx);
11386 let file = match File::from_dyn(buffer.file()) {
11387 Some(file) => file,
11388 None => continue,
11389 };
11390 let language = match buffer.language() {
11391 Some(language) => language,
11392 None => continue,
11393 };
11394
11395 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11396 || !lsp_adapters
11397 .entry(language.name())
11398 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11399 .iter()
11400 .any(|a| a.name == key.name)
11401 {
11402 continue;
11403 }
11404 // didOpen
11405 let file = match file.as_local() {
11406 Some(file) => file,
11407 None => continue,
11408 };
11409
11410 let local = self.as_local_mut().unwrap();
11411
11412 let buffer_id = buffer.remote_id();
11413 if local.registered_buffers.contains_key(&buffer_id) {
11414 let versions = local
11415 .buffer_snapshots
11416 .entry(buffer_id)
11417 .or_default()
11418 .entry(server_id)
11419 .and_modify(|_| {
11420 assert!(
11421 false,
11422 "There should not be an existing snapshot for a newly inserted buffer"
11423 )
11424 })
11425 .or_insert_with(|| {
11426 vec![LspBufferSnapshot {
11427 version: 0,
11428 snapshot: buffer.text_snapshot(),
11429 }]
11430 });
11431
11432 let snapshot = versions.last().unwrap();
11433 let version = snapshot.version;
11434 let initial_snapshot = &snapshot.snapshot;
11435 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11436 language_server.register_buffer(
11437 uri,
11438 adapter.language_id(&language.name()),
11439 version,
11440 initial_snapshot.text(),
11441 );
11442 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11443 local
11444 .buffers_opened_in_servers
11445 .entry(buffer_id)
11446 .or_default()
11447 .insert(server_id);
11448 }
11449 buffer_handle.update(cx, |buffer, cx| {
11450 buffer.set_completion_triggers(
11451 server_id,
11452 language_server
11453 .capabilities()
11454 .completion_provider
11455 .as_ref()
11456 .and_then(|provider| {
11457 provider
11458 .trigger_characters
11459 .as_ref()
11460 .map(|characters| characters.iter().cloned().collect())
11461 })
11462 .unwrap_or_default(),
11463 cx,
11464 )
11465 });
11466 }
11467 });
11468
11469 for (buffer_id, abs_path) in buffer_paths_registered {
11470 cx.emit(LspStoreEvent::LanguageServerUpdate {
11471 language_server_id: server_id,
11472 name: Some(adapter.name()),
11473 message: proto::update_language_server::Variant::RegisteredForBuffer(
11474 proto::RegisteredForBuffer {
11475 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11476 buffer_id: buffer_id.to_proto(),
11477 },
11478 ),
11479 });
11480 }
11481
11482 cx.notify();
11483 }
11484
11485 pub fn language_servers_running_disk_based_diagnostics(
11486 &self,
11487 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11488 self.language_server_statuses
11489 .iter()
11490 .filter_map(|(id, status)| {
11491 if status.has_pending_diagnostic_updates {
11492 Some(*id)
11493 } else {
11494 None
11495 }
11496 })
11497 }
11498
11499 pub(crate) fn cancel_language_server_work_for_buffers(
11500 &mut self,
11501 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11502 cx: &mut Context<Self>,
11503 ) {
11504 if let Some((client, project_id)) = self.upstream_client() {
11505 let request = client.request(proto::CancelLanguageServerWork {
11506 project_id,
11507 work: Some(proto::cancel_language_server_work::Work::Buffers(
11508 proto::cancel_language_server_work::Buffers {
11509 buffer_ids: buffers
11510 .into_iter()
11511 .map(|b| b.read(cx).remote_id().to_proto())
11512 .collect(),
11513 },
11514 )),
11515 });
11516 cx.background_spawn(request).detach_and_log_err(cx);
11517 } else if let Some(local) = self.as_local() {
11518 let servers = buffers
11519 .into_iter()
11520 .flat_map(|buffer| {
11521 buffer.update(cx, |buffer, cx| {
11522 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11523 })
11524 })
11525 .collect::<HashSet<_>>();
11526 for server_id in servers {
11527 self.cancel_language_server_work(server_id, None, cx);
11528 }
11529 }
11530 }
11531
11532 pub(crate) fn cancel_language_server_work(
11533 &mut self,
11534 server_id: LanguageServerId,
11535 token_to_cancel: Option<ProgressToken>,
11536 cx: &mut Context<Self>,
11537 ) {
11538 if let Some(local) = self.as_local() {
11539 let status = self.language_server_statuses.get(&server_id);
11540 let server = local.language_servers.get(&server_id);
11541 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11542 {
11543 for (token, progress) in &status.pending_work {
11544 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11545 && token != token_to_cancel
11546 {
11547 continue;
11548 }
11549 if progress.is_cancellable {
11550 server
11551 .notify::<lsp::notification::WorkDoneProgressCancel>(
11552 WorkDoneProgressCancelParams {
11553 token: token.to_lsp(),
11554 },
11555 )
11556 .ok();
11557 }
11558 }
11559 }
11560 } else if let Some((client, project_id)) = self.upstream_client() {
11561 let request = client.request(proto::CancelLanguageServerWork {
11562 project_id,
11563 work: Some(
11564 proto::cancel_language_server_work::Work::LanguageServerWork(
11565 proto::cancel_language_server_work::LanguageServerWork {
11566 language_server_id: server_id.to_proto(),
11567 token: token_to_cancel.map(|token| token.to_proto()),
11568 },
11569 ),
11570 ),
11571 });
11572 cx.background_spawn(request).detach_and_log_err(cx);
11573 }
11574 }
11575
11576 fn register_supplementary_language_server(
11577 &mut self,
11578 id: LanguageServerId,
11579 name: LanguageServerName,
11580 server: Arc<LanguageServer>,
11581 cx: &mut Context<Self>,
11582 ) {
11583 if let Some(local) = self.as_local_mut() {
11584 local
11585 .supplementary_language_servers
11586 .insert(id, (name.clone(), server));
11587 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11588 }
11589 }
11590
11591 fn unregister_supplementary_language_server(
11592 &mut self,
11593 id: LanguageServerId,
11594 cx: &mut Context<Self>,
11595 ) {
11596 if let Some(local) = self.as_local_mut() {
11597 local.supplementary_language_servers.remove(&id);
11598 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11599 }
11600 }
11601
11602 pub(crate) fn supplementary_language_servers(
11603 &self,
11604 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11605 self.as_local().into_iter().flat_map(|local| {
11606 local
11607 .supplementary_language_servers
11608 .iter()
11609 .map(|(id, (name, _))| (*id, name.clone()))
11610 })
11611 }
11612
11613 pub fn language_server_adapter_for_id(
11614 &self,
11615 id: LanguageServerId,
11616 ) -> Option<Arc<CachedLspAdapter>> {
11617 self.as_local()
11618 .and_then(|local| local.language_servers.get(&id))
11619 .and_then(|language_server_state| match language_server_state {
11620 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11621 _ => None,
11622 })
11623 }
11624
11625 pub(super) fn update_local_worktree_language_servers(
11626 &mut self,
11627 worktree_handle: &Entity<Worktree>,
11628 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11629 cx: &mut Context<Self>,
11630 ) {
11631 if changes.is_empty() {
11632 return;
11633 }
11634
11635 let Some(local) = self.as_local() else { return };
11636
11637 local.prettier_store.update(cx, |prettier_store, cx| {
11638 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11639 });
11640
11641 let worktree_id = worktree_handle.read(cx).id();
11642 let mut language_server_ids = local
11643 .language_server_ids
11644 .iter()
11645 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11646 .collect::<Vec<_>>();
11647 language_server_ids.sort();
11648 language_server_ids.dedup();
11649
11650 // let abs_path = worktree_handle.read(cx).abs_path();
11651 for server_id in &language_server_ids {
11652 if let Some(LanguageServerState::Running { server, .. }) =
11653 local.language_servers.get(server_id)
11654 && let Some(watched_paths) = local
11655 .language_server_watched_paths
11656 .get(server_id)
11657 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11658 {
11659 let params = lsp::DidChangeWatchedFilesParams {
11660 changes: changes
11661 .iter()
11662 .filter_map(|(path, _, change)| {
11663 if !watched_paths.is_match(path.as_std_path()) {
11664 return None;
11665 }
11666 let typ = match change {
11667 PathChange::Loaded => return None,
11668 PathChange::Added => lsp::FileChangeType::CREATED,
11669 PathChange::Removed => lsp::FileChangeType::DELETED,
11670 PathChange::Updated => lsp::FileChangeType::CHANGED,
11671 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11672 };
11673 let uri = lsp::Uri::from_file_path(
11674 worktree_handle.read(cx).absolutize(&path),
11675 )
11676 .ok()?;
11677 Some(lsp::FileEvent { uri, typ })
11678 })
11679 .collect(),
11680 };
11681 if !params.changes.is_empty() {
11682 server
11683 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11684 .ok();
11685 }
11686 }
11687 }
11688 for (path, _, _) in changes {
11689 if let Some(file_name) = path.file_name()
11690 && local.watched_manifest_filenames.contains(file_name)
11691 {
11692 self.request_workspace_config_refresh();
11693 break;
11694 }
11695 }
11696 }
11697
11698 pub fn wait_for_remote_buffer(
11699 &mut self,
11700 id: BufferId,
11701 cx: &mut Context<Self>,
11702 ) -> Task<Result<Entity<Buffer>>> {
11703 self.buffer_store.update(cx, |buffer_store, cx| {
11704 buffer_store.wait_for_remote_buffer(id, cx)
11705 })
11706 }
11707
11708 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11709 let mut result = proto::Symbol {
11710 language_server_name: symbol.language_server_name.0.to_string(),
11711 source_worktree_id: symbol.source_worktree_id.to_proto(),
11712 language_server_id: symbol.source_language_server_id.to_proto(),
11713 name: symbol.name.clone(),
11714 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11715 start: Some(proto::PointUtf16 {
11716 row: symbol.range.start.0.row,
11717 column: symbol.range.start.0.column,
11718 }),
11719 end: Some(proto::PointUtf16 {
11720 row: symbol.range.end.0.row,
11721 column: symbol.range.end.0.column,
11722 }),
11723 worktree_id: Default::default(),
11724 path: Default::default(),
11725 signature: Default::default(),
11726 };
11727 match &symbol.path {
11728 SymbolLocation::InProject(path) => {
11729 result.worktree_id = path.worktree_id.to_proto();
11730 result.path = path.path.to_proto();
11731 }
11732 SymbolLocation::OutsideProject {
11733 abs_path,
11734 signature,
11735 } => {
11736 result.path = abs_path.to_string_lossy().into_owned();
11737 result.signature = signature.to_vec();
11738 }
11739 }
11740 result
11741 }
11742
11743 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11744 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11745 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11746 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11747
11748 let path = if serialized_symbol.signature.is_empty() {
11749 SymbolLocation::InProject(ProjectPath {
11750 worktree_id,
11751 path: RelPath::from_proto(&serialized_symbol.path)
11752 .context("invalid symbol path")?,
11753 })
11754 } else {
11755 SymbolLocation::OutsideProject {
11756 abs_path: Path::new(&serialized_symbol.path).into(),
11757 signature: serialized_symbol
11758 .signature
11759 .try_into()
11760 .map_err(|_| anyhow!("invalid signature"))?,
11761 }
11762 };
11763
11764 let start = serialized_symbol.start.context("invalid start")?;
11765 let end = serialized_symbol.end.context("invalid end")?;
11766 Ok(CoreSymbol {
11767 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11768 source_worktree_id,
11769 source_language_server_id: LanguageServerId::from_proto(
11770 serialized_symbol.language_server_id,
11771 ),
11772 path,
11773 name: serialized_symbol.name,
11774 range: Unclipped(PointUtf16::new(start.row, start.column))
11775 ..Unclipped(PointUtf16::new(end.row, end.column)),
11776 kind,
11777 })
11778 }
11779
11780 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11781 let mut serialized_completion = proto::Completion {
11782 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11783 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11784 new_text: completion.new_text.clone(),
11785 ..proto::Completion::default()
11786 };
11787 match &completion.source {
11788 CompletionSource::Lsp {
11789 insert_range,
11790 server_id,
11791 lsp_completion,
11792 lsp_defaults,
11793 resolved,
11794 } => {
11795 let (old_insert_start, old_insert_end) = insert_range
11796 .as_ref()
11797 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11798 .unzip();
11799
11800 serialized_completion.old_insert_start = old_insert_start;
11801 serialized_completion.old_insert_end = old_insert_end;
11802 serialized_completion.source = proto::completion::Source::Lsp as i32;
11803 serialized_completion.server_id = server_id.0 as u64;
11804 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11805 serialized_completion.lsp_defaults = lsp_defaults
11806 .as_deref()
11807 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11808 serialized_completion.resolved = *resolved;
11809 }
11810 CompletionSource::BufferWord {
11811 word_range,
11812 resolved,
11813 } => {
11814 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11815 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11816 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11817 serialized_completion.resolved = *resolved;
11818 }
11819 CompletionSource::Custom => {
11820 serialized_completion.source = proto::completion::Source::Custom as i32;
11821 serialized_completion.resolved = true;
11822 }
11823 CompletionSource::Dap { sort_text } => {
11824 serialized_completion.source = proto::completion::Source::Dap as i32;
11825 serialized_completion.sort_text = Some(sort_text.clone());
11826 }
11827 }
11828
11829 serialized_completion
11830 }
11831
11832 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11833 let old_replace_start = completion
11834 .old_replace_start
11835 .and_then(deserialize_anchor)
11836 .context("invalid old start")?;
11837 let old_replace_end = completion
11838 .old_replace_end
11839 .and_then(deserialize_anchor)
11840 .context("invalid old end")?;
11841 let insert_range = {
11842 match completion.old_insert_start.zip(completion.old_insert_end) {
11843 Some((start, end)) => {
11844 let start = deserialize_anchor(start).context("invalid insert old start")?;
11845 let end = deserialize_anchor(end).context("invalid insert old end")?;
11846 Some(start..end)
11847 }
11848 None => None,
11849 }
11850 };
11851 Ok(CoreCompletion {
11852 replace_range: old_replace_start..old_replace_end,
11853 new_text: completion.new_text,
11854 source: match proto::completion::Source::from_i32(completion.source) {
11855 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11856 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11857 insert_range,
11858 server_id: LanguageServerId::from_proto(completion.server_id),
11859 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11860 lsp_defaults: completion
11861 .lsp_defaults
11862 .as_deref()
11863 .map(serde_json::from_slice)
11864 .transpose()?,
11865 resolved: completion.resolved,
11866 },
11867 Some(proto::completion::Source::BufferWord) => {
11868 let word_range = completion
11869 .buffer_word_start
11870 .and_then(deserialize_anchor)
11871 .context("invalid buffer word start")?
11872 ..completion
11873 .buffer_word_end
11874 .and_then(deserialize_anchor)
11875 .context("invalid buffer word end")?;
11876 CompletionSource::BufferWord {
11877 word_range,
11878 resolved: completion.resolved,
11879 }
11880 }
11881 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11882 sort_text: completion
11883 .sort_text
11884 .context("expected sort text to exist")?,
11885 },
11886 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11887 },
11888 })
11889 }
11890
11891 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11892 let (kind, lsp_action) = match &action.lsp_action {
11893 LspAction::Action(code_action) => (
11894 proto::code_action::Kind::Action as i32,
11895 serde_json::to_vec(code_action).unwrap(),
11896 ),
11897 LspAction::Command(command) => (
11898 proto::code_action::Kind::Command as i32,
11899 serde_json::to_vec(command).unwrap(),
11900 ),
11901 LspAction::CodeLens(code_lens) => (
11902 proto::code_action::Kind::CodeLens as i32,
11903 serde_json::to_vec(code_lens).unwrap(),
11904 ),
11905 };
11906
11907 proto::CodeAction {
11908 server_id: action.server_id.0 as u64,
11909 start: Some(serialize_anchor(&action.range.start)),
11910 end: Some(serialize_anchor(&action.range.end)),
11911 lsp_action,
11912 kind,
11913 resolved: action.resolved,
11914 }
11915 }
11916
11917 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11918 let start = action
11919 .start
11920 .and_then(deserialize_anchor)
11921 .context("invalid start")?;
11922 let end = action
11923 .end
11924 .and_then(deserialize_anchor)
11925 .context("invalid end")?;
11926 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11927 Some(proto::code_action::Kind::Action) => {
11928 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11929 }
11930 Some(proto::code_action::Kind::Command) => {
11931 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11932 }
11933 Some(proto::code_action::Kind::CodeLens) => {
11934 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11935 }
11936 None => anyhow::bail!("Unknown action kind {}", action.kind),
11937 };
11938 Ok(CodeAction {
11939 server_id: LanguageServerId(action.server_id as usize),
11940 range: start..end,
11941 resolved: action.resolved,
11942 lsp_action,
11943 })
11944 }
11945
11946 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11947 match &formatting_result {
11948 Ok(_) => self.last_formatting_failure = None,
11949 Err(error) => {
11950 let error_string = format!("{error:#}");
11951 log::error!("Formatting failed: {error_string}");
11952 self.last_formatting_failure
11953 .replace(error_string.lines().join(" "));
11954 }
11955 }
11956 }
11957
11958 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11959 self.lsp_server_capabilities.remove(&for_server);
11960 for lsp_data in self.lsp_data.values_mut() {
11961 lsp_data.remove_server_data(for_server);
11962 }
11963 if let Some(local) = self.as_local_mut() {
11964 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11965 local
11966 .workspace_pull_diagnostics_result_ids
11967 .remove(&for_server);
11968 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11969 buffer_servers.remove(&for_server);
11970 }
11971 }
11972 }
11973
11974 pub fn result_id_for_buffer_pull(
11975 &self,
11976 server_id: LanguageServerId,
11977 buffer_id: BufferId,
11978 registration_id: &Option<SharedString>,
11979 cx: &App,
11980 ) -> Option<SharedString> {
11981 let abs_path = self
11982 .buffer_store
11983 .read(cx)
11984 .get(buffer_id)
11985 .and_then(|b| File::from_dyn(b.read(cx).file()))
11986 .map(|f| f.abs_path(cx))?;
11987 self.as_local()?
11988 .buffer_pull_diagnostics_result_ids
11989 .get(&server_id)?
11990 .get(registration_id)?
11991 .get(&abs_path)?
11992 .clone()
11993 }
11994
11995 /// Gets all result_ids for a workspace diagnostics pull request.
11996 /// First, it tries to find buffer's result_id retrieved via the diagnostics pull; if it fails, it falls back to the workspace disagnostics pull result_id.
11997 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
11998 pub fn result_ids_for_workspace_refresh(
11999 &self,
12000 server_id: LanguageServerId,
12001 registration_id: &Option<SharedString>,
12002 ) -> HashMap<PathBuf, SharedString> {
12003 let Some(local) = self.as_local() else {
12004 return HashMap::default();
12005 };
12006 local
12007 .workspace_pull_diagnostics_result_ids
12008 .get(&server_id)
12009 .into_iter()
12010 .filter_map(|diagnostics| diagnostics.get(registration_id))
12011 .flatten()
12012 .filter_map(|(abs_path, result_id)| {
12013 let result_id = local
12014 .buffer_pull_diagnostics_result_ids
12015 .get(&server_id)
12016 .and_then(|buffer_ids_result_ids| {
12017 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12018 })
12019 .cloned()
12020 .flatten()
12021 .or_else(|| result_id.clone())?;
12022 Some((abs_path.clone(), result_id))
12023 })
12024 .collect()
12025 }
12026
12027 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12028 if let Some(LanguageServerState::Running {
12029 workspace_diagnostics_refresh_tasks,
12030 ..
12031 }) = self
12032 .as_local_mut()
12033 .and_then(|local| local.language_servers.get_mut(&server_id))
12034 {
12035 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12036 diagnostics.refresh_tx.try_send(()).ok();
12037 }
12038 }
12039 }
12040
12041 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12042 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12043 return;
12044 };
12045 let Some(local) = self.as_local_mut() else {
12046 return;
12047 };
12048
12049 for server_id in buffer.update(cx, |buffer, cx| {
12050 local.language_server_ids_for_buffer(buffer, cx)
12051 }) {
12052 if let Some(LanguageServerState::Running {
12053 workspace_diagnostics_refresh_tasks,
12054 ..
12055 }) = local.language_servers.get_mut(&server_id)
12056 {
12057 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12058 diagnostics.refresh_tx.try_send(()).ok();
12059 }
12060 }
12061 }
12062 }
12063
12064 fn apply_workspace_diagnostic_report(
12065 &mut self,
12066 server_id: LanguageServerId,
12067 report: lsp::WorkspaceDiagnosticReportResult,
12068 registration_id: Option<SharedString>,
12069 cx: &mut Context<Self>,
12070 ) {
12071 let workspace_diagnostics =
12072 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12073 report,
12074 server_id,
12075 registration_id,
12076 );
12077 let mut unchanged_buffers = HashMap::default();
12078 let workspace_diagnostics_updates = workspace_diagnostics
12079 .into_iter()
12080 .filter_map(
12081 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12082 LspPullDiagnostics::Response {
12083 server_id,
12084 uri,
12085 diagnostics,
12086 registration_id,
12087 } => Some((
12088 server_id,
12089 uri,
12090 diagnostics,
12091 workspace_diagnostics.version,
12092 registration_id,
12093 )),
12094 LspPullDiagnostics::Default => None,
12095 },
12096 )
12097 .fold(
12098 HashMap::default(),
12099 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12100 let (result_id, diagnostics) = match diagnostics {
12101 PulledDiagnostics::Unchanged { result_id } => {
12102 unchanged_buffers
12103 .entry(new_registration_id.clone())
12104 .or_insert_with(HashSet::default)
12105 .insert(uri.clone());
12106 (Some(result_id), Vec::new())
12107 }
12108 PulledDiagnostics::Changed {
12109 result_id,
12110 diagnostics,
12111 } => (result_id, diagnostics),
12112 };
12113 let disk_based_sources = Cow::Owned(
12114 self.language_server_adapter_for_id(server_id)
12115 .as_ref()
12116 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12117 .unwrap_or(&[])
12118 .to_vec(),
12119 );
12120
12121 let Some(abs_path) = uri.to_file_path().ok() else {
12122 return acc;
12123 };
12124 let Some((worktree, relative_path)) =
12125 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12126 else {
12127 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12128 return acc;
12129 };
12130 let worktree_id = worktree.read(cx).id();
12131 let project_path = ProjectPath {
12132 worktree_id,
12133 path: relative_path,
12134 };
12135 if let Some(local_lsp_store) = self.as_local_mut() {
12136 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12137 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12138 }
12139 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12140 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12141 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12142 acc.entry(server_id)
12143 .or_insert_with(HashMap::default)
12144 .entry(new_registration_id.clone())
12145 .or_insert_with(Vec::new)
12146 .push(DocumentDiagnosticsUpdate {
12147 server_id,
12148 diagnostics: lsp::PublishDiagnosticsParams {
12149 uri,
12150 diagnostics,
12151 version,
12152 },
12153 result_id,
12154 disk_based_sources,
12155 registration_id: new_registration_id,
12156 });
12157 }
12158 acc
12159 },
12160 );
12161
12162 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12163 for (registration_id, diagnostic_updates) in diagnostic_updates {
12164 self.merge_lsp_diagnostics(
12165 DiagnosticSourceKind::Pulled,
12166 diagnostic_updates,
12167 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12168 DiagnosticSourceKind::Pulled => {
12169 old_diagnostic.registration_id != registration_id
12170 || unchanged_buffers
12171 .get(&old_diagnostic.registration_id)
12172 .is_some_and(|unchanged_buffers| {
12173 unchanged_buffers.contains(&document_uri)
12174 })
12175 }
12176 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12177 },
12178 cx,
12179 )
12180 .log_err();
12181 }
12182 }
12183 }
12184
12185 fn register_server_capabilities(
12186 &mut self,
12187 server_id: LanguageServerId,
12188 params: lsp::RegistrationParams,
12189 cx: &mut Context<Self>,
12190 ) -> anyhow::Result<()> {
12191 let server = self
12192 .language_server_for_id(server_id)
12193 .with_context(|| format!("no server {server_id} found"))?;
12194 for reg in params.registrations {
12195 match reg.method.as_str() {
12196 "workspace/didChangeWatchedFiles" => {
12197 if let Some(options) = reg.register_options {
12198 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12199 let caps = serde_json::from_value(options)?;
12200 local_lsp_store
12201 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12202 true
12203 } else {
12204 false
12205 };
12206 if notify {
12207 notify_server_capabilities_updated(&server, cx);
12208 }
12209 }
12210 }
12211 "workspace/didChangeConfiguration" => {
12212 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12213 }
12214 "workspace/didChangeWorkspaceFolders" => {
12215 // In this case register options is an empty object, we can ignore it
12216 let caps = lsp::WorkspaceFoldersServerCapabilities {
12217 supported: Some(true),
12218 change_notifications: Some(OneOf::Right(reg.id)),
12219 };
12220 server.update_capabilities(|capabilities| {
12221 capabilities
12222 .workspace
12223 .get_or_insert_default()
12224 .workspace_folders = Some(caps);
12225 });
12226 notify_server_capabilities_updated(&server, cx);
12227 }
12228 "workspace/symbol" => {
12229 let options = parse_register_capabilities(reg)?;
12230 server.update_capabilities(|capabilities| {
12231 capabilities.workspace_symbol_provider = Some(options);
12232 });
12233 notify_server_capabilities_updated(&server, cx);
12234 }
12235 "workspace/fileOperations" => {
12236 if let Some(options) = reg.register_options {
12237 let caps = serde_json::from_value(options)?;
12238 server.update_capabilities(|capabilities| {
12239 capabilities
12240 .workspace
12241 .get_or_insert_default()
12242 .file_operations = Some(caps);
12243 });
12244 notify_server_capabilities_updated(&server, cx);
12245 }
12246 }
12247 "workspace/executeCommand" => {
12248 if let Some(options) = reg.register_options {
12249 let options = serde_json::from_value(options)?;
12250 server.update_capabilities(|capabilities| {
12251 capabilities.execute_command_provider = Some(options);
12252 });
12253 notify_server_capabilities_updated(&server, cx);
12254 }
12255 }
12256 "textDocument/rangeFormatting" => {
12257 let options = parse_register_capabilities(reg)?;
12258 server.update_capabilities(|capabilities| {
12259 capabilities.document_range_formatting_provider = Some(options);
12260 });
12261 notify_server_capabilities_updated(&server, cx);
12262 }
12263 "textDocument/onTypeFormatting" => {
12264 if let Some(options) = reg
12265 .register_options
12266 .map(serde_json::from_value)
12267 .transpose()?
12268 {
12269 server.update_capabilities(|capabilities| {
12270 capabilities.document_on_type_formatting_provider = Some(options);
12271 });
12272 notify_server_capabilities_updated(&server, cx);
12273 }
12274 }
12275 "textDocument/formatting" => {
12276 let options = parse_register_capabilities(reg)?;
12277 server.update_capabilities(|capabilities| {
12278 capabilities.document_formatting_provider = Some(options);
12279 });
12280 notify_server_capabilities_updated(&server, cx);
12281 }
12282 "textDocument/rename" => {
12283 let options = parse_register_capabilities(reg)?;
12284 server.update_capabilities(|capabilities| {
12285 capabilities.rename_provider = Some(options);
12286 });
12287 notify_server_capabilities_updated(&server, cx);
12288 }
12289 "textDocument/inlayHint" => {
12290 let options = parse_register_capabilities(reg)?;
12291 server.update_capabilities(|capabilities| {
12292 capabilities.inlay_hint_provider = Some(options);
12293 });
12294 notify_server_capabilities_updated(&server, cx);
12295 }
12296 "textDocument/documentSymbol" => {
12297 let options = parse_register_capabilities(reg)?;
12298 server.update_capabilities(|capabilities| {
12299 capabilities.document_symbol_provider = Some(options);
12300 });
12301 notify_server_capabilities_updated(&server, cx);
12302 }
12303 "textDocument/codeAction" => {
12304 let options = parse_register_capabilities(reg)?;
12305 let provider = match options {
12306 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12307 OneOf::Right(caps) => caps,
12308 };
12309 server.update_capabilities(|capabilities| {
12310 capabilities.code_action_provider = Some(provider);
12311 });
12312 notify_server_capabilities_updated(&server, cx);
12313 }
12314 "textDocument/definition" => {
12315 let options = parse_register_capabilities(reg)?;
12316 server.update_capabilities(|capabilities| {
12317 capabilities.definition_provider = Some(options);
12318 });
12319 notify_server_capabilities_updated(&server, cx);
12320 }
12321 "textDocument/completion" => {
12322 if let Some(caps) = reg
12323 .register_options
12324 .map(serde_json::from_value::<CompletionOptions>)
12325 .transpose()?
12326 {
12327 server.update_capabilities(|capabilities| {
12328 capabilities.completion_provider = Some(caps.clone());
12329 });
12330
12331 if let Some(local) = self.as_local() {
12332 let mut buffers_with_language_server = Vec::new();
12333 for handle in self.buffer_store.read(cx).buffers() {
12334 let buffer_id = handle.read(cx).remote_id();
12335 if local
12336 .buffers_opened_in_servers
12337 .get(&buffer_id)
12338 .filter(|s| s.contains(&server_id))
12339 .is_some()
12340 {
12341 buffers_with_language_server.push(handle);
12342 }
12343 }
12344 let triggers = caps
12345 .trigger_characters
12346 .unwrap_or_default()
12347 .into_iter()
12348 .collect::<BTreeSet<_>>();
12349 for handle in buffers_with_language_server {
12350 let triggers = triggers.clone();
12351 let _ = handle.update(cx, move |buffer, cx| {
12352 buffer.set_completion_triggers(server_id, triggers, cx);
12353 });
12354 }
12355 }
12356 notify_server_capabilities_updated(&server, cx);
12357 }
12358 }
12359 "textDocument/hover" => {
12360 let options = parse_register_capabilities(reg)?;
12361 let provider = match options {
12362 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12363 OneOf::Right(caps) => caps,
12364 };
12365 server.update_capabilities(|capabilities| {
12366 capabilities.hover_provider = Some(provider);
12367 });
12368 notify_server_capabilities_updated(&server, cx);
12369 }
12370 "textDocument/signatureHelp" => {
12371 if let Some(caps) = reg
12372 .register_options
12373 .map(serde_json::from_value)
12374 .transpose()?
12375 {
12376 server.update_capabilities(|capabilities| {
12377 capabilities.signature_help_provider = Some(caps);
12378 });
12379 notify_server_capabilities_updated(&server, cx);
12380 }
12381 }
12382 "textDocument/didChange" => {
12383 if let Some(sync_kind) = reg
12384 .register_options
12385 .and_then(|opts| opts.get("syncKind").cloned())
12386 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12387 .transpose()?
12388 {
12389 server.update_capabilities(|capabilities| {
12390 let mut sync_options =
12391 Self::take_text_document_sync_options(capabilities);
12392 sync_options.change = Some(sync_kind);
12393 capabilities.text_document_sync =
12394 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12395 });
12396 notify_server_capabilities_updated(&server, cx);
12397 }
12398 }
12399 "textDocument/didSave" => {
12400 if let Some(include_text) = reg
12401 .register_options
12402 .map(|opts| {
12403 let transpose = opts
12404 .get("includeText")
12405 .cloned()
12406 .map(serde_json::from_value::<Option<bool>>)
12407 .transpose();
12408 match transpose {
12409 Ok(value) => Ok(value.flatten()),
12410 Err(e) => Err(e),
12411 }
12412 })
12413 .transpose()?
12414 {
12415 server.update_capabilities(|capabilities| {
12416 let mut sync_options =
12417 Self::take_text_document_sync_options(capabilities);
12418 sync_options.save =
12419 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12420 include_text,
12421 }));
12422 capabilities.text_document_sync =
12423 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12424 });
12425 notify_server_capabilities_updated(&server, cx);
12426 }
12427 }
12428 "textDocument/codeLens" => {
12429 if let Some(caps) = reg
12430 .register_options
12431 .map(serde_json::from_value)
12432 .transpose()?
12433 {
12434 server.update_capabilities(|capabilities| {
12435 capabilities.code_lens_provider = Some(caps);
12436 });
12437 notify_server_capabilities_updated(&server, cx);
12438 }
12439 }
12440 "textDocument/diagnostic" => {
12441 if let Some(caps) = reg
12442 .register_options
12443 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12444 .transpose()?
12445 {
12446 let local = self
12447 .as_local_mut()
12448 .context("Expected LSP Store to be local")?;
12449 let state = local
12450 .language_servers
12451 .get_mut(&server_id)
12452 .context("Could not obtain Language Servers state")?;
12453 local
12454 .language_server_dynamic_registrations
12455 .entry(server_id)
12456 .or_default()
12457 .diagnostics
12458 .insert(Some(reg.id.clone()), caps.clone());
12459
12460 let supports_workspace_diagnostics =
12461 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12462 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12463 diagnostic_options.workspace_diagnostics
12464 }
12465 DiagnosticServerCapabilities::RegistrationOptions(
12466 diagnostic_registration_options,
12467 ) => {
12468 diagnostic_registration_options
12469 .diagnostic_options
12470 .workspace_diagnostics
12471 }
12472 };
12473
12474 if supports_workspace_diagnostics(&caps) {
12475 if let LanguageServerState::Running {
12476 workspace_diagnostics_refresh_tasks,
12477 ..
12478 } = state
12479 && let Some(task) = lsp_workspace_diagnostics_refresh(
12480 Some(reg.id.clone()),
12481 caps.clone(),
12482 server.clone(),
12483 cx,
12484 )
12485 {
12486 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12487 }
12488 }
12489
12490 server.update_capabilities(|capabilities| {
12491 capabilities.diagnostic_provider = Some(caps);
12492 });
12493
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 }
12497 "textDocument/documentColor" => {
12498 let options = parse_register_capabilities(reg)?;
12499 let provider = match options {
12500 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12501 OneOf::Right(caps) => caps,
12502 };
12503 server.update_capabilities(|capabilities| {
12504 capabilities.color_provider = Some(provider);
12505 });
12506 notify_server_capabilities_updated(&server, cx);
12507 }
12508 _ => log::warn!("unhandled capability registration: {reg:?}"),
12509 }
12510 }
12511
12512 Ok(())
12513 }
12514
12515 fn unregister_server_capabilities(
12516 &mut self,
12517 server_id: LanguageServerId,
12518 params: lsp::UnregistrationParams,
12519 cx: &mut Context<Self>,
12520 ) -> anyhow::Result<()> {
12521 let server = self
12522 .language_server_for_id(server_id)
12523 .with_context(|| format!("no server {server_id} found"))?;
12524 for unreg in params.unregisterations.iter() {
12525 match unreg.method.as_str() {
12526 "workspace/didChangeWatchedFiles" => {
12527 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12528 local_lsp_store
12529 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12530 true
12531 } else {
12532 false
12533 };
12534 if notify {
12535 notify_server_capabilities_updated(&server, cx);
12536 }
12537 }
12538 "workspace/didChangeConfiguration" => {
12539 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12540 }
12541 "workspace/didChangeWorkspaceFolders" => {
12542 server.update_capabilities(|capabilities| {
12543 capabilities
12544 .workspace
12545 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12546 workspace_folders: None,
12547 file_operations: None,
12548 })
12549 .workspace_folders = None;
12550 });
12551 notify_server_capabilities_updated(&server, cx);
12552 }
12553 "workspace/symbol" => {
12554 server.update_capabilities(|capabilities| {
12555 capabilities.workspace_symbol_provider = None
12556 });
12557 notify_server_capabilities_updated(&server, cx);
12558 }
12559 "workspace/fileOperations" => {
12560 server.update_capabilities(|capabilities| {
12561 capabilities
12562 .workspace
12563 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12564 workspace_folders: None,
12565 file_operations: None,
12566 })
12567 .file_operations = None;
12568 });
12569 notify_server_capabilities_updated(&server, cx);
12570 }
12571 "workspace/executeCommand" => {
12572 server.update_capabilities(|capabilities| {
12573 capabilities.execute_command_provider = None;
12574 });
12575 notify_server_capabilities_updated(&server, cx);
12576 }
12577 "textDocument/rangeFormatting" => {
12578 server.update_capabilities(|capabilities| {
12579 capabilities.document_range_formatting_provider = None
12580 });
12581 notify_server_capabilities_updated(&server, cx);
12582 }
12583 "textDocument/onTypeFormatting" => {
12584 server.update_capabilities(|capabilities| {
12585 capabilities.document_on_type_formatting_provider = None;
12586 });
12587 notify_server_capabilities_updated(&server, cx);
12588 }
12589 "textDocument/formatting" => {
12590 server.update_capabilities(|capabilities| {
12591 capabilities.document_formatting_provider = None;
12592 });
12593 notify_server_capabilities_updated(&server, cx);
12594 }
12595 "textDocument/rename" => {
12596 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12597 notify_server_capabilities_updated(&server, cx);
12598 }
12599 "textDocument/codeAction" => {
12600 server.update_capabilities(|capabilities| {
12601 capabilities.code_action_provider = None;
12602 });
12603 notify_server_capabilities_updated(&server, cx);
12604 }
12605 "textDocument/definition" => {
12606 server.update_capabilities(|capabilities| {
12607 capabilities.definition_provider = None;
12608 });
12609 notify_server_capabilities_updated(&server, cx);
12610 }
12611 "textDocument/completion" => {
12612 server.update_capabilities(|capabilities| {
12613 capabilities.completion_provider = None;
12614 });
12615 notify_server_capabilities_updated(&server, cx);
12616 }
12617 "textDocument/hover" => {
12618 server.update_capabilities(|capabilities| {
12619 capabilities.hover_provider = None;
12620 });
12621 notify_server_capabilities_updated(&server, cx);
12622 }
12623 "textDocument/signatureHelp" => {
12624 server.update_capabilities(|capabilities| {
12625 capabilities.signature_help_provider = None;
12626 });
12627 notify_server_capabilities_updated(&server, cx);
12628 }
12629 "textDocument/didChange" => {
12630 server.update_capabilities(|capabilities| {
12631 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12632 sync_options.change = None;
12633 capabilities.text_document_sync =
12634 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12635 });
12636 notify_server_capabilities_updated(&server, cx);
12637 }
12638 "textDocument/didSave" => {
12639 server.update_capabilities(|capabilities| {
12640 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12641 sync_options.save = None;
12642 capabilities.text_document_sync =
12643 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12644 });
12645 notify_server_capabilities_updated(&server, cx);
12646 }
12647 "textDocument/codeLens" => {
12648 server.update_capabilities(|capabilities| {
12649 capabilities.code_lens_provider = None;
12650 });
12651 notify_server_capabilities_updated(&server, cx);
12652 }
12653 "textDocument/diagnostic" => {
12654 let local = self
12655 .as_local_mut()
12656 .context("Expected LSP Store to be local")?;
12657
12658 let state = local
12659 .language_servers
12660 .get_mut(&server_id)
12661 .context("Could not obtain Language Servers state")?;
12662 let registrations = local
12663 .language_server_dynamic_registrations
12664 .get_mut(&server_id)
12665 .with_context(|| {
12666 format!("Expected dynamic registration to exist for server {server_id}")
12667 })?;
12668 registrations.diagnostics
12669 .remove(&Some(unreg.id.clone()))
12670 .with_context(|| format!(
12671 "Attempted to unregister non-existent diagnostic registration with ID {}",
12672 unreg.id)
12673 )?;
12674 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12675
12676 if let LanguageServerState::Running {
12677 workspace_diagnostics_refresh_tasks,
12678 ..
12679 } = state
12680 {
12681 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12682 }
12683
12684 if removed_last_diagnostic_provider {
12685 server.update_capabilities(|capabilities| {
12686 debug_assert!(capabilities.diagnostic_provider.is_some());
12687 capabilities.diagnostic_provider = None;
12688 });
12689 }
12690
12691 notify_server_capabilities_updated(&server, cx);
12692 }
12693 "textDocument/documentColor" => {
12694 server.update_capabilities(|capabilities| {
12695 capabilities.color_provider = None;
12696 });
12697 notify_server_capabilities_updated(&server, cx);
12698 }
12699 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12700 }
12701 }
12702
12703 Ok(())
12704 }
12705
12706 async fn deduplicate_range_based_lsp_requests<T>(
12707 lsp_store: &Entity<Self>,
12708 server_id: Option<LanguageServerId>,
12709 lsp_request_id: LspRequestId,
12710 proto_request: &T::ProtoRequest,
12711 range: Range<Anchor>,
12712 cx: &mut AsyncApp,
12713 ) -> Result<()>
12714 where
12715 T: LspCommand,
12716 T::ProtoRequest: proto::LspRequestMessage,
12717 {
12718 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12719 let version = deserialize_version(proto_request.buffer_version());
12720 let buffer = lsp_store.update(cx, |this, cx| {
12721 this.buffer_store.read(cx).get_existing(buffer_id)
12722 })??;
12723 buffer
12724 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12725 .await?;
12726 lsp_store.update(cx, |lsp_store, cx| {
12727 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12728 let chunks_queried_for = lsp_data
12729 .inlay_hints
12730 .applicable_chunks(&[range])
12731 .collect::<Vec<_>>();
12732 match chunks_queried_for.as_slice() {
12733 &[chunk] => {
12734 let key = LspKey {
12735 request_type: TypeId::of::<T>(),
12736 server_queried: server_id,
12737 };
12738 let previous_request = lsp_data
12739 .chunk_lsp_requests
12740 .entry(key)
12741 .or_default()
12742 .insert(chunk, lsp_request_id);
12743 if let Some((previous_request, running_requests)) =
12744 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12745 {
12746 running_requests.remove(&previous_request);
12747 }
12748 }
12749 _ambiguous_chunks => {
12750 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12751 // there, a buffer version-based check will be performed and outdated requests discarded.
12752 }
12753 }
12754 anyhow::Ok(())
12755 })??;
12756
12757 Ok(())
12758 }
12759
12760 async fn query_lsp_locally<T>(
12761 lsp_store: Entity<Self>,
12762 for_server_id: Option<LanguageServerId>,
12763 sender_id: proto::PeerId,
12764 lsp_request_id: LspRequestId,
12765 proto_request: T::ProtoRequest,
12766 position: Option<Anchor>,
12767 cx: &mut AsyncApp,
12768 ) -> Result<()>
12769 where
12770 T: LspCommand + Clone,
12771 T::ProtoRequest: proto::LspRequestMessage,
12772 <T::ProtoRequest as proto::RequestMessage>::Response:
12773 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12774 {
12775 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12776 let version = deserialize_version(proto_request.buffer_version());
12777 let buffer = lsp_store.update(cx, |this, cx| {
12778 this.buffer_store.read(cx).get_existing(buffer_id)
12779 })??;
12780 buffer
12781 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12782 .await?;
12783 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12784 let request =
12785 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12786 let key = LspKey {
12787 request_type: TypeId::of::<T>(),
12788 server_queried: for_server_id,
12789 };
12790 lsp_store.update(cx, |lsp_store, cx| {
12791 let request_task = match for_server_id {
12792 Some(server_id) => {
12793 let server_task = lsp_store.request_lsp(
12794 buffer.clone(),
12795 LanguageServerToQuery::Other(server_id),
12796 request.clone(),
12797 cx,
12798 );
12799 cx.background_spawn(async move {
12800 let mut responses = Vec::new();
12801 match server_task.await {
12802 Ok(response) => responses.push((server_id, response)),
12803 // rust-analyzer likes to error with this when its still loading up
12804 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12805 Err(e) => log::error!(
12806 "Error handling response for request {request:?}: {e:#}"
12807 ),
12808 }
12809 responses
12810 })
12811 }
12812 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12813 };
12814 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12815 if T::ProtoRequest::stop_previous_requests() {
12816 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12817 lsp_requests.clear();
12818 }
12819 }
12820 lsp_data.lsp_requests.entry(key).or_default().insert(
12821 lsp_request_id,
12822 cx.spawn(async move |lsp_store, cx| {
12823 let response = request_task.await;
12824 lsp_store
12825 .update(cx, |lsp_store, cx| {
12826 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12827 {
12828 let response = response
12829 .into_iter()
12830 .map(|(server_id, response)| {
12831 (
12832 server_id.to_proto(),
12833 T::response_to_proto(
12834 response,
12835 lsp_store,
12836 sender_id,
12837 &buffer_version,
12838 cx,
12839 )
12840 .into(),
12841 )
12842 })
12843 .collect::<HashMap<_, _>>();
12844 match client.send_lsp_response::<T::ProtoRequest>(
12845 project_id,
12846 lsp_request_id,
12847 response,
12848 ) {
12849 Ok(()) => {}
12850 Err(e) => {
12851 log::error!("Failed to send LSP response: {e:#}",)
12852 }
12853 }
12854 }
12855 })
12856 .ok();
12857 }),
12858 );
12859 })?;
12860 Ok(())
12861 }
12862
12863 fn take_text_document_sync_options(
12864 capabilities: &mut lsp::ServerCapabilities,
12865 ) -> lsp::TextDocumentSyncOptions {
12866 match capabilities.text_document_sync.take() {
12867 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12868 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12869 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12870 sync_options.change = Some(sync_kind);
12871 sync_options
12872 }
12873 None => lsp::TextDocumentSyncOptions::default(),
12874 }
12875 }
12876
12877 #[cfg(any(test, feature = "test-support"))]
12878 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12879 Some(
12880 self.lsp_data
12881 .get_mut(&buffer_id)?
12882 .code_lens
12883 .take()?
12884 .update
12885 .take()?
12886 .1,
12887 )
12888 }
12889
12890 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12891 self.downstream_client.clone()
12892 }
12893
12894 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12895 self.worktree_store.clone()
12896 }
12897
12898 /// Gets what's stored in the LSP data for the given buffer.
12899 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12900 self.lsp_data.get_mut(&buffer_id)
12901 }
12902
12903 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12904 /// new [`BufferLspData`] will be created to replace the previous state.
12905 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12906 let (buffer_id, buffer_version) =
12907 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12908 let lsp_data = self
12909 .lsp_data
12910 .entry(buffer_id)
12911 .or_insert_with(|| BufferLspData::new(buffer, cx));
12912 if buffer_version.changed_since(&lsp_data.buffer_version) {
12913 *lsp_data = BufferLspData::new(buffer, cx);
12914 }
12915 lsp_data
12916 }
12917}
12918
12919// Registration with registerOptions as null, should fallback to true.
12920// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12921fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12922 reg: lsp::Registration,
12923) -> Result<OneOf<bool, T>> {
12924 Ok(match reg.register_options {
12925 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12926 None => OneOf::Left(true),
12927 })
12928}
12929
12930fn subscribe_to_binary_statuses(
12931 languages: &Arc<LanguageRegistry>,
12932 cx: &mut Context<'_, LspStore>,
12933) -> Task<()> {
12934 let mut server_statuses = languages.language_server_binary_statuses();
12935 cx.spawn(async move |lsp_store, cx| {
12936 while let Some((server_name, binary_status)) = server_statuses.next().await {
12937 if lsp_store
12938 .update(cx, |_, cx| {
12939 let mut message = None;
12940 let binary_status = match binary_status {
12941 BinaryStatus::None => proto::ServerBinaryStatus::None,
12942 BinaryStatus::CheckingForUpdate => {
12943 proto::ServerBinaryStatus::CheckingForUpdate
12944 }
12945 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12946 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12947 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12948 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12949 BinaryStatus::Failed { error } => {
12950 message = Some(error);
12951 proto::ServerBinaryStatus::Failed
12952 }
12953 };
12954 cx.emit(LspStoreEvent::LanguageServerUpdate {
12955 // Binary updates are about the binary that might not have any language server id at that point.
12956 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12957 language_server_id: LanguageServerId(0),
12958 name: Some(server_name),
12959 message: proto::update_language_server::Variant::StatusUpdate(
12960 proto::StatusUpdate {
12961 message,
12962 status: Some(proto::status_update::Status::Binary(
12963 binary_status as i32,
12964 )),
12965 },
12966 ),
12967 });
12968 })
12969 .is_err()
12970 {
12971 break;
12972 }
12973 }
12974 })
12975}
12976
12977fn lsp_workspace_diagnostics_refresh(
12978 registration_id: Option<String>,
12979 options: DiagnosticServerCapabilities,
12980 server: Arc<LanguageServer>,
12981 cx: &mut Context<'_, LspStore>,
12982) -> Option<WorkspaceRefreshTask> {
12983 let identifier = workspace_diagnostic_identifier(&options)?;
12984 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
12985
12986 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12987 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12988 refresh_tx.try_send(()).ok();
12989
12990 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12991 let mut attempts = 0;
12992 let max_attempts = 50;
12993 let mut requests = 0;
12994
12995 loop {
12996 let Some(()) = refresh_rx.recv().await else {
12997 return;
12998 };
12999
13000 'request: loop {
13001 requests += 1;
13002 if attempts > max_attempts {
13003 log::error!(
13004 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13005 );
13006 return;
13007 }
13008 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13009 cx.background_executor()
13010 .timer(Duration::from_millis(backoff_millis))
13011 .await;
13012 attempts += 1;
13013
13014 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13015 lsp_store
13016 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13017 .into_iter()
13018 .filter_map(|(abs_path, result_id)| {
13019 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13020 Some(lsp::PreviousResultId {
13021 uri,
13022 value: result_id.to_string(),
13023 })
13024 })
13025 .collect()
13026 }) else {
13027 return;
13028 };
13029
13030 let token = if let Some(registration_id) = ®istration_id {
13031 format!(
13032 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13033 server.server_id(),
13034 )
13035 } else {
13036 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13037 };
13038
13039 progress_rx.try_recv().ok();
13040 let timer =
13041 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13042 let progress = pin!(progress_rx.recv().fuse());
13043 let response_result = server
13044 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13045 lsp::WorkspaceDiagnosticParams {
13046 previous_result_ids,
13047 identifier: identifier.clone(),
13048 work_done_progress_params: Default::default(),
13049 partial_result_params: lsp::PartialResultParams {
13050 partial_result_token: Some(lsp::ProgressToken::String(token)),
13051 },
13052 },
13053 select(timer, progress).then(|either| match either {
13054 Either::Left((message, ..)) => ready(message).left_future(),
13055 Either::Right(..) => pending::<String>().right_future(),
13056 }),
13057 )
13058 .await;
13059
13060 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13061 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13062 match response_result {
13063 ConnectionResult::Timeout => {
13064 log::error!("Timeout during workspace diagnostics pull");
13065 continue 'request;
13066 }
13067 ConnectionResult::ConnectionReset => {
13068 log::error!("Server closed a workspace diagnostics pull request");
13069 continue 'request;
13070 }
13071 ConnectionResult::Result(Err(e)) => {
13072 log::error!("Error during workspace diagnostics pull: {e:#}");
13073 break 'request;
13074 }
13075 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13076 attempts = 0;
13077 if lsp_store
13078 .update(cx, |lsp_store, cx| {
13079 lsp_store.apply_workspace_diagnostic_report(
13080 server.server_id(),
13081 pulled_diagnostics,
13082 registration_id_shared.clone(),
13083 cx,
13084 )
13085 })
13086 .is_err()
13087 {
13088 return;
13089 }
13090 break 'request;
13091 }
13092 }
13093 }
13094 }
13095 });
13096
13097 Some(WorkspaceRefreshTask {
13098 refresh_tx,
13099 progress_tx,
13100 task: workspace_query_language_server,
13101 })
13102}
13103
13104fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13105 match &options {
13106 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13107 diagnostic_options.identifier.clone()
13108 }
13109 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13110 let diagnostic_options = ®istration_options.diagnostic_options;
13111 diagnostic_options.identifier.clone()
13112 }
13113 }
13114}
13115
13116fn workspace_diagnostic_identifier(
13117 options: &DiagnosticServerCapabilities,
13118) -> Option<Option<String>> {
13119 match &options {
13120 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13121 if !diagnostic_options.workspace_diagnostics {
13122 return None;
13123 }
13124 Some(diagnostic_options.identifier.clone())
13125 }
13126 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13127 let diagnostic_options = ®istration_options.diagnostic_options;
13128 if !diagnostic_options.workspace_diagnostics {
13129 return None;
13130 }
13131 Some(diagnostic_options.identifier.clone())
13132 }
13133 }
13134}
13135
13136fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13137 let CompletionSource::BufferWord {
13138 word_range,
13139 resolved,
13140 } = &mut completion.source
13141 else {
13142 return;
13143 };
13144 if *resolved {
13145 return;
13146 }
13147
13148 if completion.new_text
13149 != snapshot
13150 .text_for_range(word_range.clone())
13151 .collect::<String>()
13152 {
13153 return;
13154 }
13155
13156 let mut offset = 0;
13157 for chunk in snapshot.chunks(word_range.clone(), true) {
13158 let end_offset = offset + chunk.text.len();
13159 if let Some(highlight_id) = chunk.syntax_highlight_id {
13160 completion
13161 .label
13162 .runs
13163 .push((offset..end_offset, highlight_id));
13164 }
13165 offset = end_offset;
13166 }
13167 *resolved = true;
13168}
13169
13170impl EventEmitter<LspStoreEvent> for LspStore {}
13171
13172fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13173 hover
13174 .contents
13175 .retain(|hover_block| !hover_block.text.trim().is_empty());
13176 if hover.contents.is_empty() {
13177 None
13178 } else {
13179 Some(hover)
13180 }
13181}
13182
13183async fn populate_labels_for_completions(
13184 new_completions: Vec<CoreCompletion>,
13185 language: Option<Arc<Language>>,
13186 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13187) -> Vec<Completion> {
13188 let lsp_completions = new_completions
13189 .iter()
13190 .filter_map(|new_completion| {
13191 new_completion
13192 .source
13193 .lsp_completion(true)
13194 .map(|lsp_completion| lsp_completion.into_owned())
13195 })
13196 .collect::<Vec<_>>();
13197
13198 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13199 lsp_adapter
13200 .labels_for_completions(&lsp_completions, language)
13201 .await
13202 .log_err()
13203 .unwrap_or_default()
13204 } else {
13205 Vec::new()
13206 }
13207 .into_iter()
13208 .fuse();
13209
13210 let mut completions = Vec::new();
13211 for completion in new_completions {
13212 match completion.source.lsp_completion(true) {
13213 Some(lsp_completion) => {
13214 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13215
13216 let mut label = labels.next().flatten().unwrap_or_else(|| {
13217 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13218 });
13219 ensure_uniform_list_compatible_label(&mut label);
13220 completions.push(Completion {
13221 label,
13222 documentation,
13223 replace_range: completion.replace_range,
13224 new_text: completion.new_text,
13225 insert_text_mode: lsp_completion.insert_text_mode,
13226 source: completion.source,
13227 icon_path: None,
13228 confirm: None,
13229 match_start: None,
13230 snippet_deduplication_key: None,
13231 });
13232 }
13233 None => {
13234 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13235 ensure_uniform_list_compatible_label(&mut label);
13236 completions.push(Completion {
13237 label,
13238 documentation: None,
13239 replace_range: completion.replace_range,
13240 new_text: completion.new_text,
13241 source: completion.source,
13242 insert_text_mode: None,
13243 icon_path: None,
13244 confirm: None,
13245 match_start: None,
13246 snippet_deduplication_key: None,
13247 });
13248 }
13249 }
13250 }
13251 completions
13252}
13253
13254#[derive(Debug)]
13255pub enum LanguageServerToQuery {
13256 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13257 FirstCapable,
13258 /// Query a specific language server.
13259 Other(LanguageServerId),
13260}
13261
13262#[derive(Default)]
13263struct RenamePathsWatchedForServer {
13264 did_rename: Vec<RenameActionPredicate>,
13265 will_rename: Vec<RenameActionPredicate>,
13266}
13267
13268impl RenamePathsWatchedForServer {
13269 fn with_did_rename_patterns(
13270 mut self,
13271 did_rename: Option<&FileOperationRegistrationOptions>,
13272 ) -> Self {
13273 if let Some(did_rename) = did_rename {
13274 self.did_rename = did_rename
13275 .filters
13276 .iter()
13277 .filter_map(|filter| filter.try_into().log_err())
13278 .collect();
13279 }
13280 self
13281 }
13282 fn with_will_rename_patterns(
13283 mut self,
13284 will_rename: Option<&FileOperationRegistrationOptions>,
13285 ) -> Self {
13286 if let Some(will_rename) = will_rename {
13287 self.will_rename = will_rename
13288 .filters
13289 .iter()
13290 .filter_map(|filter| filter.try_into().log_err())
13291 .collect();
13292 }
13293 self
13294 }
13295
13296 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13297 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13298 }
13299 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13300 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13301 }
13302}
13303
13304impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13305 type Error = globset::Error;
13306 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13307 Ok(Self {
13308 kind: ops.pattern.matches.clone(),
13309 glob: GlobBuilder::new(&ops.pattern.glob)
13310 .case_insensitive(
13311 ops.pattern
13312 .options
13313 .as_ref()
13314 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13315 )
13316 .build()?
13317 .compile_matcher(),
13318 })
13319 }
13320}
13321struct RenameActionPredicate {
13322 glob: GlobMatcher,
13323 kind: Option<FileOperationPatternKind>,
13324}
13325
13326impl RenameActionPredicate {
13327 // Returns true if language server should be notified
13328 fn eval(&self, path: &str, is_dir: bool) -> bool {
13329 self.kind.as_ref().is_none_or(|kind| {
13330 let expected_kind = if is_dir {
13331 FileOperationPatternKind::Folder
13332 } else {
13333 FileOperationPatternKind::File
13334 };
13335 kind == &expected_kind
13336 }) && self.glob.is_match(path)
13337 }
13338}
13339
13340#[derive(Default)]
13341struct LanguageServerWatchedPaths {
13342 worktree_paths: HashMap<WorktreeId, GlobSet>,
13343 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13344}
13345
13346#[derive(Default)]
13347struct LanguageServerWatchedPathsBuilder {
13348 worktree_paths: HashMap<WorktreeId, GlobSet>,
13349 abs_paths: HashMap<Arc<Path>, GlobSet>,
13350}
13351
13352impl LanguageServerWatchedPathsBuilder {
13353 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13354 self.worktree_paths.insert(worktree_id, glob_set);
13355 }
13356 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13357 self.abs_paths.insert(path, glob_set);
13358 }
13359 fn build(
13360 self,
13361 fs: Arc<dyn Fs>,
13362 language_server_id: LanguageServerId,
13363 cx: &mut Context<LspStore>,
13364 ) -> LanguageServerWatchedPaths {
13365 let lsp_store = cx.weak_entity();
13366
13367 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13368 let abs_paths = self
13369 .abs_paths
13370 .into_iter()
13371 .map(|(abs_path, globset)| {
13372 let task = cx.spawn({
13373 let abs_path = abs_path.clone();
13374 let fs = fs.clone();
13375
13376 let lsp_store = lsp_store.clone();
13377 async move |_, cx| {
13378 maybe!(async move {
13379 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13380 while let Some(update) = push_updates.0.next().await {
13381 let action = lsp_store
13382 .update(cx, |this, _| {
13383 let Some(local) = this.as_local() else {
13384 return ControlFlow::Break(());
13385 };
13386 let Some(watcher) = local
13387 .language_server_watched_paths
13388 .get(&language_server_id)
13389 else {
13390 return ControlFlow::Break(());
13391 };
13392 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13393 "Watched abs path is not registered with a watcher",
13394 );
13395 let matching_entries = update
13396 .into_iter()
13397 .filter(|event| globs.is_match(&event.path))
13398 .collect::<Vec<_>>();
13399 this.lsp_notify_abs_paths_changed(
13400 language_server_id,
13401 matching_entries,
13402 );
13403 ControlFlow::Continue(())
13404 })
13405 .ok()?;
13406
13407 if action.is_break() {
13408 break;
13409 }
13410 }
13411 Some(())
13412 })
13413 .await;
13414 }
13415 });
13416 (abs_path, (globset, task))
13417 })
13418 .collect();
13419 LanguageServerWatchedPaths {
13420 worktree_paths: self.worktree_paths,
13421 abs_paths,
13422 }
13423 }
13424}
13425
13426struct LspBufferSnapshot {
13427 version: i32,
13428 snapshot: TextBufferSnapshot,
13429}
13430
13431/// A prompt requested by LSP server.
13432#[derive(Clone, Debug)]
13433pub struct LanguageServerPromptRequest {
13434 pub level: PromptLevel,
13435 pub message: String,
13436 pub actions: Vec<MessageActionItem>,
13437 pub lsp_name: String,
13438 pub(crate) response_channel: Sender<MessageActionItem>,
13439}
13440
13441impl LanguageServerPromptRequest {
13442 pub async fn respond(self, index: usize) -> Option<()> {
13443 if let Some(response) = self.actions.into_iter().nth(index) {
13444 self.response_channel.send(response).await.ok()
13445 } else {
13446 None
13447 }
13448 }
13449}
13450impl PartialEq for LanguageServerPromptRequest {
13451 fn eq(&self, other: &Self) -> bool {
13452 self.message == other.message && self.actions == other.actions
13453 }
13454}
13455
13456#[derive(Clone, Debug, PartialEq)]
13457pub enum LanguageServerLogType {
13458 Log(MessageType),
13459 Trace { verbose_info: Option<String> },
13460 Rpc { received: bool },
13461}
13462
13463impl LanguageServerLogType {
13464 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13465 match self {
13466 Self::Log(log_type) => {
13467 use proto::log_message::LogLevel;
13468 let level = match *log_type {
13469 MessageType::ERROR => LogLevel::Error,
13470 MessageType::WARNING => LogLevel::Warning,
13471 MessageType::INFO => LogLevel::Info,
13472 MessageType::LOG => LogLevel::Log,
13473 other => {
13474 log::warn!("Unknown lsp log message type: {other:?}");
13475 LogLevel::Log
13476 }
13477 };
13478 proto::language_server_log::LogType::Log(proto::LogMessage {
13479 level: level as i32,
13480 })
13481 }
13482 Self::Trace { verbose_info } => {
13483 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13484 verbose_info: verbose_info.to_owned(),
13485 })
13486 }
13487 Self::Rpc { received } => {
13488 let kind = if *received {
13489 proto::rpc_message::Kind::Received
13490 } else {
13491 proto::rpc_message::Kind::Sent
13492 };
13493 let kind = kind as i32;
13494 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13495 }
13496 }
13497 }
13498
13499 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13500 use proto::log_message::LogLevel;
13501 use proto::rpc_message;
13502 match log_type {
13503 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13504 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13505 LogLevel::Error => MessageType::ERROR,
13506 LogLevel::Warning => MessageType::WARNING,
13507 LogLevel::Info => MessageType::INFO,
13508 LogLevel::Log => MessageType::LOG,
13509 },
13510 ),
13511 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13512 verbose_info: trace_message.verbose_info,
13513 },
13514 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13515 received: match rpc_message::Kind::from_i32(message.kind)
13516 .unwrap_or(rpc_message::Kind::Received)
13517 {
13518 rpc_message::Kind::Received => true,
13519 rpc_message::Kind::Sent => false,
13520 },
13521 },
13522 }
13523 }
13524}
13525
13526pub struct WorkspaceRefreshTask {
13527 refresh_tx: mpsc::Sender<()>,
13528 progress_tx: mpsc::Sender<()>,
13529 #[allow(dead_code)]
13530 task: Task<()>,
13531}
13532
13533pub enum LanguageServerState {
13534 Starting {
13535 startup: Task<Option<Arc<LanguageServer>>>,
13536 /// List of language servers that will be added to the workspace once it's initialization completes.
13537 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13538 },
13539
13540 Running {
13541 adapter: Arc<CachedLspAdapter>,
13542 server: Arc<LanguageServer>,
13543 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13544 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13545 },
13546}
13547
13548impl LanguageServerState {
13549 fn add_workspace_folder(&self, uri: Uri) {
13550 match self {
13551 LanguageServerState::Starting {
13552 pending_workspace_folders,
13553 ..
13554 } => {
13555 pending_workspace_folders.lock().insert(uri);
13556 }
13557 LanguageServerState::Running { server, .. } => {
13558 server.add_workspace_folder(uri);
13559 }
13560 }
13561 }
13562 fn _remove_workspace_folder(&self, uri: Uri) {
13563 match self {
13564 LanguageServerState::Starting {
13565 pending_workspace_folders,
13566 ..
13567 } => {
13568 pending_workspace_folders.lock().remove(&uri);
13569 }
13570 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13571 }
13572 }
13573}
13574
13575impl std::fmt::Debug for LanguageServerState {
13576 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13577 match self {
13578 LanguageServerState::Starting { .. } => {
13579 f.debug_struct("LanguageServerState::Starting").finish()
13580 }
13581 LanguageServerState::Running { .. } => {
13582 f.debug_struct("LanguageServerState::Running").finish()
13583 }
13584 }
13585 }
13586}
13587
13588#[derive(Clone, Debug, Serialize)]
13589pub struct LanguageServerProgress {
13590 pub is_disk_based_diagnostics_progress: bool,
13591 pub is_cancellable: bool,
13592 pub title: Option<String>,
13593 pub message: Option<String>,
13594 pub percentage: Option<usize>,
13595 #[serde(skip_serializing)]
13596 pub last_update_at: Instant,
13597}
13598
13599#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13600pub struct DiagnosticSummary {
13601 pub error_count: usize,
13602 pub warning_count: usize,
13603}
13604
13605impl DiagnosticSummary {
13606 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13607 let mut this = Self {
13608 error_count: 0,
13609 warning_count: 0,
13610 };
13611
13612 for entry in diagnostics {
13613 if entry.diagnostic.is_primary {
13614 match entry.diagnostic.severity {
13615 DiagnosticSeverity::ERROR => this.error_count += 1,
13616 DiagnosticSeverity::WARNING => this.warning_count += 1,
13617 _ => {}
13618 }
13619 }
13620 }
13621
13622 this
13623 }
13624
13625 pub fn is_empty(&self) -> bool {
13626 self.error_count == 0 && self.warning_count == 0
13627 }
13628
13629 pub fn to_proto(
13630 self,
13631 language_server_id: LanguageServerId,
13632 path: &RelPath,
13633 ) -> proto::DiagnosticSummary {
13634 proto::DiagnosticSummary {
13635 path: path.to_proto(),
13636 language_server_id: language_server_id.0 as u64,
13637 error_count: self.error_count as u32,
13638 warning_count: self.warning_count as u32,
13639 }
13640 }
13641}
13642
13643#[derive(Clone, Debug)]
13644pub enum CompletionDocumentation {
13645 /// There is no documentation for this completion.
13646 Undocumented,
13647 /// A single line of documentation.
13648 SingleLine(SharedString),
13649 /// Multiple lines of plain text documentation.
13650 MultiLinePlainText(SharedString),
13651 /// Markdown documentation.
13652 MultiLineMarkdown(SharedString),
13653 /// Both single line and multiple lines of plain text documentation.
13654 SingleLineAndMultiLinePlainText {
13655 single_line: SharedString,
13656 plain_text: Option<SharedString>,
13657 },
13658}
13659
13660impl CompletionDocumentation {
13661 #[cfg(any(test, feature = "test-support"))]
13662 pub fn text(&self) -> SharedString {
13663 match self {
13664 CompletionDocumentation::Undocumented => "".into(),
13665 CompletionDocumentation::SingleLine(s) => s.clone(),
13666 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13667 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13668 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13669 single_line.clone()
13670 }
13671 }
13672 }
13673}
13674
13675impl From<lsp::Documentation> for CompletionDocumentation {
13676 fn from(docs: lsp::Documentation) -> Self {
13677 match docs {
13678 lsp::Documentation::String(text) => {
13679 if text.lines().count() <= 1 {
13680 CompletionDocumentation::SingleLine(text.into())
13681 } else {
13682 CompletionDocumentation::MultiLinePlainText(text.into())
13683 }
13684 }
13685
13686 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13687 lsp::MarkupKind::PlainText => {
13688 if value.lines().count() <= 1 {
13689 CompletionDocumentation::SingleLine(value.into())
13690 } else {
13691 CompletionDocumentation::MultiLinePlainText(value.into())
13692 }
13693 }
13694
13695 lsp::MarkupKind::Markdown => {
13696 CompletionDocumentation::MultiLineMarkdown(value.into())
13697 }
13698 },
13699 }
13700 }
13701}
13702
13703pub enum ResolvedHint {
13704 Resolved(InlayHint),
13705 Resolving(Shared<Task<()>>),
13706}
13707
13708fn glob_literal_prefix(glob: &Path) -> PathBuf {
13709 glob.components()
13710 .take_while(|component| match component {
13711 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13712 _ => true,
13713 })
13714 .collect()
13715}
13716
13717pub struct SshLspAdapter {
13718 name: LanguageServerName,
13719 binary: LanguageServerBinary,
13720 initialization_options: Option<String>,
13721 code_action_kinds: Option<Vec<CodeActionKind>>,
13722}
13723
13724impl SshLspAdapter {
13725 pub fn new(
13726 name: LanguageServerName,
13727 binary: LanguageServerBinary,
13728 initialization_options: Option<String>,
13729 code_action_kinds: Option<String>,
13730 ) -> Self {
13731 Self {
13732 name,
13733 binary,
13734 initialization_options,
13735 code_action_kinds: code_action_kinds
13736 .as_ref()
13737 .and_then(|c| serde_json::from_str(c).ok()),
13738 }
13739 }
13740}
13741
13742impl LspInstaller for SshLspAdapter {
13743 type BinaryVersion = ();
13744 async fn check_if_user_installed(
13745 &self,
13746 _: &dyn LspAdapterDelegate,
13747 _: Option<Toolchain>,
13748 _: &AsyncApp,
13749 ) -> Option<LanguageServerBinary> {
13750 Some(self.binary.clone())
13751 }
13752
13753 async fn cached_server_binary(
13754 &self,
13755 _: PathBuf,
13756 _: &dyn LspAdapterDelegate,
13757 ) -> Option<LanguageServerBinary> {
13758 None
13759 }
13760
13761 async fn fetch_latest_server_version(
13762 &self,
13763 _: &dyn LspAdapterDelegate,
13764 _: bool,
13765 _: &mut AsyncApp,
13766 ) -> Result<()> {
13767 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13768 }
13769
13770 async fn fetch_server_binary(
13771 &self,
13772 _: (),
13773 _: PathBuf,
13774 _: &dyn LspAdapterDelegate,
13775 ) -> Result<LanguageServerBinary> {
13776 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13777 }
13778}
13779
13780#[async_trait(?Send)]
13781impl LspAdapter for SshLspAdapter {
13782 fn name(&self) -> LanguageServerName {
13783 self.name.clone()
13784 }
13785
13786 async fn initialization_options(
13787 self: Arc<Self>,
13788 _: &Arc<dyn LspAdapterDelegate>,
13789 ) -> Result<Option<serde_json::Value>> {
13790 let Some(options) = &self.initialization_options else {
13791 return Ok(None);
13792 };
13793 let result = serde_json::from_str(options)?;
13794 Ok(result)
13795 }
13796
13797 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13798 self.code_action_kinds.clone()
13799 }
13800}
13801
13802pub fn language_server_settings<'a>(
13803 delegate: &'a dyn LspAdapterDelegate,
13804 language: &LanguageServerName,
13805 cx: &'a App,
13806) -> Option<&'a LspSettings> {
13807 language_server_settings_for(
13808 SettingsLocation {
13809 worktree_id: delegate.worktree_id(),
13810 path: RelPath::empty(),
13811 },
13812 language,
13813 cx,
13814 )
13815}
13816
13817pub fn language_server_settings_for<'a>(
13818 location: SettingsLocation<'a>,
13819 language: &LanguageServerName,
13820 cx: &'a App,
13821) -> Option<&'a LspSettings> {
13822 ProjectSettings::get(Some(location), cx).lsp.get(language)
13823}
13824
13825pub struct LocalLspAdapterDelegate {
13826 lsp_store: WeakEntity<LspStore>,
13827 worktree: worktree::Snapshot,
13828 fs: Arc<dyn Fs>,
13829 http_client: Arc<dyn HttpClient>,
13830 language_registry: Arc<LanguageRegistry>,
13831 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13832}
13833
13834impl LocalLspAdapterDelegate {
13835 pub fn new(
13836 language_registry: Arc<LanguageRegistry>,
13837 environment: &Entity<ProjectEnvironment>,
13838 lsp_store: WeakEntity<LspStore>,
13839 worktree: &Entity<Worktree>,
13840 http_client: Arc<dyn HttpClient>,
13841 fs: Arc<dyn Fs>,
13842 cx: &mut App,
13843 ) -> Arc<Self> {
13844 let load_shell_env_task =
13845 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13846
13847 Arc::new(Self {
13848 lsp_store,
13849 worktree: worktree.read(cx).snapshot(),
13850 fs,
13851 http_client,
13852 language_registry,
13853 load_shell_env_task,
13854 })
13855 }
13856
13857 fn from_local_lsp(
13858 local: &LocalLspStore,
13859 worktree: &Entity<Worktree>,
13860 cx: &mut App,
13861 ) -> Arc<Self> {
13862 Self::new(
13863 local.languages.clone(),
13864 &local.environment,
13865 local.weak.clone(),
13866 worktree,
13867 local.http_client.clone(),
13868 local.fs.clone(),
13869 cx,
13870 )
13871 }
13872}
13873
13874#[async_trait]
13875impl LspAdapterDelegate for LocalLspAdapterDelegate {
13876 fn show_notification(&self, message: &str, cx: &mut App) {
13877 self.lsp_store
13878 .update(cx, |_, cx| {
13879 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13880 })
13881 .ok();
13882 }
13883
13884 fn http_client(&self) -> Arc<dyn HttpClient> {
13885 self.http_client.clone()
13886 }
13887
13888 fn worktree_id(&self) -> WorktreeId {
13889 self.worktree.id()
13890 }
13891
13892 fn worktree_root_path(&self) -> &Path {
13893 self.worktree.abs_path().as_ref()
13894 }
13895
13896 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13897 self.worktree.resolve_executable_path(path)
13898 }
13899
13900 async fn shell_env(&self) -> HashMap<String, String> {
13901 let task = self.load_shell_env_task.clone();
13902 task.await.unwrap_or_default()
13903 }
13904
13905 async fn npm_package_installed_version(
13906 &self,
13907 package_name: &str,
13908 ) -> Result<Option<(PathBuf, String)>> {
13909 let local_package_directory = self.worktree_root_path();
13910 let node_modules_directory = local_package_directory.join("node_modules");
13911
13912 if let Some(version) =
13913 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13914 {
13915 return Ok(Some((node_modules_directory, version)));
13916 }
13917 let Some(npm) = self.which("npm".as_ref()).await else {
13918 log::warn!(
13919 "Failed to find npm executable for {:?}",
13920 local_package_directory
13921 );
13922 return Ok(None);
13923 };
13924
13925 let env = self.shell_env().await;
13926 let output = util::command::new_smol_command(&npm)
13927 .args(["root", "-g"])
13928 .envs(env)
13929 .current_dir(local_package_directory)
13930 .output()
13931 .await?;
13932 let global_node_modules =
13933 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13934
13935 if let Some(version) =
13936 read_package_installed_version(global_node_modules.clone(), package_name).await?
13937 {
13938 return Ok(Some((global_node_modules, version)));
13939 }
13940 return Ok(None);
13941 }
13942
13943 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13944 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13945 if self.fs.is_file(&worktree_abs_path).await {
13946 worktree_abs_path.pop();
13947 }
13948
13949 let env = self.shell_env().await;
13950
13951 let shell_path = env.get("PATH").cloned();
13952
13953 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13954 }
13955
13956 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13957 let mut working_dir = self.worktree_root_path().to_path_buf();
13958 if self.fs.is_file(&working_dir).await {
13959 working_dir.pop();
13960 }
13961 let output = util::command::new_smol_command(&command.path)
13962 .args(command.arguments)
13963 .envs(command.env.clone().unwrap_or_default())
13964 .current_dir(working_dir)
13965 .output()
13966 .await?;
13967
13968 anyhow::ensure!(
13969 output.status.success(),
13970 "{}, stdout: {:?}, stderr: {:?}",
13971 output.status,
13972 String::from_utf8_lossy(&output.stdout),
13973 String::from_utf8_lossy(&output.stderr)
13974 );
13975 Ok(())
13976 }
13977
13978 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13979 self.language_registry
13980 .update_lsp_binary_status(server_name, status);
13981 }
13982
13983 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13984 self.language_registry
13985 .all_lsp_adapters()
13986 .into_iter()
13987 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13988 .collect()
13989 }
13990
13991 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13992 let dir = self.language_registry.language_server_download_dir(name)?;
13993
13994 if !dir.exists() {
13995 smol::fs::create_dir_all(&dir)
13996 .await
13997 .context("failed to create container directory")
13998 .log_err()?;
13999 }
14000
14001 Some(dir)
14002 }
14003
14004 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14005 let entry = self
14006 .worktree
14007 .entry_for_path(path)
14008 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14009 let abs_path = self.worktree.absolutize(&entry.path);
14010 self.fs.load(&abs_path).await
14011 }
14012}
14013
14014async fn populate_labels_for_symbols(
14015 symbols: Vec<CoreSymbol>,
14016 language_registry: &Arc<LanguageRegistry>,
14017 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14018 output: &mut Vec<Symbol>,
14019) {
14020 #[allow(clippy::mutable_key_type)]
14021 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14022
14023 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14024 for symbol in symbols {
14025 let Some(file_name) = symbol.path.file_name() else {
14026 continue;
14027 };
14028 let language = language_registry
14029 .load_language_for_file_path(Path::new(file_name))
14030 .await
14031 .ok()
14032 .or_else(|| {
14033 unknown_paths.insert(file_name.into());
14034 None
14035 });
14036 symbols_by_language
14037 .entry(language)
14038 .or_default()
14039 .push(symbol);
14040 }
14041
14042 for unknown_path in unknown_paths {
14043 log::info!("no language found for symbol in file {unknown_path:?}");
14044 }
14045
14046 let mut label_params = Vec::new();
14047 for (language, mut symbols) in symbols_by_language {
14048 label_params.clear();
14049 label_params.extend(
14050 symbols
14051 .iter_mut()
14052 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14053 );
14054
14055 let mut labels = Vec::new();
14056 if let Some(language) = language {
14057 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14058 language_registry
14059 .lsp_adapters(&language.name())
14060 .first()
14061 .cloned()
14062 });
14063 if let Some(lsp_adapter) = lsp_adapter {
14064 labels = lsp_adapter
14065 .labels_for_symbols(&label_params, &language)
14066 .await
14067 .log_err()
14068 .unwrap_or_default();
14069 }
14070 }
14071
14072 for ((symbol, (name, _)), label) in symbols
14073 .into_iter()
14074 .zip(label_params.drain(..))
14075 .zip(labels.into_iter().chain(iter::repeat(None)))
14076 {
14077 output.push(Symbol {
14078 language_server_name: symbol.language_server_name,
14079 source_worktree_id: symbol.source_worktree_id,
14080 source_language_server_id: symbol.source_language_server_id,
14081 path: symbol.path,
14082 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14083 name,
14084 kind: symbol.kind,
14085 range: symbol.range,
14086 });
14087 }
14088 }
14089}
14090
14091fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14092 match server.capabilities().text_document_sync.as_ref()? {
14093 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14094 // Server wants didSave but didn't specify includeText.
14095 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14096 // Server doesn't want didSave at all.
14097 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14098 // Server provided SaveOptions.
14099 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14100 Some(save_options.include_text.unwrap_or(false))
14101 }
14102 },
14103 // We do not have any save info. Kind affects didChange only.
14104 lsp::TextDocumentSyncCapability::Kind(_) => None,
14105 }
14106}
14107
14108/// Completion items are displayed in a `UniformList`.
14109/// Usually, those items are single-line strings, but in LSP responses,
14110/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14111/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14112/// 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,
14113/// breaking the completions menu presentation.
14114///
14115/// 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.
14116fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14117 let mut new_text = String::with_capacity(label.text.len());
14118 let mut offset_map = vec![0; label.text.len() + 1];
14119 let mut last_char_was_space = false;
14120 let mut new_idx = 0;
14121 let chars = label.text.char_indices().fuse();
14122 let mut newlines_removed = false;
14123
14124 for (idx, c) in chars {
14125 offset_map[idx] = new_idx;
14126
14127 match c {
14128 '\n' if last_char_was_space => {
14129 newlines_removed = true;
14130 }
14131 '\t' | ' ' if last_char_was_space => {}
14132 '\n' if !last_char_was_space => {
14133 new_text.push(' ');
14134 new_idx += 1;
14135 last_char_was_space = true;
14136 newlines_removed = true;
14137 }
14138 ' ' | '\t' => {
14139 new_text.push(' ');
14140 new_idx += 1;
14141 last_char_was_space = true;
14142 }
14143 _ => {
14144 new_text.push(c);
14145 new_idx += c.len_utf8();
14146 last_char_was_space = false;
14147 }
14148 }
14149 }
14150 offset_map[label.text.len()] = new_idx;
14151
14152 // Only modify the label if newlines were removed.
14153 if !newlines_removed {
14154 return;
14155 }
14156
14157 let last_index = new_idx;
14158 let mut run_ranges_errors = Vec::new();
14159 label.runs.retain_mut(|(range, _)| {
14160 match offset_map.get(range.start) {
14161 Some(&start) => range.start = start,
14162 None => {
14163 run_ranges_errors.push(range.clone());
14164 return false;
14165 }
14166 }
14167
14168 match offset_map.get(range.end) {
14169 Some(&end) => range.end = end,
14170 None => {
14171 run_ranges_errors.push(range.clone());
14172 range.end = last_index;
14173 }
14174 }
14175 true
14176 });
14177 if !run_ranges_errors.is_empty() {
14178 log::error!(
14179 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14180 label.text
14181 );
14182 }
14183
14184 let mut wrong_filter_range = None;
14185 if label.filter_range == (0..label.text.len()) {
14186 label.filter_range = 0..new_text.len();
14187 } else {
14188 let mut original_filter_range = Some(label.filter_range.clone());
14189 match offset_map.get(label.filter_range.start) {
14190 Some(&start) => label.filter_range.start = start,
14191 None => {
14192 wrong_filter_range = original_filter_range.take();
14193 label.filter_range.start = last_index;
14194 }
14195 }
14196
14197 match offset_map.get(label.filter_range.end) {
14198 Some(&end) => label.filter_range.end = end,
14199 None => {
14200 wrong_filter_range = original_filter_range.take();
14201 label.filter_range.end = last_index;
14202 }
14203 }
14204 }
14205 if let Some(wrong_filter_range) = wrong_filter_range {
14206 log::error!(
14207 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14208 label.text
14209 );
14210 }
14211
14212 label.text = new_text;
14213}
14214
14215#[cfg(test)]
14216mod tests {
14217 use language::HighlightId;
14218
14219 use super::*;
14220
14221 #[test]
14222 fn test_glob_literal_prefix() {
14223 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14224 assert_eq!(
14225 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14226 Path::new("node_modules")
14227 );
14228 assert_eq!(
14229 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14230 Path::new("foo")
14231 );
14232 assert_eq!(
14233 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14234 Path::new("foo/bar/baz.js")
14235 );
14236
14237 #[cfg(target_os = "windows")]
14238 {
14239 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14240 assert_eq!(
14241 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14242 Path::new("node_modules")
14243 );
14244 assert_eq!(
14245 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14246 Path::new("foo")
14247 );
14248 assert_eq!(
14249 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14250 Path::new("foo/bar/baz.js")
14251 );
14252 }
14253 }
14254
14255 #[test]
14256 fn test_multi_len_chars_normalization() {
14257 let mut label = CodeLabel::new(
14258 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14259 0..6,
14260 vec![(0..6, HighlightId(1))],
14261 );
14262 ensure_uniform_list_compatible_label(&mut label);
14263 assert_eq!(
14264 label,
14265 CodeLabel::new(
14266 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14267 0..6,
14268 vec![(0..6, HighlightId(1))],
14269 )
14270 );
14271 }
14272}