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.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 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_server_for_local_buffer<'a>(
8149 &'a self,
8150 buffer: &'a Buffer,
8151 server_id: LanguageServerId,
8152 cx: &'a mut App,
8153 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8154 self.as_local()?
8155 .language_servers_for_buffer(buffer, cx)
8156 .find(|(_, s)| s.server_id() == server_id)
8157 }
8158
8159 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8160 self.diagnostic_summaries.remove(&id_to_remove);
8161 if let Some(local) = self.as_local_mut() {
8162 let to_remove = local.remove_worktree(id_to_remove, cx);
8163 for server in to_remove {
8164 self.language_server_statuses.remove(&server);
8165 }
8166 }
8167 }
8168
8169 pub fn shared(
8170 &mut self,
8171 project_id: u64,
8172 downstream_client: AnyProtoClient,
8173 _: &mut Context<Self>,
8174 ) {
8175 self.downstream_client = Some((downstream_client.clone(), project_id));
8176
8177 for (server_id, status) in &self.language_server_statuses {
8178 if let Some(server) = self.language_server_for_id(*server_id) {
8179 downstream_client
8180 .send(proto::StartLanguageServer {
8181 project_id,
8182 server: Some(proto::LanguageServer {
8183 id: server_id.to_proto(),
8184 name: status.name.to_string(),
8185 worktree_id: status.worktree.map(|id| id.to_proto()),
8186 }),
8187 capabilities: serde_json::to_string(&server.capabilities())
8188 .expect("serializing server LSP capabilities"),
8189 })
8190 .log_err();
8191 }
8192 }
8193 }
8194
8195 pub fn disconnected_from_host(&mut self) {
8196 self.downstream_client.take();
8197 }
8198
8199 pub fn disconnected_from_ssh_remote(&mut self) {
8200 if let LspStoreMode::Remote(RemoteLspStore {
8201 upstream_client, ..
8202 }) = &mut self.mode
8203 {
8204 upstream_client.take();
8205 }
8206 }
8207
8208 pub(crate) fn set_language_server_statuses_from_proto(
8209 &mut self,
8210 project: WeakEntity<Project>,
8211 language_servers: Vec<proto::LanguageServer>,
8212 server_capabilities: Vec<String>,
8213 cx: &mut Context<Self>,
8214 ) {
8215 let lsp_logs = cx
8216 .try_global::<GlobalLogStore>()
8217 .map(|lsp_store| lsp_store.0.clone());
8218
8219 self.language_server_statuses = language_servers
8220 .into_iter()
8221 .zip(server_capabilities)
8222 .map(|(server, server_capabilities)| {
8223 let server_id = LanguageServerId(server.id as usize);
8224 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8225 self.lsp_server_capabilities
8226 .insert(server_id, server_capabilities);
8227 }
8228
8229 let name = LanguageServerName::from_proto(server.name);
8230 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8231
8232 if let Some(lsp_logs) = &lsp_logs {
8233 lsp_logs.update(cx, |lsp_logs, cx| {
8234 lsp_logs.add_language_server(
8235 // Only remote clients get their language servers set from proto
8236 LanguageServerKind::Remote {
8237 project: project.clone(),
8238 },
8239 server_id,
8240 Some(name.clone()),
8241 worktree,
8242 None,
8243 cx,
8244 );
8245 });
8246 }
8247
8248 (
8249 server_id,
8250 LanguageServerStatus {
8251 name,
8252 pending_work: Default::default(),
8253 has_pending_diagnostic_updates: false,
8254 progress_tokens: Default::default(),
8255 worktree,
8256 binary: None,
8257 configuration: None,
8258 workspace_folders: BTreeSet::new(),
8259 },
8260 )
8261 })
8262 .collect();
8263 }
8264
8265 #[cfg(test)]
8266 pub fn update_diagnostic_entries(
8267 &mut self,
8268 server_id: LanguageServerId,
8269 abs_path: PathBuf,
8270 result_id: Option<SharedString>,
8271 version: Option<i32>,
8272 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8273 cx: &mut Context<Self>,
8274 ) -> anyhow::Result<()> {
8275 self.merge_diagnostic_entries(
8276 vec![DocumentDiagnosticsUpdate {
8277 diagnostics: DocumentDiagnostics {
8278 diagnostics,
8279 document_abs_path: abs_path,
8280 version,
8281 },
8282 result_id,
8283 server_id,
8284 disk_based_sources: Cow::Borrowed(&[]),
8285 registration_id: None,
8286 }],
8287 |_, _, _| false,
8288 cx,
8289 )?;
8290 Ok(())
8291 }
8292
8293 pub fn merge_diagnostic_entries<'a>(
8294 &mut self,
8295 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8296 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8297 cx: &mut Context<Self>,
8298 ) -> anyhow::Result<()> {
8299 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8300 let mut updated_diagnostics_paths = HashMap::default();
8301 for mut update in diagnostic_updates {
8302 let abs_path = &update.diagnostics.document_abs_path;
8303 let server_id = update.server_id;
8304 let Some((worktree, relative_path)) =
8305 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8306 else {
8307 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8308 return Ok(());
8309 };
8310
8311 let worktree_id = worktree.read(cx).id();
8312 let project_path = ProjectPath {
8313 worktree_id,
8314 path: relative_path,
8315 };
8316
8317 let document_uri = lsp::Uri::from_file_path(abs_path)
8318 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8319 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8320 let snapshot = buffer_handle.read(cx).snapshot();
8321 let buffer = buffer_handle.read(cx);
8322 let reused_diagnostics = buffer
8323 .buffer_diagnostics(Some(server_id))
8324 .iter()
8325 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8326 .map(|v| {
8327 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8328 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8329 DiagnosticEntry {
8330 range: start..end,
8331 diagnostic: v.diagnostic.clone(),
8332 }
8333 })
8334 .collect::<Vec<_>>();
8335
8336 self.as_local_mut()
8337 .context("cannot merge diagnostics on a remote LspStore")?
8338 .update_buffer_diagnostics(
8339 &buffer_handle,
8340 server_id,
8341 Some(update.registration_id),
8342 update.result_id,
8343 update.diagnostics.version,
8344 update.diagnostics.diagnostics.clone(),
8345 reused_diagnostics.clone(),
8346 cx,
8347 )?;
8348
8349 update.diagnostics.diagnostics.extend(reused_diagnostics);
8350 } else if let Some(local) = self.as_local() {
8351 let reused_diagnostics = local
8352 .diagnostics
8353 .get(&worktree_id)
8354 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8355 .and_then(|diagnostics_by_server_id| {
8356 diagnostics_by_server_id
8357 .binary_search_by_key(&server_id, |e| e.0)
8358 .ok()
8359 .map(|ix| &diagnostics_by_server_id[ix].1)
8360 })
8361 .into_iter()
8362 .flatten()
8363 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8364
8365 update
8366 .diagnostics
8367 .diagnostics
8368 .extend(reused_diagnostics.cloned());
8369 }
8370
8371 let updated = worktree.update(cx, |worktree, cx| {
8372 self.update_worktree_diagnostics(
8373 worktree.id(),
8374 server_id,
8375 project_path.path.clone(),
8376 update.diagnostics.diagnostics,
8377 cx,
8378 )
8379 })?;
8380 match updated {
8381 ControlFlow::Continue(new_summary) => {
8382 if let Some((project_id, new_summary)) = new_summary {
8383 match &mut diagnostics_summary {
8384 Some(diagnostics_summary) => {
8385 diagnostics_summary
8386 .more_summaries
8387 .push(proto::DiagnosticSummary {
8388 path: project_path.path.as_ref().to_proto(),
8389 language_server_id: server_id.0 as u64,
8390 error_count: new_summary.error_count,
8391 warning_count: new_summary.warning_count,
8392 })
8393 }
8394 None => {
8395 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8396 project_id,
8397 worktree_id: worktree_id.to_proto(),
8398 summary: Some(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 more_summaries: Vec::new(),
8405 })
8406 }
8407 }
8408 }
8409 updated_diagnostics_paths
8410 .entry(server_id)
8411 .or_insert_with(Vec::new)
8412 .push(project_path);
8413 }
8414 ControlFlow::Break(()) => {}
8415 }
8416 }
8417
8418 if let Some((diagnostics_summary, (downstream_client, _))) =
8419 diagnostics_summary.zip(self.downstream_client.as_ref())
8420 {
8421 downstream_client.send(diagnostics_summary).log_err();
8422 }
8423 for (server_id, paths) in updated_diagnostics_paths {
8424 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8425 }
8426 Ok(())
8427 }
8428
8429 fn update_worktree_diagnostics(
8430 &mut self,
8431 worktree_id: WorktreeId,
8432 server_id: LanguageServerId,
8433 path_in_worktree: Arc<RelPath>,
8434 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8435 _: &mut Context<Worktree>,
8436 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8437 let local = match &mut self.mode {
8438 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8439 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8440 };
8441
8442 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8443 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8444 let summaries_by_server_id = summaries_for_tree
8445 .entry(path_in_worktree.clone())
8446 .or_default();
8447
8448 let old_summary = summaries_by_server_id
8449 .remove(&server_id)
8450 .unwrap_or_default();
8451
8452 let new_summary = DiagnosticSummary::new(&diagnostics);
8453 if diagnostics.is_empty() {
8454 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8455 {
8456 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8457 diagnostics_by_server_id.remove(ix);
8458 }
8459 if diagnostics_by_server_id.is_empty() {
8460 diagnostics_for_tree.remove(&path_in_worktree);
8461 }
8462 }
8463 } else {
8464 summaries_by_server_id.insert(server_id, new_summary);
8465 let diagnostics_by_server_id = diagnostics_for_tree
8466 .entry(path_in_worktree.clone())
8467 .or_default();
8468 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8469 Ok(ix) => {
8470 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8471 }
8472 Err(ix) => {
8473 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8474 }
8475 }
8476 }
8477
8478 if !old_summary.is_empty() || !new_summary.is_empty() {
8479 if let Some((_, project_id)) = &self.downstream_client {
8480 Ok(ControlFlow::Continue(Some((
8481 *project_id,
8482 proto::DiagnosticSummary {
8483 path: path_in_worktree.to_proto(),
8484 language_server_id: server_id.0 as u64,
8485 error_count: new_summary.error_count as u32,
8486 warning_count: new_summary.warning_count as u32,
8487 },
8488 ))))
8489 } else {
8490 Ok(ControlFlow::Continue(None))
8491 }
8492 } else {
8493 Ok(ControlFlow::Break(()))
8494 }
8495 }
8496
8497 pub fn open_buffer_for_symbol(
8498 &mut self,
8499 symbol: &Symbol,
8500 cx: &mut Context<Self>,
8501 ) -> Task<Result<Entity<Buffer>>> {
8502 if let Some((client, project_id)) = self.upstream_client() {
8503 let request = client.request(proto::OpenBufferForSymbol {
8504 project_id,
8505 symbol: Some(Self::serialize_symbol(symbol)),
8506 });
8507 cx.spawn(async move |this, cx| {
8508 let response = request.await?;
8509 let buffer_id = BufferId::new(response.buffer_id)?;
8510 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8511 .await
8512 })
8513 } else if let Some(local) = self.as_local() {
8514 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8515 seed.worktree_id == symbol.source_worktree_id
8516 && state.id == symbol.source_language_server_id
8517 && symbol.language_server_name == seed.name
8518 });
8519 if !is_valid {
8520 return Task::ready(Err(anyhow!(
8521 "language server for worktree and language not found"
8522 )));
8523 };
8524
8525 let symbol_abs_path = match &symbol.path {
8526 SymbolLocation::InProject(project_path) => self
8527 .worktree_store
8528 .read(cx)
8529 .absolutize(&project_path, cx)
8530 .context("no such worktree"),
8531 SymbolLocation::OutsideProject {
8532 abs_path,
8533 signature: _,
8534 } => Ok(abs_path.to_path_buf()),
8535 };
8536 let symbol_abs_path = match symbol_abs_path {
8537 Ok(abs_path) => abs_path,
8538 Err(err) => return Task::ready(Err(err)),
8539 };
8540 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8541 uri
8542 } else {
8543 return Task::ready(Err(anyhow!("invalid symbol path")));
8544 };
8545
8546 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8547 } else {
8548 Task::ready(Err(anyhow!("no upstream client or local store")))
8549 }
8550 }
8551
8552 pub(crate) fn open_local_buffer_via_lsp(
8553 &mut self,
8554 abs_path: lsp::Uri,
8555 language_server_id: LanguageServerId,
8556 cx: &mut Context<Self>,
8557 ) -> Task<Result<Entity<Buffer>>> {
8558 cx.spawn(async move |lsp_store, cx| {
8559 // Escape percent-encoded string.
8560 let current_scheme = abs_path.scheme().to_owned();
8561 // Uri is immutable, so we can't modify the scheme
8562
8563 let abs_path = abs_path
8564 .to_file_path()
8565 .map_err(|()| anyhow!("can't convert URI to path"))?;
8566 let p = abs_path.clone();
8567 let yarn_worktree = lsp_store
8568 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8569 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8570 cx.spawn(async move |this, cx| {
8571 let t = this
8572 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8573 .ok()?;
8574 t.await
8575 })
8576 }),
8577 None => Task::ready(None),
8578 })?
8579 .await;
8580 let (worktree_root_target, known_relative_path) =
8581 if let Some((zip_root, relative_path)) = yarn_worktree {
8582 (zip_root, Some(relative_path))
8583 } else {
8584 (Arc::<Path>::from(abs_path.as_path()), None)
8585 };
8586 let (worktree, relative_path) = if let Some(result) =
8587 lsp_store.update(cx, |lsp_store, cx| {
8588 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8589 worktree_store.find_worktree(&worktree_root_target, cx)
8590 })
8591 })? {
8592 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8593 (result.0, relative_path)
8594 } else {
8595 let worktree = lsp_store
8596 .update(cx, |lsp_store, cx| {
8597 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8598 worktree_store.create_worktree(&worktree_root_target, false, cx)
8599 })
8600 })?
8601 .await?;
8602 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8603 lsp_store
8604 .update(cx, |lsp_store, cx| {
8605 if let Some(local) = lsp_store.as_local_mut() {
8606 local.register_language_server_for_invisible_worktree(
8607 &worktree,
8608 language_server_id,
8609 cx,
8610 )
8611 }
8612 })
8613 .ok();
8614 }
8615 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8616 let relative_path = if let Some(known_path) = known_relative_path {
8617 known_path
8618 } else {
8619 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8620 .into_arc()
8621 };
8622 (worktree, relative_path)
8623 };
8624 let project_path = ProjectPath {
8625 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8626 path: relative_path,
8627 };
8628 lsp_store
8629 .update(cx, |lsp_store, cx| {
8630 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8631 buffer_store.open_buffer(project_path, cx)
8632 })
8633 })?
8634 .await
8635 })
8636 }
8637
8638 fn request_multiple_lsp_locally<P, R>(
8639 &mut self,
8640 buffer: &Entity<Buffer>,
8641 position: Option<P>,
8642 request: R,
8643 cx: &mut Context<Self>,
8644 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8645 where
8646 P: ToOffset,
8647 R: LspCommand + Clone,
8648 <R::LspRequest as lsp::request::Request>::Result: Send,
8649 <R::LspRequest as lsp::request::Request>::Params: Send,
8650 {
8651 let Some(local) = self.as_local() else {
8652 return Task::ready(Vec::new());
8653 };
8654
8655 let snapshot = buffer.read(cx).snapshot();
8656 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8657
8658 let server_ids = buffer.update(cx, |buffer, cx| {
8659 local
8660 .language_servers_for_buffer(buffer, cx)
8661 .filter(|(adapter, _)| {
8662 scope
8663 .as_ref()
8664 .map(|scope| scope.language_allowed(&adapter.name))
8665 .unwrap_or(true)
8666 })
8667 .map(|(_, server)| server.server_id())
8668 .filter(|server_id| {
8669 self.as_local().is_none_or(|local| {
8670 local
8671 .buffers_opened_in_servers
8672 .get(&snapshot.remote_id())
8673 .is_some_and(|servers| servers.contains(server_id))
8674 })
8675 })
8676 .collect::<Vec<_>>()
8677 });
8678
8679 let mut response_results = server_ids
8680 .into_iter()
8681 .map(|server_id| {
8682 let task = self.request_lsp(
8683 buffer.clone(),
8684 LanguageServerToQuery::Other(server_id),
8685 request.clone(),
8686 cx,
8687 );
8688 async move { (server_id, task.await) }
8689 })
8690 .collect::<FuturesUnordered<_>>();
8691
8692 cx.background_spawn(async move {
8693 let mut responses = Vec::with_capacity(response_results.len());
8694 while let Some((server_id, response_result)) = response_results.next().await {
8695 match response_result {
8696 Ok(response) => responses.push((server_id, response)),
8697 // rust-analyzer likes to error with this when its still loading up
8698 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8699 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8700 }
8701 }
8702 responses
8703 })
8704 }
8705
8706 async fn handle_lsp_get_completions(
8707 this: Entity<Self>,
8708 envelope: TypedEnvelope<proto::GetCompletions>,
8709 mut cx: AsyncApp,
8710 ) -> Result<proto::GetCompletionsResponse> {
8711 let sender_id = envelope.original_sender_id().unwrap_or_default();
8712
8713 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8714 let buffer_handle = this.update(&mut cx, |this, cx| {
8715 this.buffer_store.read(cx).get_existing(buffer_id)
8716 })??;
8717 let request = GetCompletions::from_proto(
8718 envelope.payload,
8719 this.clone(),
8720 buffer_handle.clone(),
8721 cx.clone(),
8722 )
8723 .await?;
8724
8725 let server_to_query = match request.server_id {
8726 Some(server_id) => LanguageServerToQuery::Other(server_id),
8727 None => LanguageServerToQuery::FirstCapable,
8728 };
8729
8730 let response = this
8731 .update(&mut cx, |this, cx| {
8732 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8733 })?
8734 .await?;
8735 this.update(&mut cx, |this, cx| {
8736 Ok(GetCompletions::response_to_proto(
8737 response,
8738 this,
8739 sender_id,
8740 &buffer_handle.read(cx).version(),
8741 cx,
8742 ))
8743 })?
8744 }
8745
8746 async fn handle_lsp_command<T: LspCommand>(
8747 this: Entity<Self>,
8748 envelope: TypedEnvelope<T::ProtoRequest>,
8749 mut cx: AsyncApp,
8750 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8751 where
8752 <T::LspRequest as lsp::request::Request>::Params: Send,
8753 <T::LspRequest as lsp::request::Request>::Result: Send,
8754 {
8755 let sender_id = envelope.original_sender_id().unwrap_or_default();
8756 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8757 let buffer_handle = this.update(&mut cx, |this, cx| {
8758 this.buffer_store.read(cx).get_existing(buffer_id)
8759 })??;
8760 let request = T::from_proto(
8761 envelope.payload,
8762 this.clone(),
8763 buffer_handle.clone(),
8764 cx.clone(),
8765 )
8766 .await?;
8767 let response = this
8768 .update(&mut cx, |this, cx| {
8769 this.request_lsp(
8770 buffer_handle.clone(),
8771 LanguageServerToQuery::FirstCapable,
8772 request,
8773 cx,
8774 )
8775 })?
8776 .await?;
8777 this.update(&mut cx, |this, cx| {
8778 Ok(T::response_to_proto(
8779 response,
8780 this,
8781 sender_id,
8782 &buffer_handle.read(cx).version(),
8783 cx,
8784 ))
8785 })?
8786 }
8787
8788 async fn handle_lsp_query(
8789 lsp_store: Entity<Self>,
8790 envelope: TypedEnvelope<proto::LspQuery>,
8791 mut cx: AsyncApp,
8792 ) -> Result<proto::Ack> {
8793 use proto::lsp_query::Request;
8794 let sender_id = envelope.original_sender_id().unwrap_or_default();
8795 let lsp_query = envelope.payload;
8796 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8797 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8798 match lsp_query.request.context("invalid LSP query request")? {
8799 Request::GetReferences(get_references) => {
8800 let position = get_references.position.clone().and_then(deserialize_anchor);
8801 Self::query_lsp_locally::<GetReferences>(
8802 lsp_store,
8803 server_id,
8804 sender_id,
8805 lsp_request_id,
8806 get_references,
8807 position,
8808 &mut cx,
8809 )
8810 .await?;
8811 }
8812 Request::GetDocumentColor(get_document_color) => {
8813 Self::query_lsp_locally::<GetDocumentColor>(
8814 lsp_store,
8815 server_id,
8816 sender_id,
8817 lsp_request_id,
8818 get_document_color,
8819 None,
8820 &mut cx,
8821 )
8822 .await?;
8823 }
8824 Request::GetHover(get_hover) => {
8825 let position = get_hover.position.clone().and_then(deserialize_anchor);
8826 Self::query_lsp_locally::<GetHover>(
8827 lsp_store,
8828 server_id,
8829 sender_id,
8830 lsp_request_id,
8831 get_hover,
8832 position,
8833 &mut cx,
8834 )
8835 .await?;
8836 }
8837 Request::GetCodeActions(get_code_actions) => {
8838 Self::query_lsp_locally::<GetCodeActions>(
8839 lsp_store,
8840 server_id,
8841 sender_id,
8842 lsp_request_id,
8843 get_code_actions,
8844 None,
8845 &mut cx,
8846 )
8847 .await?;
8848 }
8849 Request::GetSignatureHelp(get_signature_help) => {
8850 let position = get_signature_help
8851 .position
8852 .clone()
8853 .and_then(deserialize_anchor);
8854 Self::query_lsp_locally::<GetSignatureHelp>(
8855 lsp_store,
8856 server_id,
8857 sender_id,
8858 lsp_request_id,
8859 get_signature_help,
8860 position,
8861 &mut cx,
8862 )
8863 .await?;
8864 }
8865 Request::GetCodeLens(get_code_lens) => {
8866 Self::query_lsp_locally::<GetCodeLens>(
8867 lsp_store,
8868 server_id,
8869 sender_id,
8870 lsp_request_id,
8871 get_code_lens,
8872 None,
8873 &mut cx,
8874 )
8875 .await?;
8876 }
8877 Request::GetDefinition(get_definition) => {
8878 let position = get_definition.position.clone().and_then(deserialize_anchor);
8879 Self::query_lsp_locally::<GetDefinitions>(
8880 lsp_store,
8881 server_id,
8882 sender_id,
8883 lsp_request_id,
8884 get_definition,
8885 position,
8886 &mut cx,
8887 )
8888 .await?;
8889 }
8890 Request::GetDeclaration(get_declaration) => {
8891 let position = get_declaration
8892 .position
8893 .clone()
8894 .and_then(deserialize_anchor);
8895 Self::query_lsp_locally::<GetDeclarations>(
8896 lsp_store,
8897 server_id,
8898 sender_id,
8899 lsp_request_id,
8900 get_declaration,
8901 position,
8902 &mut cx,
8903 )
8904 .await?;
8905 }
8906 Request::GetTypeDefinition(get_type_definition) => {
8907 let position = get_type_definition
8908 .position
8909 .clone()
8910 .and_then(deserialize_anchor);
8911 Self::query_lsp_locally::<GetTypeDefinitions>(
8912 lsp_store,
8913 server_id,
8914 sender_id,
8915 lsp_request_id,
8916 get_type_definition,
8917 position,
8918 &mut cx,
8919 )
8920 .await?;
8921 }
8922 Request::GetImplementation(get_implementation) => {
8923 let position = get_implementation
8924 .position
8925 .clone()
8926 .and_then(deserialize_anchor);
8927 Self::query_lsp_locally::<GetImplementations>(
8928 lsp_store,
8929 server_id,
8930 sender_id,
8931 lsp_request_id,
8932 get_implementation,
8933 position,
8934 &mut cx,
8935 )
8936 .await?;
8937 }
8938 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8939 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8940 let version = deserialize_version(get_document_diagnostics.buffer_version());
8941 let buffer = lsp_store.update(&mut cx, |this, cx| {
8942 this.buffer_store.read(cx).get_existing(buffer_id)
8943 })??;
8944 buffer
8945 .update(&mut cx, |buffer, _| {
8946 buffer.wait_for_version(version.clone())
8947 })?
8948 .await?;
8949 lsp_store.update(&mut cx, |lsp_store, cx| {
8950 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8951 let key = LspKey {
8952 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8953 server_queried: server_id,
8954 };
8955 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8956 ) {
8957 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8958 lsp_requests.clear();
8959 };
8960 }
8961
8962 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8963 existing_queries.insert(
8964 lsp_request_id,
8965 cx.spawn(async move |lsp_store, cx| {
8966 let diagnostics_pull = lsp_store
8967 .update(cx, |lsp_store, cx| {
8968 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8969 })
8970 .ok();
8971 if let Some(diagnostics_pull) = diagnostics_pull {
8972 match diagnostics_pull.await {
8973 Ok(()) => {}
8974 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8975 };
8976 }
8977 }),
8978 );
8979 })?;
8980 }
8981 Request::InlayHints(inlay_hints) => {
8982 let query_start = inlay_hints
8983 .start
8984 .clone()
8985 .and_then(deserialize_anchor)
8986 .context("invalid inlay hints range start")?;
8987 let query_end = inlay_hints
8988 .end
8989 .clone()
8990 .and_then(deserialize_anchor)
8991 .context("invalid inlay hints range end")?;
8992 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8993 &lsp_store,
8994 server_id,
8995 lsp_request_id,
8996 &inlay_hints,
8997 query_start..query_end,
8998 &mut cx,
8999 )
9000 .await
9001 .context("preparing inlay hints request")?;
9002 Self::query_lsp_locally::<InlayHints>(
9003 lsp_store,
9004 server_id,
9005 sender_id,
9006 lsp_request_id,
9007 inlay_hints,
9008 None,
9009 &mut cx,
9010 )
9011 .await
9012 .context("querying for inlay hints")?
9013 }
9014 }
9015 Ok(proto::Ack {})
9016 }
9017
9018 async fn handle_lsp_query_response(
9019 lsp_store: Entity<Self>,
9020 envelope: TypedEnvelope<proto::LspQueryResponse>,
9021 cx: AsyncApp,
9022 ) -> Result<()> {
9023 lsp_store.read_with(&cx, |lsp_store, _| {
9024 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9025 upstream_client.handle_lsp_response(envelope.clone());
9026 }
9027 })?;
9028 Ok(())
9029 }
9030
9031 async fn handle_apply_code_action(
9032 this: Entity<Self>,
9033 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9034 mut cx: AsyncApp,
9035 ) -> Result<proto::ApplyCodeActionResponse> {
9036 let sender_id = envelope.original_sender_id().unwrap_or_default();
9037 let action =
9038 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9039 let apply_code_action = this.update(&mut cx, |this, cx| {
9040 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9041 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9042 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9043 })??;
9044
9045 let project_transaction = apply_code_action.await?;
9046 let project_transaction = this.update(&mut cx, |this, cx| {
9047 this.buffer_store.update(cx, |buffer_store, cx| {
9048 buffer_store.serialize_project_transaction_for_peer(
9049 project_transaction,
9050 sender_id,
9051 cx,
9052 )
9053 })
9054 })?;
9055 Ok(proto::ApplyCodeActionResponse {
9056 transaction: Some(project_transaction),
9057 })
9058 }
9059
9060 async fn handle_register_buffer_with_language_servers(
9061 this: Entity<Self>,
9062 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9063 mut cx: AsyncApp,
9064 ) -> Result<proto::Ack> {
9065 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9066 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9067 this.update(&mut cx, |this, cx| {
9068 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9069 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9070 project_id: upstream_project_id,
9071 buffer_id: buffer_id.to_proto(),
9072 only_servers: envelope.payload.only_servers,
9073 });
9074 }
9075
9076 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9077 anyhow::bail!("buffer is not open");
9078 };
9079
9080 let handle = this.register_buffer_with_language_servers(
9081 &buffer,
9082 envelope
9083 .payload
9084 .only_servers
9085 .into_iter()
9086 .filter_map(|selector| {
9087 Some(match selector.selector? {
9088 proto::language_server_selector::Selector::ServerId(server_id) => {
9089 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9090 }
9091 proto::language_server_selector::Selector::Name(name) => {
9092 LanguageServerSelector::Name(LanguageServerName(
9093 SharedString::from(name),
9094 ))
9095 }
9096 })
9097 })
9098 .collect(),
9099 false,
9100 cx,
9101 );
9102 this.buffer_store().update(cx, |buffer_store, _| {
9103 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9104 });
9105
9106 Ok(())
9107 })??;
9108 Ok(proto::Ack {})
9109 }
9110
9111 async fn handle_rename_project_entry(
9112 this: Entity<Self>,
9113 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9114 mut cx: AsyncApp,
9115 ) -> Result<proto::ProjectEntryResponse> {
9116 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9117 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9118 let new_path =
9119 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9120
9121 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9122 .update(&mut cx, |this, cx| {
9123 let (worktree, entry) = this
9124 .worktree_store
9125 .read(cx)
9126 .worktree_and_entry_for_id(entry_id, cx)?;
9127 let new_worktree = this
9128 .worktree_store
9129 .read(cx)
9130 .worktree_for_id(new_worktree_id, cx)?;
9131 Some((
9132 this.worktree_store.clone(),
9133 worktree,
9134 new_worktree,
9135 entry.clone(),
9136 ))
9137 })?
9138 .context("worktree not found")?;
9139 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9140 (worktree.absolutize(&old_entry.path), worktree.id())
9141 })?;
9142 let new_abs_path =
9143 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9144
9145 let _transaction = Self::will_rename_entry(
9146 this.downgrade(),
9147 old_worktree_id,
9148 &old_abs_path,
9149 &new_abs_path,
9150 old_entry.is_dir(),
9151 cx.clone(),
9152 )
9153 .await;
9154 let response = WorktreeStore::handle_rename_project_entry(
9155 worktree_store,
9156 envelope.payload,
9157 cx.clone(),
9158 )
9159 .await;
9160 this.read_with(&cx, |this, _| {
9161 this.did_rename_entry(
9162 old_worktree_id,
9163 &old_abs_path,
9164 &new_abs_path,
9165 old_entry.is_dir(),
9166 );
9167 })
9168 .ok();
9169 response
9170 }
9171
9172 async fn handle_update_diagnostic_summary(
9173 this: Entity<Self>,
9174 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9175 mut cx: AsyncApp,
9176 ) -> Result<()> {
9177 this.update(&mut cx, |lsp_store, cx| {
9178 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9179 let mut updated_diagnostics_paths = HashMap::default();
9180 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9181 for message_summary in envelope
9182 .payload
9183 .summary
9184 .into_iter()
9185 .chain(envelope.payload.more_summaries)
9186 {
9187 let project_path = ProjectPath {
9188 worktree_id,
9189 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9190 };
9191 let path = project_path.path.clone();
9192 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9193 let summary = DiagnosticSummary {
9194 error_count: message_summary.error_count as usize,
9195 warning_count: message_summary.warning_count as usize,
9196 };
9197
9198 if summary.is_empty() {
9199 if let Some(worktree_summaries) =
9200 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9201 && let Some(summaries) = worktree_summaries.get_mut(&path)
9202 {
9203 summaries.remove(&server_id);
9204 if summaries.is_empty() {
9205 worktree_summaries.remove(&path);
9206 }
9207 }
9208 } else {
9209 lsp_store
9210 .diagnostic_summaries
9211 .entry(worktree_id)
9212 .or_default()
9213 .entry(path)
9214 .or_default()
9215 .insert(server_id, summary);
9216 }
9217
9218 if let Some((_, project_id)) = &lsp_store.downstream_client {
9219 match &mut diagnostics_summary {
9220 Some(diagnostics_summary) => {
9221 diagnostics_summary
9222 .more_summaries
9223 .push(proto::DiagnosticSummary {
9224 path: project_path.path.as_ref().to_proto(),
9225 language_server_id: server_id.0 as u64,
9226 error_count: summary.error_count as u32,
9227 warning_count: summary.warning_count as u32,
9228 })
9229 }
9230 None => {
9231 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9232 project_id: *project_id,
9233 worktree_id: worktree_id.to_proto(),
9234 summary: Some(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 more_summaries: Vec::new(),
9241 })
9242 }
9243 }
9244 }
9245 updated_diagnostics_paths
9246 .entry(server_id)
9247 .or_insert_with(Vec::new)
9248 .push(project_path);
9249 }
9250
9251 if let Some((diagnostics_summary, (downstream_client, _))) =
9252 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9253 {
9254 downstream_client.send(diagnostics_summary).log_err();
9255 }
9256 for (server_id, paths) in updated_diagnostics_paths {
9257 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9258 }
9259 Ok(())
9260 })?
9261 }
9262
9263 async fn handle_start_language_server(
9264 lsp_store: Entity<Self>,
9265 envelope: TypedEnvelope<proto::StartLanguageServer>,
9266 mut cx: AsyncApp,
9267 ) -> Result<()> {
9268 let server = envelope.payload.server.context("invalid server")?;
9269 let server_capabilities =
9270 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9271 .with_context(|| {
9272 format!(
9273 "incorrect server capabilities {}",
9274 envelope.payload.capabilities
9275 )
9276 })?;
9277 lsp_store.update(&mut cx, |lsp_store, cx| {
9278 let server_id = LanguageServerId(server.id as usize);
9279 let server_name = LanguageServerName::from_proto(server.name.clone());
9280 lsp_store
9281 .lsp_server_capabilities
9282 .insert(server_id, server_capabilities);
9283 lsp_store.language_server_statuses.insert(
9284 server_id,
9285 LanguageServerStatus {
9286 name: server_name.clone(),
9287 pending_work: Default::default(),
9288 has_pending_diagnostic_updates: false,
9289 progress_tokens: Default::default(),
9290 worktree: server.worktree_id.map(WorktreeId::from_proto),
9291 binary: None,
9292 configuration: None,
9293 workspace_folders: BTreeSet::new(),
9294 },
9295 );
9296 cx.emit(LspStoreEvent::LanguageServerAdded(
9297 server_id,
9298 server_name,
9299 server.worktree_id.map(WorktreeId::from_proto),
9300 ));
9301 cx.notify();
9302 })?;
9303 Ok(())
9304 }
9305
9306 async fn handle_update_language_server(
9307 lsp_store: Entity<Self>,
9308 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9309 mut cx: AsyncApp,
9310 ) -> Result<()> {
9311 lsp_store.update(&mut cx, |lsp_store, cx| {
9312 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9313
9314 match envelope.payload.variant.context("invalid variant")? {
9315 proto::update_language_server::Variant::WorkStart(payload) => {
9316 lsp_store.on_lsp_work_start(
9317 language_server_id,
9318 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9319 .context("invalid progress token value")?,
9320 LanguageServerProgress {
9321 title: payload.title,
9322 is_disk_based_diagnostics_progress: false,
9323 is_cancellable: payload.is_cancellable.unwrap_or(false),
9324 message: payload.message,
9325 percentage: payload.percentage.map(|p| p as usize),
9326 last_update_at: cx.background_executor().now(),
9327 },
9328 cx,
9329 );
9330 }
9331 proto::update_language_server::Variant::WorkProgress(payload) => {
9332 lsp_store.on_lsp_work_progress(
9333 language_server_id,
9334 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9335 .context("invalid progress token value")?,
9336 LanguageServerProgress {
9337 title: None,
9338 is_disk_based_diagnostics_progress: false,
9339 is_cancellable: payload.is_cancellable.unwrap_or(false),
9340 message: payload.message,
9341 percentage: payload.percentage.map(|p| p as usize),
9342 last_update_at: cx.background_executor().now(),
9343 },
9344 cx,
9345 );
9346 }
9347
9348 proto::update_language_server::Variant::WorkEnd(payload) => {
9349 lsp_store.on_lsp_work_end(
9350 language_server_id,
9351 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9352 .context("invalid progress token value")?,
9353 cx,
9354 );
9355 }
9356
9357 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9358 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9359 }
9360
9361 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9362 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9363 }
9364
9365 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9366 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9367 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9368 cx.emit(LspStoreEvent::LanguageServerUpdate {
9369 language_server_id,
9370 name: envelope
9371 .payload
9372 .server_name
9373 .map(SharedString::new)
9374 .map(LanguageServerName),
9375 message: non_lsp,
9376 });
9377 }
9378 }
9379
9380 Ok(())
9381 })?
9382 }
9383
9384 async fn handle_language_server_log(
9385 this: Entity<Self>,
9386 envelope: TypedEnvelope<proto::LanguageServerLog>,
9387 mut cx: AsyncApp,
9388 ) -> Result<()> {
9389 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9390 let log_type = envelope
9391 .payload
9392 .log_type
9393 .map(LanguageServerLogType::from_proto)
9394 .context("invalid language server log type")?;
9395
9396 let message = envelope.payload.message;
9397
9398 this.update(&mut cx, |_, cx| {
9399 cx.emit(LspStoreEvent::LanguageServerLog(
9400 language_server_id,
9401 log_type,
9402 message,
9403 ));
9404 })
9405 }
9406
9407 async fn handle_lsp_ext_cancel_flycheck(
9408 lsp_store: Entity<Self>,
9409 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9410 cx: AsyncApp,
9411 ) -> Result<proto::Ack> {
9412 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9413 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9414 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9415 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9416 } else {
9417 None
9418 }
9419 })?;
9420 if let Some(task) = task {
9421 task.context("handling lsp ext cancel flycheck")?;
9422 }
9423
9424 Ok(proto::Ack {})
9425 }
9426
9427 async fn handle_lsp_ext_run_flycheck(
9428 lsp_store: Entity<Self>,
9429 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9430 mut cx: AsyncApp,
9431 ) -> Result<proto::Ack> {
9432 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9433 lsp_store.update(&mut cx, |lsp_store, cx| {
9434 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9435 let text_document = if envelope.payload.current_file_only {
9436 let buffer_id = envelope
9437 .payload
9438 .buffer_id
9439 .map(|id| BufferId::new(id))
9440 .transpose()?;
9441 buffer_id
9442 .and_then(|buffer_id| {
9443 lsp_store
9444 .buffer_store()
9445 .read(cx)
9446 .get(buffer_id)
9447 .and_then(|buffer| {
9448 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9449 })
9450 .map(|path| make_text_document_identifier(&path))
9451 })
9452 .transpose()?
9453 } else {
9454 None
9455 };
9456 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9457 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9458 )?;
9459 }
9460 anyhow::Ok(())
9461 })??;
9462
9463 Ok(proto::Ack {})
9464 }
9465
9466 async fn handle_lsp_ext_clear_flycheck(
9467 lsp_store: Entity<Self>,
9468 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9469 cx: AsyncApp,
9470 ) -> Result<proto::Ack> {
9471 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9472 lsp_store
9473 .read_with(&cx, |lsp_store, _| {
9474 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9475 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9476 } else {
9477 None
9478 }
9479 })
9480 .context("handling lsp ext clear flycheck")?;
9481
9482 Ok(proto::Ack {})
9483 }
9484
9485 pub fn disk_based_diagnostics_started(
9486 &mut self,
9487 language_server_id: LanguageServerId,
9488 cx: &mut Context<Self>,
9489 ) {
9490 if let Some(language_server_status) =
9491 self.language_server_statuses.get_mut(&language_server_id)
9492 {
9493 language_server_status.has_pending_diagnostic_updates = true;
9494 }
9495
9496 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9497 cx.emit(LspStoreEvent::LanguageServerUpdate {
9498 language_server_id,
9499 name: self
9500 .language_server_adapter_for_id(language_server_id)
9501 .map(|adapter| adapter.name()),
9502 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9503 Default::default(),
9504 ),
9505 })
9506 }
9507
9508 pub fn disk_based_diagnostics_finished(
9509 &mut self,
9510 language_server_id: LanguageServerId,
9511 cx: &mut Context<Self>,
9512 ) {
9513 if let Some(language_server_status) =
9514 self.language_server_statuses.get_mut(&language_server_id)
9515 {
9516 language_server_status.has_pending_diagnostic_updates = false;
9517 }
9518
9519 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9520 cx.emit(LspStoreEvent::LanguageServerUpdate {
9521 language_server_id,
9522 name: self
9523 .language_server_adapter_for_id(language_server_id)
9524 .map(|adapter| adapter.name()),
9525 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9526 Default::default(),
9527 ),
9528 })
9529 }
9530
9531 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9532 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9533 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9534 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9535 // the language server might take some time to publish diagnostics.
9536 fn simulate_disk_based_diagnostics_events_if_needed(
9537 &mut self,
9538 language_server_id: LanguageServerId,
9539 cx: &mut Context<Self>,
9540 ) {
9541 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9542
9543 let Some(LanguageServerState::Running {
9544 simulate_disk_based_diagnostics_completion,
9545 adapter,
9546 ..
9547 }) = self
9548 .as_local_mut()
9549 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9550 else {
9551 return;
9552 };
9553
9554 if adapter.disk_based_diagnostics_progress_token.is_some() {
9555 return;
9556 }
9557
9558 let prev_task =
9559 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9560 cx.background_executor()
9561 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9562 .await;
9563
9564 this.update(cx, |this, cx| {
9565 this.disk_based_diagnostics_finished(language_server_id, cx);
9566
9567 if let Some(LanguageServerState::Running {
9568 simulate_disk_based_diagnostics_completion,
9569 ..
9570 }) = this.as_local_mut().and_then(|local_store| {
9571 local_store.language_servers.get_mut(&language_server_id)
9572 }) {
9573 *simulate_disk_based_diagnostics_completion = None;
9574 }
9575 })
9576 .ok();
9577 }));
9578
9579 if prev_task.is_none() {
9580 self.disk_based_diagnostics_started(language_server_id, cx);
9581 }
9582 }
9583
9584 pub fn language_server_statuses(
9585 &self,
9586 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9587 self.language_server_statuses
9588 .iter()
9589 .map(|(key, value)| (*key, value))
9590 }
9591
9592 pub(super) fn did_rename_entry(
9593 &self,
9594 worktree_id: WorktreeId,
9595 old_path: &Path,
9596 new_path: &Path,
9597 is_dir: bool,
9598 ) {
9599 maybe!({
9600 let local_store = self.as_local()?;
9601
9602 let old_uri = lsp::Uri::from_file_path(old_path)
9603 .ok()
9604 .map(|uri| uri.to_string())?;
9605 let new_uri = lsp::Uri::from_file_path(new_path)
9606 .ok()
9607 .map(|uri| uri.to_string())?;
9608
9609 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9610 let Some(filter) = local_store
9611 .language_server_paths_watched_for_rename
9612 .get(&language_server.server_id())
9613 else {
9614 continue;
9615 };
9616
9617 if filter.should_send_did_rename(&old_uri, is_dir) {
9618 language_server
9619 .notify::<DidRenameFiles>(RenameFilesParams {
9620 files: vec![FileRename {
9621 old_uri: old_uri.clone(),
9622 new_uri: new_uri.clone(),
9623 }],
9624 })
9625 .ok();
9626 }
9627 }
9628 Some(())
9629 });
9630 }
9631
9632 pub(super) fn will_rename_entry(
9633 this: WeakEntity<Self>,
9634 worktree_id: WorktreeId,
9635 old_path: &Path,
9636 new_path: &Path,
9637 is_dir: bool,
9638 cx: AsyncApp,
9639 ) -> Task<ProjectTransaction> {
9640 let old_uri = lsp::Uri::from_file_path(old_path)
9641 .ok()
9642 .map(|uri| uri.to_string());
9643 let new_uri = lsp::Uri::from_file_path(new_path)
9644 .ok()
9645 .map(|uri| uri.to_string());
9646 cx.spawn(async move |cx| {
9647 let mut tasks = vec![];
9648 this.update(cx, |this, cx| {
9649 let local_store = this.as_local()?;
9650 let old_uri = old_uri?;
9651 let new_uri = new_uri?;
9652 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9653 let Some(filter) = local_store
9654 .language_server_paths_watched_for_rename
9655 .get(&language_server.server_id())
9656 else {
9657 continue;
9658 };
9659
9660 if filter.should_send_will_rename(&old_uri, is_dir) {
9661 let apply_edit = cx.spawn({
9662 let old_uri = old_uri.clone();
9663 let new_uri = new_uri.clone();
9664 let language_server = language_server.clone();
9665 async move |this, cx| {
9666 let edit = language_server
9667 .request::<WillRenameFiles>(RenameFilesParams {
9668 files: vec![FileRename { old_uri, new_uri }],
9669 })
9670 .await
9671 .into_response()
9672 .context("will rename files")
9673 .log_err()
9674 .flatten()?;
9675
9676 let transaction = LocalLspStore::deserialize_workspace_edit(
9677 this.upgrade()?,
9678 edit,
9679 false,
9680 language_server.clone(),
9681 cx,
9682 )
9683 .await
9684 .ok()?;
9685 Some(transaction)
9686 }
9687 });
9688 tasks.push(apply_edit);
9689 }
9690 }
9691 Some(())
9692 })
9693 .ok()
9694 .flatten();
9695 let mut merged_transaction = ProjectTransaction::default();
9696 for task in tasks {
9697 // Await on tasks sequentially so that the order of application of edits is deterministic
9698 // (at least with regards to the order of registration of language servers)
9699 if let Some(transaction) = task.await {
9700 for (buffer, buffer_transaction) in transaction.0 {
9701 merged_transaction.0.insert(buffer, buffer_transaction);
9702 }
9703 }
9704 }
9705 merged_transaction
9706 })
9707 }
9708
9709 fn lsp_notify_abs_paths_changed(
9710 &mut self,
9711 server_id: LanguageServerId,
9712 changes: Vec<PathEvent>,
9713 ) {
9714 maybe!({
9715 let server = self.language_server_for_id(server_id)?;
9716 let changes = changes
9717 .into_iter()
9718 .filter_map(|event| {
9719 let typ = match event.kind? {
9720 PathEventKind::Created => lsp::FileChangeType::CREATED,
9721 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9722 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9723 };
9724 Some(lsp::FileEvent {
9725 uri: file_path_to_lsp_url(&event.path).log_err()?,
9726 typ,
9727 })
9728 })
9729 .collect::<Vec<_>>();
9730 if !changes.is_empty() {
9731 server
9732 .notify::<lsp::notification::DidChangeWatchedFiles>(
9733 lsp::DidChangeWatchedFilesParams { changes },
9734 )
9735 .ok();
9736 }
9737 Some(())
9738 });
9739 }
9740
9741 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9742 self.as_local()?.language_server_for_id(id)
9743 }
9744
9745 fn on_lsp_progress(
9746 &mut self,
9747 progress_params: lsp::ProgressParams,
9748 language_server_id: LanguageServerId,
9749 disk_based_diagnostics_progress_token: Option<String>,
9750 cx: &mut Context<Self>,
9751 ) {
9752 match progress_params.value {
9753 lsp::ProgressParamsValue::WorkDone(progress) => {
9754 self.handle_work_done_progress(
9755 progress,
9756 language_server_id,
9757 disk_based_diagnostics_progress_token,
9758 ProgressToken::from_lsp(progress_params.token),
9759 cx,
9760 );
9761 }
9762 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9763 let registration_id = match progress_params.token {
9764 lsp::NumberOrString::Number(_) => None,
9765 lsp::NumberOrString::String(token) => token
9766 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9767 .map(|(_, id)| id.to_owned()),
9768 };
9769 if let Some(LanguageServerState::Running {
9770 workspace_diagnostics_refresh_tasks,
9771 ..
9772 }) = self
9773 .as_local_mut()
9774 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9775 && let Some(workspace_diagnostics) =
9776 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9777 {
9778 workspace_diagnostics.progress_tx.try_send(()).ok();
9779 self.apply_workspace_diagnostic_report(
9780 language_server_id,
9781 report,
9782 registration_id.map(SharedString::from),
9783 cx,
9784 )
9785 }
9786 }
9787 }
9788 }
9789
9790 fn handle_work_done_progress(
9791 &mut self,
9792 progress: lsp::WorkDoneProgress,
9793 language_server_id: LanguageServerId,
9794 disk_based_diagnostics_progress_token: Option<String>,
9795 token: ProgressToken,
9796 cx: &mut Context<Self>,
9797 ) {
9798 let language_server_status =
9799 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9800 status
9801 } else {
9802 return;
9803 };
9804
9805 if !language_server_status.progress_tokens.contains(&token) {
9806 return;
9807 }
9808
9809 let is_disk_based_diagnostics_progress =
9810 if let (Some(disk_based_token), ProgressToken::String(token)) =
9811 (&disk_based_diagnostics_progress_token, &token)
9812 {
9813 token.starts_with(disk_based_token)
9814 } else {
9815 false
9816 };
9817
9818 match progress {
9819 lsp::WorkDoneProgress::Begin(report) => {
9820 if is_disk_based_diagnostics_progress {
9821 self.disk_based_diagnostics_started(language_server_id, cx);
9822 }
9823 self.on_lsp_work_start(
9824 language_server_id,
9825 token.clone(),
9826 LanguageServerProgress {
9827 title: Some(report.title),
9828 is_disk_based_diagnostics_progress,
9829 is_cancellable: report.cancellable.unwrap_or(false),
9830 message: report.message.clone(),
9831 percentage: report.percentage.map(|p| p as usize),
9832 last_update_at: cx.background_executor().now(),
9833 },
9834 cx,
9835 );
9836 }
9837 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9838 language_server_id,
9839 token,
9840 LanguageServerProgress {
9841 title: None,
9842 is_disk_based_diagnostics_progress,
9843 is_cancellable: report.cancellable.unwrap_or(false),
9844 message: report.message,
9845 percentage: report.percentage.map(|p| p as usize),
9846 last_update_at: cx.background_executor().now(),
9847 },
9848 cx,
9849 ),
9850 lsp::WorkDoneProgress::End(_) => {
9851 language_server_status.progress_tokens.remove(&token);
9852 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9853 if is_disk_based_diagnostics_progress {
9854 self.disk_based_diagnostics_finished(language_server_id, cx);
9855 }
9856 }
9857 }
9858 }
9859
9860 fn on_lsp_work_start(
9861 &mut self,
9862 language_server_id: LanguageServerId,
9863 token: ProgressToken,
9864 progress: LanguageServerProgress,
9865 cx: &mut Context<Self>,
9866 ) {
9867 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9868 status.pending_work.insert(token.clone(), progress.clone());
9869 cx.notify();
9870 }
9871 cx.emit(LspStoreEvent::LanguageServerUpdate {
9872 language_server_id,
9873 name: self
9874 .language_server_adapter_for_id(language_server_id)
9875 .map(|adapter| adapter.name()),
9876 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9877 token: Some(token.to_proto()),
9878 title: progress.title,
9879 message: progress.message,
9880 percentage: progress.percentage.map(|p| p as u32),
9881 is_cancellable: Some(progress.is_cancellable),
9882 }),
9883 })
9884 }
9885
9886 fn on_lsp_work_progress(
9887 &mut self,
9888 language_server_id: LanguageServerId,
9889 token: ProgressToken,
9890 progress: LanguageServerProgress,
9891 cx: &mut Context<Self>,
9892 ) {
9893 let mut did_update = false;
9894 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9895 match status.pending_work.entry(token.clone()) {
9896 btree_map::Entry::Vacant(entry) => {
9897 entry.insert(progress.clone());
9898 did_update = true;
9899 }
9900 btree_map::Entry::Occupied(mut entry) => {
9901 let entry = entry.get_mut();
9902 if (progress.last_update_at - entry.last_update_at)
9903 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9904 {
9905 entry.last_update_at = progress.last_update_at;
9906 if progress.message.is_some() {
9907 entry.message = progress.message.clone();
9908 }
9909 if progress.percentage.is_some() {
9910 entry.percentage = progress.percentage;
9911 }
9912 if progress.is_cancellable != entry.is_cancellable {
9913 entry.is_cancellable = progress.is_cancellable;
9914 }
9915 did_update = true;
9916 }
9917 }
9918 }
9919 }
9920
9921 if did_update {
9922 cx.emit(LspStoreEvent::LanguageServerUpdate {
9923 language_server_id,
9924 name: self
9925 .language_server_adapter_for_id(language_server_id)
9926 .map(|adapter| adapter.name()),
9927 message: proto::update_language_server::Variant::WorkProgress(
9928 proto::LspWorkProgress {
9929 token: Some(token.to_proto()),
9930 message: progress.message,
9931 percentage: progress.percentage.map(|p| p as u32),
9932 is_cancellable: Some(progress.is_cancellable),
9933 },
9934 ),
9935 })
9936 }
9937 }
9938
9939 fn on_lsp_work_end(
9940 &mut self,
9941 language_server_id: LanguageServerId,
9942 token: ProgressToken,
9943 cx: &mut Context<Self>,
9944 ) {
9945 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9946 if let Some(work) = status.pending_work.remove(&token)
9947 && !work.is_disk_based_diagnostics_progress
9948 {
9949 cx.emit(LspStoreEvent::RefreshInlayHints {
9950 server_id: language_server_id,
9951 request_id: None,
9952 });
9953 }
9954 cx.notify();
9955 }
9956
9957 cx.emit(LspStoreEvent::LanguageServerUpdate {
9958 language_server_id,
9959 name: self
9960 .language_server_adapter_for_id(language_server_id)
9961 .map(|adapter| adapter.name()),
9962 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9963 token: Some(token.to_proto()),
9964 }),
9965 })
9966 }
9967
9968 pub async fn handle_resolve_completion_documentation(
9969 this: Entity<Self>,
9970 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9971 mut cx: AsyncApp,
9972 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9973 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9974
9975 let completion = this
9976 .read_with(&cx, |this, cx| {
9977 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9978 let server = this
9979 .language_server_for_id(id)
9980 .with_context(|| format!("No language server {id}"))?;
9981
9982 anyhow::Ok(cx.background_spawn(async move {
9983 let can_resolve = server
9984 .capabilities()
9985 .completion_provider
9986 .as_ref()
9987 .and_then(|options| options.resolve_provider)
9988 .unwrap_or(false);
9989 if can_resolve {
9990 server
9991 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9992 .await
9993 .into_response()
9994 .context("resolve completion item")
9995 } else {
9996 anyhow::Ok(lsp_completion)
9997 }
9998 }))
9999 })??
10000 .await?;
10001
10002 let mut documentation_is_markdown = false;
10003 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10004 let documentation = match completion.documentation {
10005 Some(lsp::Documentation::String(text)) => text,
10006
10007 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10008 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10009 value
10010 }
10011
10012 _ => String::new(),
10013 };
10014
10015 // If we have a new buffer_id, that means we're talking to a new client
10016 // and want to check for new text_edits in the completion too.
10017 let mut old_replace_start = None;
10018 let mut old_replace_end = None;
10019 let mut old_insert_start = None;
10020 let mut old_insert_end = None;
10021 let mut new_text = String::default();
10022 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10023 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10024 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10025 anyhow::Ok(buffer.read(cx).snapshot())
10026 })??;
10027
10028 if let Some(text_edit) = completion.text_edit.as_ref() {
10029 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10030
10031 if let Some(mut edit) = edit {
10032 LineEnding::normalize(&mut edit.new_text);
10033
10034 new_text = edit.new_text;
10035 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10036 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10037 if let Some(insert_range) = edit.insert_range {
10038 old_insert_start = Some(serialize_anchor(&insert_range.start));
10039 old_insert_end = Some(serialize_anchor(&insert_range.end));
10040 }
10041 }
10042 }
10043 }
10044
10045 Ok(proto::ResolveCompletionDocumentationResponse {
10046 documentation,
10047 documentation_is_markdown,
10048 old_replace_start,
10049 old_replace_end,
10050 new_text,
10051 lsp_completion,
10052 old_insert_start,
10053 old_insert_end,
10054 })
10055 }
10056
10057 async fn handle_on_type_formatting(
10058 this: Entity<Self>,
10059 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10060 mut cx: AsyncApp,
10061 ) -> Result<proto::OnTypeFormattingResponse> {
10062 let on_type_formatting = this.update(&mut cx, |this, cx| {
10063 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10064 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10065 let position = envelope
10066 .payload
10067 .position
10068 .and_then(deserialize_anchor)
10069 .context("invalid position")?;
10070 anyhow::Ok(this.apply_on_type_formatting(
10071 buffer,
10072 position,
10073 envelope.payload.trigger.clone(),
10074 cx,
10075 ))
10076 })??;
10077
10078 let transaction = on_type_formatting
10079 .await?
10080 .as_ref()
10081 .map(language::proto::serialize_transaction);
10082 Ok(proto::OnTypeFormattingResponse { transaction })
10083 }
10084
10085 async fn handle_refresh_inlay_hints(
10086 lsp_store: Entity<Self>,
10087 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10088 mut cx: AsyncApp,
10089 ) -> Result<proto::Ack> {
10090 lsp_store.update(&mut cx, |_, cx| {
10091 cx.emit(LspStoreEvent::RefreshInlayHints {
10092 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10093 request_id: envelope.payload.request_id.map(|id| id as usize),
10094 });
10095 })?;
10096 Ok(proto::Ack {})
10097 }
10098
10099 async fn handle_pull_workspace_diagnostics(
10100 lsp_store: Entity<Self>,
10101 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10102 mut cx: AsyncApp,
10103 ) -> Result<proto::Ack> {
10104 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10105 lsp_store.update(&mut cx, |lsp_store, _| {
10106 lsp_store.pull_workspace_diagnostics(server_id);
10107 })?;
10108 Ok(proto::Ack {})
10109 }
10110
10111 async fn handle_get_color_presentation(
10112 lsp_store: Entity<Self>,
10113 envelope: TypedEnvelope<proto::GetColorPresentation>,
10114 mut cx: AsyncApp,
10115 ) -> Result<proto::GetColorPresentationResponse> {
10116 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10117 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10118 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10119 })??;
10120
10121 let color = envelope
10122 .payload
10123 .color
10124 .context("invalid color resolve request")?;
10125 let start = color
10126 .lsp_range_start
10127 .context("invalid color resolve request")?;
10128 let end = color
10129 .lsp_range_end
10130 .context("invalid color resolve request")?;
10131
10132 let color = DocumentColor {
10133 lsp_range: lsp::Range {
10134 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10135 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10136 },
10137 color: lsp::Color {
10138 red: color.red,
10139 green: color.green,
10140 blue: color.blue,
10141 alpha: color.alpha,
10142 },
10143 resolved: false,
10144 color_presentations: Vec::new(),
10145 };
10146 let resolved_color = lsp_store
10147 .update(&mut cx, |lsp_store, cx| {
10148 lsp_store.resolve_color_presentation(
10149 color,
10150 buffer.clone(),
10151 LanguageServerId(envelope.payload.server_id as usize),
10152 cx,
10153 )
10154 })?
10155 .await
10156 .context("resolving color presentation")?;
10157
10158 Ok(proto::GetColorPresentationResponse {
10159 presentations: resolved_color
10160 .color_presentations
10161 .into_iter()
10162 .map(|presentation| proto::ColorPresentation {
10163 label: presentation.label.to_string(),
10164 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10165 additional_text_edits: presentation
10166 .additional_text_edits
10167 .into_iter()
10168 .map(serialize_lsp_edit)
10169 .collect(),
10170 })
10171 .collect(),
10172 })
10173 }
10174
10175 async fn handle_resolve_inlay_hint(
10176 lsp_store: Entity<Self>,
10177 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10178 mut cx: AsyncApp,
10179 ) -> Result<proto::ResolveInlayHintResponse> {
10180 let proto_hint = envelope
10181 .payload
10182 .hint
10183 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10184 let hint = InlayHints::proto_to_project_hint(proto_hint)
10185 .context("resolved proto inlay hint conversion")?;
10186 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10187 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10188 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10189 })??;
10190 let response_hint = lsp_store
10191 .update(&mut cx, |lsp_store, cx| {
10192 lsp_store.resolve_inlay_hint(
10193 hint,
10194 buffer,
10195 LanguageServerId(envelope.payload.language_server_id as usize),
10196 cx,
10197 )
10198 })?
10199 .await
10200 .context("inlay hints fetch")?;
10201 Ok(proto::ResolveInlayHintResponse {
10202 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10203 })
10204 }
10205
10206 async fn handle_refresh_code_lens(
10207 this: Entity<Self>,
10208 _: TypedEnvelope<proto::RefreshCodeLens>,
10209 mut cx: AsyncApp,
10210 ) -> Result<proto::Ack> {
10211 this.update(&mut cx, |_, cx| {
10212 cx.emit(LspStoreEvent::RefreshCodeLens);
10213 })?;
10214 Ok(proto::Ack {})
10215 }
10216
10217 async fn handle_open_buffer_for_symbol(
10218 this: Entity<Self>,
10219 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10220 mut cx: AsyncApp,
10221 ) -> Result<proto::OpenBufferForSymbolResponse> {
10222 let peer_id = envelope.original_sender_id().unwrap_or_default();
10223 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10224 let symbol = Self::deserialize_symbol(symbol)?;
10225 this.read_with(&cx, |this, _| {
10226 if let SymbolLocation::OutsideProject {
10227 abs_path,
10228 signature,
10229 } = &symbol.path
10230 {
10231 let new_signature = this.symbol_signature(&abs_path);
10232 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10233 }
10234 Ok(())
10235 })??;
10236 let buffer = this
10237 .update(&mut cx, |this, cx| {
10238 this.open_buffer_for_symbol(
10239 &Symbol {
10240 language_server_name: symbol.language_server_name,
10241 source_worktree_id: symbol.source_worktree_id,
10242 source_language_server_id: symbol.source_language_server_id,
10243 path: symbol.path,
10244 name: symbol.name,
10245 kind: symbol.kind,
10246 range: symbol.range,
10247 label: CodeLabel::default(),
10248 },
10249 cx,
10250 )
10251 })?
10252 .await?;
10253
10254 this.update(&mut cx, |this, cx| {
10255 let is_private = buffer
10256 .read(cx)
10257 .file()
10258 .map(|f| f.is_private())
10259 .unwrap_or_default();
10260 if is_private {
10261 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10262 } else {
10263 this.buffer_store
10264 .update(cx, |buffer_store, cx| {
10265 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10266 })
10267 .detach_and_log_err(cx);
10268 let buffer_id = buffer.read(cx).remote_id().to_proto();
10269 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10270 }
10271 })?
10272 }
10273
10274 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10275 let mut hasher = Sha256::new();
10276 hasher.update(abs_path.to_string_lossy().as_bytes());
10277 hasher.update(self.nonce.to_be_bytes());
10278 hasher.finalize().as_slice().try_into().unwrap()
10279 }
10280
10281 pub async fn handle_get_project_symbols(
10282 this: Entity<Self>,
10283 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10284 mut cx: AsyncApp,
10285 ) -> Result<proto::GetProjectSymbolsResponse> {
10286 let symbols = this
10287 .update(&mut cx, |this, cx| {
10288 this.symbols(&envelope.payload.query, cx)
10289 })?
10290 .await?;
10291
10292 Ok(proto::GetProjectSymbolsResponse {
10293 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10294 })
10295 }
10296
10297 pub async fn handle_restart_language_servers(
10298 this: Entity<Self>,
10299 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10300 mut cx: AsyncApp,
10301 ) -> Result<proto::Ack> {
10302 this.update(&mut cx, |lsp_store, cx| {
10303 let buffers =
10304 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10305 lsp_store.restart_language_servers_for_buffers(
10306 buffers,
10307 envelope
10308 .payload
10309 .only_servers
10310 .into_iter()
10311 .filter_map(|selector| {
10312 Some(match selector.selector? {
10313 proto::language_server_selector::Selector::ServerId(server_id) => {
10314 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10315 }
10316 proto::language_server_selector::Selector::Name(name) => {
10317 LanguageServerSelector::Name(LanguageServerName(
10318 SharedString::from(name),
10319 ))
10320 }
10321 })
10322 })
10323 .collect(),
10324 cx,
10325 );
10326 })?;
10327
10328 Ok(proto::Ack {})
10329 }
10330
10331 pub async fn handle_stop_language_servers(
10332 lsp_store: Entity<Self>,
10333 envelope: TypedEnvelope<proto::StopLanguageServers>,
10334 mut cx: AsyncApp,
10335 ) -> Result<proto::Ack> {
10336 lsp_store.update(&mut cx, |lsp_store, cx| {
10337 if envelope.payload.all
10338 && envelope.payload.also_servers.is_empty()
10339 && envelope.payload.buffer_ids.is_empty()
10340 {
10341 lsp_store.stop_all_language_servers(cx);
10342 } else {
10343 let buffers =
10344 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10345 lsp_store
10346 .stop_language_servers_for_buffers(
10347 buffers,
10348 envelope
10349 .payload
10350 .also_servers
10351 .into_iter()
10352 .filter_map(|selector| {
10353 Some(match selector.selector? {
10354 proto::language_server_selector::Selector::ServerId(
10355 server_id,
10356 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10357 server_id,
10358 )),
10359 proto::language_server_selector::Selector::Name(name) => {
10360 LanguageServerSelector::Name(LanguageServerName(
10361 SharedString::from(name),
10362 ))
10363 }
10364 })
10365 })
10366 .collect(),
10367 cx,
10368 )
10369 .detach_and_log_err(cx);
10370 }
10371 })?;
10372
10373 Ok(proto::Ack {})
10374 }
10375
10376 pub async fn handle_cancel_language_server_work(
10377 lsp_store: Entity<Self>,
10378 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10379 mut cx: AsyncApp,
10380 ) -> Result<proto::Ack> {
10381 lsp_store.update(&mut cx, |lsp_store, cx| {
10382 if let Some(work) = envelope.payload.work {
10383 match work {
10384 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10385 let buffers =
10386 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10387 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10388 }
10389 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10390 let server_id = LanguageServerId::from_proto(work.language_server_id);
10391 let token = work
10392 .token
10393 .map(|token| {
10394 ProgressToken::from_proto(token)
10395 .context("invalid work progress token")
10396 })
10397 .transpose()?;
10398 lsp_store.cancel_language_server_work(server_id, token, cx);
10399 }
10400 }
10401 }
10402 anyhow::Ok(())
10403 })??;
10404
10405 Ok(proto::Ack {})
10406 }
10407
10408 fn buffer_ids_to_buffers(
10409 &mut self,
10410 buffer_ids: impl Iterator<Item = u64>,
10411 cx: &mut Context<Self>,
10412 ) -> Vec<Entity<Buffer>> {
10413 buffer_ids
10414 .into_iter()
10415 .flat_map(|buffer_id| {
10416 self.buffer_store
10417 .read(cx)
10418 .get(BufferId::new(buffer_id).log_err()?)
10419 })
10420 .collect::<Vec<_>>()
10421 }
10422
10423 async fn handle_apply_additional_edits_for_completion(
10424 this: Entity<Self>,
10425 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10426 mut cx: AsyncApp,
10427 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10428 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10429 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10430 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10431 let completion = Self::deserialize_completion(
10432 envelope.payload.completion.context("invalid completion")?,
10433 )?;
10434 anyhow::Ok((buffer, completion))
10435 })??;
10436
10437 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10438 this.apply_additional_edits_for_completion(
10439 buffer,
10440 Rc::new(RefCell::new(Box::new([Completion {
10441 replace_range: completion.replace_range,
10442 new_text: completion.new_text,
10443 source: completion.source,
10444 documentation: None,
10445 label: CodeLabel::default(),
10446 match_start: None,
10447 snippet_deduplication_key: None,
10448 insert_text_mode: None,
10449 icon_path: None,
10450 confirm: None,
10451 }]))),
10452 0,
10453 false,
10454 cx,
10455 )
10456 })?;
10457
10458 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10459 transaction: apply_additional_edits
10460 .await?
10461 .as_ref()
10462 .map(language::proto::serialize_transaction),
10463 })
10464 }
10465
10466 pub fn last_formatting_failure(&self) -> Option<&str> {
10467 self.last_formatting_failure.as_deref()
10468 }
10469
10470 pub fn reset_last_formatting_failure(&mut self) {
10471 self.last_formatting_failure = None;
10472 }
10473
10474 pub fn environment_for_buffer(
10475 &self,
10476 buffer: &Entity<Buffer>,
10477 cx: &mut Context<Self>,
10478 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10479 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10480 environment.update(cx, |env, cx| {
10481 env.buffer_environment(buffer, &self.worktree_store, cx)
10482 })
10483 } else {
10484 Task::ready(None).shared()
10485 }
10486 }
10487
10488 pub fn format(
10489 &mut self,
10490 buffers: HashSet<Entity<Buffer>>,
10491 target: LspFormatTarget,
10492 push_to_history: bool,
10493 trigger: FormatTrigger,
10494 cx: &mut Context<Self>,
10495 ) -> Task<anyhow::Result<ProjectTransaction>> {
10496 let logger = zlog::scoped!("format");
10497 if self.as_local().is_some() {
10498 zlog::trace!(logger => "Formatting locally");
10499 let logger = zlog::scoped!(logger => "local");
10500 let buffers = buffers
10501 .into_iter()
10502 .map(|buffer_handle| {
10503 let buffer = buffer_handle.read(cx);
10504 let buffer_abs_path = File::from_dyn(buffer.file())
10505 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10506
10507 (buffer_handle, buffer_abs_path, buffer.remote_id())
10508 })
10509 .collect::<Vec<_>>();
10510
10511 cx.spawn(async move |lsp_store, cx| {
10512 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10513
10514 for (handle, abs_path, id) in buffers {
10515 let env = lsp_store
10516 .update(cx, |lsp_store, cx| {
10517 lsp_store.environment_for_buffer(&handle, cx)
10518 })?
10519 .await;
10520
10521 let ranges = match &target {
10522 LspFormatTarget::Buffers => None,
10523 LspFormatTarget::Ranges(ranges) => {
10524 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10525 }
10526 };
10527
10528 formattable_buffers.push(FormattableBuffer {
10529 handle,
10530 abs_path,
10531 env,
10532 ranges,
10533 });
10534 }
10535 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10536
10537 let format_timer = zlog::time!(logger => "Formatting buffers");
10538 let result = LocalLspStore::format_locally(
10539 lsp_store.clone(),
10540 formattable_buffers,
10541 push_to_history,
10542 trigger,
10543 logger,
10544 cx,
10545 )
10546 .await;
10547 format_timer.end();
10548
10549 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10550
10551 lsp_store.update(cx, |lsp_store, _| {
10552 lsp_store.update_last_formatting_failure(&result);
10553 })?;
10554
10555 result
10556 })
10557 } else if let Some((client, project_id)) = self.upstream_client() {
10558 zlog::trace!(logger => "Formatting remotely");
10559 let logger = zlog::scoped!(logger => "remote");
10560 // Don't support formatting ranges via remote
10561 match target {
10562 LspFormatTarget::Buffers => {}
10563 LspFormatTarget::Ranges(_) => {
10564 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10565 return Task::ready(Ok(ProjectTransaction::default()));
10566 }
10567 }
10568
10569 let buffer_store = self.buffer_store();
10570 cx.spawn(async move |lsp_store, cx| {
10571 zlog::trace!(logger => "Sending remote format request");
10572 let request_timer = zlog::time!(logger => "remote format request");
10573 let result = client
10574 .request(proto::FormatBuffers {
10575 project_id,
10576 trigger: trigger as i32,
10577 buffer_ids: buffers
10578 .iter()
10579 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10580 .collect::<Result<_>>()?,
10581 })
10582 .await
10583 .and_then(|result| result.transaction.context("missing transaction"));
10584 request_timer.end();
10585
10586 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10587
10588 lsp_store.update(cx, |lsp_store, _| {
10589 lsp_store.update_last_formatting_failure(&result);
10590 })?;
10591
10592 let transaction_response = result?;
10593 let _timer = zlog::time!(logger => "deserializing project transaction");
10594 buffer_store
10595 .update(cx, |buffer_store, cx| {
10596 buffer_store.deserialize_project_transaction(
10597 transaction_response,
10598 push_to_history,
10599 cx,
10600 )
10601 })?
10602 .await
10603 })
10604 } else {
10605 zlog::trace!(logger => "Not formatting");
10606 Task::ready(Ok(ProjectTransaction::default()))
10607 }
10608 }
10609
10610 async fn handle_format_buffers(
10611 this: Entity<Self>,
10612 envelope: TypedEnvelope<proto::FormatBuffers>,
10613 mut cx: AsyncApp,
10614 ) -> Result<proto::FormatBuffersResponse> {
10615 let sender_id = envelope.original_sender_id().unwrap_or_default();
10616 let format = this.update(&mut cx, |this, cx| {
10617 let mut buffers = HashSet::default();
10618 for buffer_id in &envelope.payload.buffer_ids {
10619 let buffer_id = BufferId::new(*buffer_id)?;
10620 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10621 }
10622 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10623 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10624 })??;
10625
10626 let project_transaction = format.await?;
10627 let project_transaction = this.update(&mut cx, |this, cx| {
10628 this.buffer_store.update(cx, |buffer_store, cx| {
10629 buffer_store.serialize_project_transaction_for_peer(
10630 project_transaction,
10631 sender_id,
10632 cx,
10633 )
10634 })
10635 })?;
10636 Ok(proto::FormatBuffersResponse {
10637 transaction: Some(project_transaction),
10638 })
10639 }
10640
10641 async fn handle_apply_code_action_kind(
10642 this: Entity<Self>,
10643 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10644 mut cx: AsyncApp,
10645 ) -> Result<proto::ApplyCodeActionKindResponse> {
10646 let sender_id = envelope.original_sender_id().unwrap_or_default();
10647 let format = this.update(&mut cx, |this, cx| {
10648 let mut buffers = HashSet::default();
10649 for buffer_id in &envelope.payload.buffer_ids {
10650 let buffer_id = BufferId::new(*buffer_id)?;
10651 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10652 }
10653 let kind = match envelope.payload.kind.as_str() {
10654 "" => CodeActionKind::EMPTY,
10655 "quickfix" => CodeActionKind::QUICKFIX,
10656 "refactor" => CodeActionKind::REFACTOR,
10657 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10658 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10659 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10660 "source" => CodeActionKind::SOURCE,
10661 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10662 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10663 _ => anyhow::bail!(
10664 "Invalid code action kind {}",
10665 envelope.payload.kind.as_str()
10666 ),
10667 };
10668 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10669 })??;
10670
10671 let project_transaction = format.await?;
10672 let project_transaction = this.update(&mut cx, |this, cx| {
10673 this.buffer_store.update(cx, |buffer_store, cx| {
10674 buffer_store.serialize_project_transaction_for_peer(
10675 project_transaction,
10676 sender_id,
10677 cx,
10678 )
10679 })
10680 })?;
10681 Ok(proto::ApplyCodeActionKindResponse {
10682 transaction: Some(project_transaction),
10683 })
10684 }
10685
10686 async fn shutdown_language_server(
10687 server_state: Option<LanguageServerState>,
10688 name: LanguageServerName,
10689 cx: &mut AsyncApp,
10690 ) {
10691 let server = match server_state {
10692 Some(LanguageServerState::Starting { startup, .. }) => {
10693 let mut timer = cx
10694 .background_executor()
10695 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10696 .fuse();
10697
10698 select! {
10699 server = startup.fuse() => server,
10700 () = timer => {
10701 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10702 None
10703 },
10704 }
10705 }
10706
10707 Some(LanguageServerState::Running { server, .. }) => Some(server),
10708
10709 None => None,
10710 };
10711
10712 if let Some(server) = server
10713 && let Some(shutdown) = server.shutdown()
10714 {
10715 shutdown.await;
10716 }
10717 }
10718
10719 // Returns a list of all of the worktrees which no longer have a language server and the root path
10720 // for the stopped server
10721 fn stop_local_language_server(
10722 &mut self,
10723 server_id: LanguageServerId,
10724 cx: &mut Context<Self>,
10725 ) -> Task<()> {
10726 let local = match &mut self.mode {
10727 LspStoreMode::Local(local) => local,
10728 _ => {
10729 return Task::ready(());
10730 }
10731 };
10732
10733 // Remove this server ID from all entries in the given worktree.
10734 local
10735 .language_server_ids
10736 .retain(|_, state| state.id != server_id);
10737 self.buffer_store.update(cx, |buffer_store, cx| {
10738 for buffer in buffer_store.buffers() {
10739 buffer.update(cx, |buffer, cx| {
10740 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10741 buffer.set_completion_triggers(server_id, Default::default(), cx);
10742 });
10743 }
10744 });
10745
10746 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10747 summaries.retain(|path, summaries_by_server_id| {
10748 if summaries_by_server_id.remove(&server_id).is_some() {
10749 if let Some((client, project_id)) = self.downstream_client.clone() {
10750 client
10751 .send(proto::UpdateDiagnosticSummary {
10752 project_id,
10753 worktree_id: worktree_id.to_proto(),
10754 summary: Some(proto::DiagnosticSummary {
10755 path: path.as_ref().to_proto(),
10756 language_server_id: server_id.0 as u64,
10757 error_count: 0,
10758 warning_count: 0,
10759 }),
10760 more_summaries: Vec::new(),
10761 })
10762 .log_err();
10763 }
10764 !summaries_by_server_id.is_empty()
10765 } else {
10766 true
10767 }
10768 });
10769 }
10770
10771 let local = self.as_local_mut().unwrap();
10772 for diagnostics in local.diagnostics.values_mut() {
10773 diagnostics.retain(|_, diagnostics_by_server_id| {
10774 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10775 diagnostics_by_server_id.remove(ix);
10776 !diagnostics_by_server_id.is_empty()
10777 } else {
10778 true
10779 }
10780 });
10781 }
10782 local.language_server_watched_paths.remove(&server_id);
10783
10784 let server_state = local.language_servers.remove(&server_id);
10785 self.cleanup_lsp_data(server_id);
10786 let name = self
10787 .language_server_statuses
10788 .remove(&server_id)
10789 .map(|status| status.name)
10790 .or_else(|| {
10791 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10792 Some(adapter.name())
10793 } else {
10794 None
10795 }
10796 });
10797
10798 if let Some(name) = name {
10799 log::info!("stopping language server {name}");
10800 self.languages
10801 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10802 cx.notify();
10803
10804 return cx.spawn(async move |lsp_store, cx| {
10805 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10806 lsp_store
10807 .update(cx, |lsp_store, cx| {
10808 lsp_store
10809 .languages
10810 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10811 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10812 cx.notify();
10813 })
10814 .ok();
10815 });
10816 }
10817
10818 if server_state.is_some() {
10819 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10820 }
10821 Task::ready(())
10822 }
10823
10824 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10825 if let Some((client, project_id)) = self.upstream_client() {
10826 let request = client.request(proto::StopLanguageServers {
10827 project_id,
10828 buffer_ids: Vec::new(),
10829 also_servers: Vec::new(),
10830 all: true,
10831 });
10832 cx.background_spawn(request).detach_and_log_err(cx);
10833 } else {
10834 let Some(local) = self.as_local_mut() else {
10835 return;
10836 };
10837 let language_servers_to_stop = local
10838 .language_server_ids
10839 .values()
10840 .map(|state| state.id)
10841 .collect();
10842 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10843 let tasks = language_servers_to_stop
10844 .into_iter()
10845 .map(|server| self.stop_local_language_server(server, cx))
10846 .collect::<Vec<_>>();
10847 cx.background_spawn(async move {
10848 futures::future::join_all(tasks).await;
10849 })
10850 .detach();
10851 }
10852 }
10853
10854 pub fn restart_language_servers_for_buffers(
10855 &mut self,
10856 buffers: Vec<Entity<Buffer>>,
10857 only_restart_servers: HashSet<LanguageServerSelector>,
10858 cx: &mut Context<Self>,
10859 ) {
10860 if let Some((client, project_id)) = self.upstream_client() {
10861 let request = client.request(proto::RestartLanguageServers {
10862 project_id,
10863 buffer_ids: buffers
10864 .into_iter()
10865 .map(|b| b.read(cx).remote_id().to_proto())
10866 .collect(),
10867 only_servers: only_restart_servers
10868 .into_iter()
10869 .map(|selector| {
10870 let selector = match selector {
10871 LanguageServerSelector::Id(language_server_id) => {
10872 proto::language_server_selector::Selector::ServerId(
10873 language_server_id.to_proto(),
10874 )
10875 }
10876 LanguageServerSelector::Name(language_server_name) => {
10877 proto::language_server_selector::Selector::Name(
10878 language_server_name.to_string(),
10879 )
10880 }
10881 };
10882 proto::LanguageServerSelector {
10883 selector: Some(selector),
10884 }
10885 })
10886 .collect(),
10887 all: false,
10888 });
10889 cx.background_spawn(request).detach_and_log_err(cx);
10890 } else {
10891 let stop_task = if only_restart_servers.is_empty() {
10892 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10893 } else {
10894 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10895 };
10896 cx.spawn(async move |lsp_store, cx| {
10897 stop_task.await;
10898 lsp_store
10899 .update(cx, |lsp_store, cx| {
10900 for buffer in buffers {
10901 lsp_store.register_buffer_with_language_servers(
10902 &buffer,
10903 only_restart_servers.clone(),
10904 true,
10905 cx,
10906 );
10907 }
10908 })
10909 .ok()
10910 })
10911 .detach();
10912 }
10913 }
10914
10915 pub fn stop_language_servers_for_buffers(
10916 &mut self,
10917 buffers: Vec<Entity<Buffer>>,
10918 also_stop_servers: HashSet<LanguageServerSelector>,
10919 cx: &mut Context<Self>,
10920 ) -> Task<Result<()>> {
10921 if let Some((client, project_id)) = self.upstream_client() {
10922 let request = client.request(proto::StopLanguageServers {
10923 project_id,
10924 buffer_ids: buffers
10925 .into_iter()
10926 .map(|b| b.read(cx).remote_id().to_proto())
10927 .collect(),
10928 also_servers: also_stop_servers
10929 .into_iter()
10930 .map(|selector| {
10931 let selector = match selector {
10932 LanguageServerSelector::Id(language_server_id) => {
10933 proto::language_server_selector::Selector::ServerId(
10934 language_server_id.to_proto(),
10935 )
10936 }
10937 LanguageServerSelector::Name(language_server_name) => {
10938 proto::language_server_selector::Selector::Name(
10939 language_server_name.to_string(),
10940 )
10941 }
10942 };
10943 proto::LanguageServerSelector {
10944 selector: Some(selector),
10945 }
10946 })
10947 .collect(),
10948 all: false,
10949 });
10950 cx.background_spawn(async move {
10951 let _ = request.await?;
10952 Ok(())
10953 })
10954 } else {
10955 let task =
10956 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10957 cx.background_spawn(async move {
10958 task.await;
10959 Ok(())
10960 })
10961 }
10962 }
10963
10964 fn stop_local_language_servers_for_buffers(
10965 &mut self,
10966 buffers: &[Entity<Buffer>],
10967 also_stop_servers: HashSet<LanguageServerSelector>,
10968 cx: &mut Context<Self>,
10969 ) -> Task<()> {
10970 let Some(local) = self.as_local_mut() else {
10971 return Task::ready(());
10972 };
10973 let mut language_server_names_to_stop = BTreeSet::default();
10974 let mut language_servers_to_stop = also_stop_servers
10975 .into_iter()
10976 .flat_map(|selector| match selector {
10977 LanguageServerSelector::Id(id) => Some(id),
10978 LanguageServerSelector::Name(name) => {
10979 language_server_names_to_stop.insert(name);
10980 None
10981 }
10982 })
10983 .collect::<BTreeSet<_>>();
10984
10985 let mut covered_worktrees = HashSet::default();
10986 for buffer in buffers {
10987 buffer.update(cx, |buffer, cx| {
10988 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10989 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10990 && covered_worktrees.insert(worktree_id)
10991 {
10992 language_server_names_to_stop.retain(|name| {
10993 let old_ids_count = language_servers_to_stop.len();
10994 let all_language_servers_with_this_name = local
10995 .language_server_ids
10996 .iter()
10997 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10998 language_servers_to_stop.extend(all_language_servers_with_this_name);
10999 old_ids_count == language_servers_to_stop.len()
11000 });
11001 }
11002 });
11003 }
11004 for name in language_server_names_to_stop {
11005 language_servers_to_stop.extend(
11006 local
11007 .language_server_ids
11008 .iter()
11009 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11010 );
11011 }
11012
11013 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11014 let tasks = language_servers_to_stop
11015 .into_iter()
11016 .map(|server| self.stop_local_language_server(server, cx))
11017 .collect::<Vec<_>>();
11018
11019 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11020 }
11021
11022 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11023 let (worktree, relative_path) =
11024 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11025
11026 let project_path = ProjectPath {
11027 worktree_id: worktree.read(cx).id(),
11028 path: relative_path,
11029 };
11030
11031 Some(
11032 self.buffer_store()
11033 .read(cx)
11034 .get_by_path(&project_path)?
11035 .read(cx),
11036 )
11037 }
11038
11039 #[cfg(any(test, feature = "test-support"))]
11040 pub fn update_diagnostics(
11041 &mut self,
11042 server_id: LanguageServerId,
11043 diagnostics: lsp::PublishDiagnosticsParams,
11044 result_id: Option<SharedString>,
11045 source_kind: DiagnosticSourceKind,
11046 disk_based_sources: &[String],
11047 cx: &mut Context<Self>,
11048 ) -> Result<()> {
11049 self.merge_lsp_diagnostics(
11050 source_kind,
11051 vec![DocumentDiagnosticsUpdate {
11052 diagnostics,
11053 result_id,
11054 server_id,
11055 disk_based_sources: Cow::Borrowed(disk_based_sources),
11056 registration_id: None,
11057 }],
11058 |_, _, _| false,
11059 cx,
11060 )
11061 }
11062
11063 pub fn merge_lsp_diagnostics(
11064 &mut self,
11065 source_kind: DiagnosticSourceKind,
11066 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11067 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11068 cx: &mut Context<Self>,
11069 ) -> Result<()> {
11070 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11071 let updates = lsp_diagnostics
11072 .into_iter()
11073 .filter_map(|update| {
11074 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11075 Some(DocumentDiagnosticsUpdate {
11076 diagnostics: self.lsp_to_document_diagnostics(
11077 abs_path,
11078 source_kind,
11079 update.server_id,
11080 update.diagnostics,
11081 &update.disk_based_sources,
11082 update.registration_id.clone(),
11083 ),
11084 result_id: update.result_id,
11085 server_id: update.server_id,
11086 disk_based_sources: update.disk_based_sources,
11087 registration_id: update.registration_id,
11088 })
11089 })
11090 .collect();
11091 self.merge_diagnostic_entries(updates, merge, cx)?;
11092 Ok(())
11093 }
11094
11095 fn lsp_to_document_diagnostics(
11096 &mut self,
11097 document_abs_path: PathBuf,
11098 source_kind: DiagnosticSourceKind,
11099 server_id: LanguageServerId,
11100 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11101 disk_based_sources: &[String],
11102 registration_id: Option<SharedString>,
11103 ) -> DocumentDiagnostics {
11104 let mut diagnostics = Vec::default();
11105 let mut primary_diagnostic_group_ids = HashMap::default();
11106 let mut sources_by_group_id = HashMap::default();
11107 let mut supporting_diagnostics = HashMap::default();
11108
11109 let adapter = self.language_server_adapter_for_id(server_id);
11110
11111 // Ensure that primary diagnostics are always the most severe
11112 lsp_diagnostics
11113 .diagnostics
11114 .sort_by_key(|item| item.severity);
11115
11116 for diagnostic in &lsp_diagnostics.diagnostics {
11117 let source = diagnostic.source.as_ref();
11118 let range = range_from_lsp(diagnostic.range);
11119 let is_supporting = diagnostic
11120 .related_information
11121 .as_ref()
11122 .is_some_and(|infos| {
11123 infos.iter().any(|info| {
11124 primary_diagnostic_group_ids.contains_key(&(
11125 source,
11126 diagnostic.code.clone(),
11127 range_from_lsp(info.location.range),
11128 ))
11129 })
11130 });
11131
11132 let is_unnecessary = diagnostic
11133 .tags
11134 .as_ref()
11135 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11136
11137 let underline = self
11138 .language_server_adapter_for_id(server_id)
11139 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11140
11141 if is_supporting {
11142 supporting_diagnostics.insert(
11143 (source, diagnostic.code.clone(), range),
11144 (diagnostic.severity, is_unnecessary),
11145 );
11146 } else {
11147 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11148 let is_disk_based =
11149 source.is_some_and(|source| disk_based_sources.contains(source));
11150
11151 sources_by_group_id.insert(group_id, source);
11152 primary_diagnostic_group_ids
11153 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11154
11155 diagnostics.push(DiagnosticEntry {
11156 range,
11157 diagnostic: Diagnostic {
11158 source: diagnostic.source.clone(),
11159 source_kind,
11160 code: diagnostic.code.clone(),
11161 code_description: diagnostic
11162 .code_description
11163 .as_ref()
11164 .and_then(|d| d.href.clone()),
11165 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11166 markdown: adapter.as_ref().and_then(|adapter| {
11167 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11168 }),
11169 message: diagnostic.message.trim().to_string(),
11170 group_id,
11171 is_primary: true,
11172 is_disk_based,
11173 is_unnecessary,
11174 underline,
11175 data: diagnostic.data.clone(),
11176 registration_id: registration_id.clone(),
11177 },
11178 });
11179 if let Some(infos) = &diagnostic.related_information {
11180 for info in infos {
11181 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11182 let range = range_from_lsp(info.location.range);
11183 diagnostics.push(DiagnosticEntry {
11184 range,
11185 diagnostic: Diagnostic {
11186 source: diagnostic.source.clone(),
11187 source_kind,
11188 code: diagnostic.code.clone(),
11189 code_description: diagnostic
11190 .code_description
11191 .as_ref()
11192 .and_then(|d| d.href.clone()),
11193 severity: DiagnosticSeverity::INFORMATION,
11194 markdown: adapter.as_ref().and_then(|adapter| {
11195 adapter.diagnostic_message_to_markdown(&info.message)
11196 }),
11197 message: info.message.trim().to_string(),
11198 group_id,
11199 is_primary: false,
11200 is_disk_based,
11201 is_unnecessary: false,
11202 underline,
11203 data: diagnostic.data.clone(),
11204 registration_id: registration_id.clone(),
11205 },
11206 });
11207 }
11208 }
11209 }
11210 }
11211 }
11212
11213 for entry in &mut diagnostics {
11214 let diagnostic = &mut entry.diagnostic;
11215 if !diagnostic.is_primary {
11216 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11217 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11218 source,
11219 diagnostic.code.clone(),
11220 entry.range.clone(),
11221 )) {
11222 if let Some(severity) = severity {
11223 diagnostic.severity = severity;
11224 }
11225 diagnostic.is_unnecessary = is_unnecessary;
11226 }
11227 }
11228 }
11229
11230 DocumentDiagnostics {
11231 diagnostics,
11232 document_abs_path,
11233 version: lsp_diagnostics.version,
11234 }
11235 }
11236
11237 fn insert_newly_running_language_server(
11238 &mut self,
11239 adapter: Arc<CachedLspAdapter>,
11240 language_server: Arc<LanguageServer>,
11241 server_id: LanguageServerId,
11242 key: LanguageServerSeed,
11243 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11244 cx: &mut Context<Self>,
11245 ) {
11246 let Some(local) = self.as_local_mut() else {
11247 return;
11248 };
11249 // If the language server for this key doesn't match the server id, don't store the
11250 // server. Which will cause it to be dropped, killing the process
11251 if local
11252 .language_server_ids
11253 .get(&key)
11254 .map(|state| state.id != server_id)
11255 .unwrap_or(false)
11256 {
11257 return;
11258 }
11259
11260 // Update language_servers collection with Running variant of LanguageServerState
11261 // indicating that the server is up and running and ready
11262 let workspace_folders = workspace_folders.lock().clone();
11263 language_server.set_workspace_folders(workspace_folders);
11264
11265 let workspace_diagnostics_refresh_tasks = language_server
11266 .capabilities()
11267 .diagnostic_provider
11268 .and_then(|provider| {
11269 local
11270 .language_server_dynamic_registrations
11271 .entry(server_id)
11272 .or_default()
11273 .diagnostics
11274 .entry(None)
11275 .or_insert(provider.clone());
11276 let workspace_refresher =
11277 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11278
11279 Some((None, workspace_refresher))
11280 })
11281 .into_iter()
11282 .collect();
11283 local.language_servers.insert(
11284 server_id,
11285 LanguageServerState::Running {
11286 workspace_diagnostics_refresh_tasks,
11287 adapter: adapter.clone(),
11288 server: language_server.clone(),
11289 simulate_disk_based_diagnostics_completion: None,
11290 },
11291 );
11292 local
11293 .languages
11294 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11295 if let Some(file_ops_caps) = language_server
11296 .capabilities()
11297 .workspace
11298 .as_ref()
11299 .and_then(|ws| ws.file_operations.as_ref())
11300 {
11301 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11302 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11303 if did_rename_caps.or(will_rename_caps).is_some() {
11304 let watcher = RenamePathsWatchedForServer::default()
11305 .with_did_rename_patterns(did_rename_caps)
11306 .with_will_rename_patterns(will_rename_caps);
11307 local
11308 .language_server_paths_watched_for_rename
11309 .insert(server_id, watcher);
11310 }
11311 }
11312
11313 self.language_server_statuses.insert(
11314 server_id,
11315 LanguageServerStatus {
11316 name: language_server.name(),
11317 pending_work: Default::default(),
11318 has_pending_diagnostic_updates: false,
11319 progress_tokens: Default::default(),
11320 worktree: Some(key.worktree_id),
11321 binary: Some(language_server.binary().clone()),
11322 configuration: Some(language_server.configuration().clone()),
11323 workspace_folders: language_server.workspace_folders(),
11324 },
11325 );
11326
11327 cx.emit(LspStoreEvent::LanguageServerAdded(
11328 server_id,
11329 language_server.name(),
11330 Some(key.worktree_id),
11331 ));
11332
11333 let server_capabilities = language_server.capabilities();
11334 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11335 downstream_client
11336 .send(proto::StartLanguageServer {
11337 project_id: *project_id,
11338 server: Some(proto::LanguageServer {
11339 id: server_id.to_proto(),
11340 name: language_server.name().to_string(),
11341 worktree_id: Some(key.worktree_id.to_proto()),
11342 }),
11343 capabilities: serde_json::to_string(&server_capabilities)
11344 .expect("serializing server LSP capabilities"),
11345 })
11346 .log_err();
11347 }
11348 self.lsp_server_capabilities
11349 .insert(server_id, server_capabilities);
11350
11351 // Tell the language server about every open buffer in the worktree that matches the language.
11352 // Also check for buffers in worktrees that reused this server
11353 let mut worktrees_using_server = vec![key.worktree_id];
11354 if let Some(local) = self.as_local() {
11355 // Find all worktrees that have this server in their language server tree
11356 for (worktree_id, servers) in &local.lsp_tree.instances {
11357 if *worktree_id != key.worktree_id {
11358 for server_map in servers.roots.values() {
11359 if server_map
11360 .values()
11361 .any(|(node, _)| node.id() == Some(server_id))
11362 {
11363 worktrees_using_server.push(*worktree_id);
11364 }
11365 }
11366 }
11367 }
11368 }
11369
11370 let mut buffer_paths_registered = Vec::new();
11371 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11372 let mut lsp_adapters = HashMap::default();
11373 for buffer_handle in buffer_store.buffers() {
11374 let buffer = buffer_handle.read(cx);
11375 let file = match File::from_dyn(buffer.file()) {
11376 Some(file) => file,
11377 None => continue,
11378 };
11379 let language = match buffer.language() {
11380 Some(language) => language,
11381 None => continue,
11382 };
11383
11384 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11385 || !lsp_adapters
11386 .entry(language.name())
11387 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11388 .iter()
11389 .any(|a| a.name == key.name)
11390 {
11391 continue;
11392 }
11393 // didOpen
11394 let file = match file.as_local() {
11395 Some(file) => file,
11396 None => continue,
11397 };
11398
11399 let local = self.as_local_mut().unwrap();
11400
11401 let buffer_id = buffer.remote_id();
11402 if local.registered_buffers.contains_key(&buffer_id) {
11403 let versions = local
11404 .buffer_snapshots
11405 .entry(buffer_id)
11406 .or_default()
11407 .entry(server_id)
11408 .and_modify(|_| {
11409 assert!(
11410 false,
11411 "There should not be an existing snapshot for a newly inserted buffer"
11412 )
11413 })
11414 .or_insert_with(|| {
11415 vec![LspBufferSnapshot {
11416 version: 0,
11417 snapshot: buffer.text_snapshot(),
11418 }]
11419 });
11420
11421 let snapshot = versions.last().unwrap();
11422 let version = snapshot.version;
11423 let initial_snapshot = &snapshot.snapshot;
11424 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11425 language_server.register_buffer(
11426 uri,
11427 adapter.language_id(&language.name()),
11428 version,
11429 initial_snapshot.text(),
11430 );
11431 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11432 local
11433 .buffers_opened_in_servers
11434 .entry(buffer_id)
11435 .or_default()
11436 .insert(server_id);
11437 }
11438 buffer_handle.update(cx, |buffer, cx| {
11439 buffer.set_completion_triggers(
11440 server_id,
11441 language_server
11442 .capabilities()
11443 .completion_provider
11444 .as_ref()
11445 .and_then(|provider| {
11446 provider
11447 .trigger_characters
11448 .as_ref()
11449 .map(|characters| characters.iter().cloned().collect())
11450 })
11451 .unwrap_or_default(),
11452 cx,
11453 )
11454 });
11455 }
11456 });
11457
11458 for (buffer_id, abs_path) in buffer_paths_registered {
11459 cx.emit(LspStoreEvent::LanguageServerUpdate {
11460 language_server_id: server_id,
11461 name: Some(adapter.name()),
11462 message: proto::update_language_server::Variant::RegisteredForBuffer(
11463 proto::RegisteredForBuffer {
11464 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11465 buffer_id: buffer_id.to_proto(),
11466 },
11467 ),
11468 });
11469 }
11470
11471 cx.notify();
11472 }
11473
11474 pub fn language_servers_running_disk_based_diagnostics(
11475 &self,
11476 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11477 self.language_server_statuses
11478 .iter()
11479 .filter_map(|(id, status)| {
11480 if status.has_pending_diagnostic_updates {
11481 Some(*id)
11482 } else {
11483 None
11484 }
11485 })
11486 }
11487
11488 pub(crate) fn cancel_language_server_work_for_buffers(
11489 &mut self,
11490 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11491 cx: &mut Context<Self>,
11492 ) {
11493 if let Some((client, project_id)) = self.upstream_client() {
11494 let request = client.request(proto::CancelLanguageServerWork {
11495 project_id,
11496 work: Some(proto::cancel_language_server_work::Work::Buffers(
11497 proto::cancel_language_server_work::Buffers {
11498 buffer_ids: buffers
11499 .into_iter()
11500 .map(|b| b.read(cx).remote_id().to_proto())
11501 .collect(),
11502 },
11503 )),
11504 });
11505 cx.background_spawn(request).detach_and_log_err(cx);
11506 } else if let Some(local) = self.as_local() {
11507 let servers = buffers
11508 .into_iter()
11509 .flat_map(|buffer| {
11510 buffer.update(cx, |buffer, cx| {
11511 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11512 })
11513 })
11514 .collect::<HashSet<_>>();
11515 for server_id in servers {
11516 self.cancel_language_server_work(server_id, None, cx);
11517 }
11518 }
11519 }
11520
11521 pub(crate) fn cancel_language_server_work(
11522 &mut self,
11523 server_id: LanguageServerId,
11524 token_to_cancel: Option<ProgressToken>,
11525 cx: &mut Context<Self>,
11526 ) {
11527 if let Some(local) = self.as_local() {
11528 let status = self.language_server_statuses.get(&server_id);
11529 let server = local.language_servers.get(&server_id);
11530 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11531 {
11532 for (token, progress) in &status.pending_work {
11533 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11534 && token != token_to_cancel
11535 {
11536 continue;
11537 }
11538 if progress.is_cancellable {
11539 server
11540 .notify::<lsp::notification::WorkDoneProgressCancel>(
11541 WorkDoneProgressCancelParams {
11542 token: token.to_lsp(),
11543 },
11544 )
11545 .ok();
11546 }
11547 }
11548 }
11549 } else if let Some((client, project_id)) = self.upstream_client() {
11550 let request = client.request(proto::CancelLanguageServerWork {
11551 project_id,
11552 work: Some(
11553 proto::cancel_language_server_work::Work::LanguageServerWork(
11554 proto::cancel_language_server_work::LanguageServerWork {
11555 language_server_id: server_id.to_proto(),
11556 token: token_to_cancel.map(|token| token.to_proto()),
11557 },
11558 ),
11559 ),
11560 });
11561 cx.background_spawn(request).detach_and_log_err(cx);
11562 }
11563 }
11564
11565 fn register_supplementary_language_server(
11566 &mut self,
11567 id: LanguageServerId,
11568 name: LanguageServerName,
11569 server: Arc<LanguageServer>,
11570 cx: &mut Context<Self>,
11571 ) {
11572 if let Some(local) = self.as_local_mut() {
11573 local
11574 .supplementary_language_servers
11575 .insert(id, (name.clone(), server));
11576 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11577 }
11578 }
11579
11580 fn unregister_supplementary_language_server(
11581 &mut self,
11582 id: LanguageServerId,
11583 cx: &mut Context<Self>,
11584 ) {
11585 if let Some(local) = self.as_local_mut() {
11586 local.supplementary_language_servers.remove(&id);
11587 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11588 }
11589 }
11590
11591 pub(crate) fn supplementary_language_servers(
11592 &self,
11593 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11594 self.as_local().into_iter().flat_map(|local| {
11595 local
11596 .supplementary_language_servers
11597 .iter()
11598 .map(|(id, (name, _))| (*id, name.clone()))
11599 })
11600 }
11601
11602 pub fn language_server_adapter_for_id(
11603 &self,
11604 id: LanguageServerId,
11605 ) -> Option<Arc<CachedLspAdapter>> {
11606 self.as_local()
11607 .and_then(|local| local.language_servers.get(&id))
11608 .and_then(|language_server_state| match language_server_state {
11609 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11610 _ => None,
11611 })
11612 }
11613
11614 pub(super) fn update_local_worktree_language_servers(
11615 &mut self,
11616 worktree_handle: &Entity<Worktree>,
11617 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11618 cx: &mut Context<Self>,
11619 ) {
11620 if changes.is_empty() {
11621 return;
11622 }
11623
11624 let Some(local) = self.as_local() else { return };
11625
11626 local.prettier_store.update(cx, |prettier_store, cx| {
11627 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11628 });
11629
11630 let worktree_id = worktree_handle.read(cx).id();
11631 let mut language_server_ids = local
11632 .language_server_ids
11633 .iter()
11634 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11635 .collect::<Vec<_>>();
11636 language_server_ids.sort();
11637 language_server_ids.dedup();
11638
11639 // let abs_path = worktree_handle.read(cx).abs_path();
11640 for server_id in &language_server_ids {
11641 if let Some(LanguageServerState::Running { server, .. }) =
11642 local.language_servers.get(server_id)
11643 && let Some(watched_paths) = local
11644 .language_server_watched_paths
11645 .get(server_id)
11646 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11647 {
11648 let params = lsp::DidChangeWatchedFilesParams {
11649 changes: changes
11650 .iter()
11651 .filter_map(|(path, _, change)| {
11652 if !watched_paths.is_match(path.as_std_path()) {
11653 return None;
11654 }
11655 let typ = match change {
11656 PathChange::Loaded => return None,
11657 PathChange::Added => lsp::FileChangeType::CREATED,
11658 PathChange::Removed => lsp::FileChangeType::DELETED,
11659 PathChange::Updated => lsp::FileChangeType::CHANGED,
11660 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11661 };
11662 let uri = lsp::Uri::from_file_path(
11663 worktree_handle.read(cx).absolutize(&path),
11664 )
11665 .ok()?;
11666 Some(lsp::FileEvent { uri, typ })
11667 })
11668 .collect(),
11669 };
11670 if !params.changes.is_empty() {
11671 server
11672 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11673 .ok();
11674 }
11675 }
11676 }
11677 for (path, _, _) in changes {
11678 if let Some(file_name) = path.file_name()
11679 && local.watched_manifest_filenames.contains(file_name)
11680 {
11681 self.request_workspace_config_refresh();
11682 break;
11683 }
11684 }
11685 }
11686
11687 pub fn wait_for_remote_buffer(
11688 &mut self,
11689 id: BufferId,
11690 cx: &mut Context<Self>,
11691 ) -> Task<Result<Entity<Buffer>>> {
11692 self.buffer_store.update(cx, |buffer_store, cx| {
11693 buffer_store.wait_for_remote_buffer(id, cx)
11694 })
11695 }
11696
11697 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11698 let mut result = proto::Symbol {
11699 language_server_name: symbol.language_server_name.0.to_string(),
11700 source_worktree_id: symbol.source_worktree_id.to_proto(),
11701 language_server_id: symbol.source_language_server_id.to_proto(),
11702 name: symbol.name.clone(),
11703 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11704 start: Some(proto::PointUtf16 {
11705 row: symbol.range.start.0.row,
11706 column: symbol.range.start.0.column,
11707 }),
11708 end: Some(proto::PointUtf16 {
11709 row: symbol.range.end.0.row,
11710 column: symbol.range.end.0.column,
11711 }),
11712 worktree_id: Default::default(),
11713 path: Default::default(),
11714 signature: Default::default(),
11715 };
11716 match &symbol.path {
11717 SymbolLocation::InProject(path) => {
11718 result.worktree_id = path.worktree_id.to_proto();
11719 result.path = path.path.to_proto();
11720 }
11721 SymbolLocation::OutsideProject {
11722 abs_path,
11723 signature,
11724 } => {
11725 result.path = abs_path.to_string_lossy().into_owned();
11726 result.signature = signature.to_vec();
11727 }
11728 }
11729 result
11730 }
11731
11732 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11733 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11734 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11735 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11736
11737 let path = if serialized_symbol.signature.is_empty() {
11738 SymbolLocation::InProject(ProjectPath {
11739 worktree_id,
11740 path: RelPath::from_proto(&serialized_symbol.path)
11741 .context("invalid symbol path")?,
11742 })
11743 } else {
11744 SymbolLocation::OutsideProject {
11745 abs_path: Path::new(&serialized_symbol.path).into(),
11746 signature: serialized_symbol
11747 .signature
11748 .try_into()
11749 .map_err(|_| anyhow!("invalid signature"))?,
11750 }
11751 };
11752
11753 let start = serialized_symbol.start.context("invalid start")?;
11754 let end = serialized_symbol.end.context("invalid end")?;
11755 Ok(CoreSymbol {
11756 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11757 source_worktree_id,
11758 source_language_server_id: LanguageServerId::from_proto(
11759 serialized_symbol.language_server_id,
11760 ),
11761 path,
11762 name: serialized_symbol.name,
11763 range: Unclipped(PointUtf16::new(start.row, start.column))
11764 ..Unclipped(PointUtf16::new(end.row, end.column)),
11765 kind,
11766 })
11767 }
11768
11769 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11770 let mut serialized_completion = proto::Completion {
11771 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11772 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11773 new_text: completion.new_text.clone(),
11774 ..proto::Completion::default()
11775 };
11776 match &completion.source {
11777 CompletionSource::Lsp {
11778 insert_range,
11779 server_id,
11780 lsp_completion,
11781 lsp_defaults,
11782 resolved,
11783 } => {
11784 let (old_insert_start, old_insert_end) = insert_range
11785 .as_ref()
11786 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11787 .unzip();
11788
11789 serialized_completion.old_insert_start = old_insert_start;
11790 serialized_completion.old_insert_end = old_insert_end;
11791 serialized_completion.source = proto::completion::Source::Lsp as i32;
11792 serialized_completion.server_id = server_id.0 as u64;
11793 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11794 serialized_completion.lsp_defaults = lsp_defaults
11795 .as_deref()
11796 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11797 serialized_completion.resolved = *resolved;
11798 }
11799 CompletionSource::BufferWord {
11800 word_range,
11801 resolved,
11802 } => {
11803 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11804 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11805 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11806 serialized_completion.resolved = *resolved;
11807 }
11808 CompletionSource::Custom => {
11809 serialized_completion.source = proto::completion::Source::Custom as i32;
11810 serialized_completion.resolved = true;
11811 }
11812 CompletionSource::Dap { sort_text } => {
11813 serialized_completion.source = proto::completion::Source::Dap as i32;
11814 serialized_completion.sort_text = Some(sort_text.clone());
11815 }
11816 }
11817
11818 serialized_completion
11819 }
11820
11821 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11822 let old_replace_start = completion
11823 .old_replace_start
11824 .and_then(deserialize_anchor)
11825 .context("invalid old start")?;
11826 let old_replace_end = completion
11827 .old_replace_end
11828 .and_then(deserialize_anchor)
11829 .context("invalid old end")?;
11830 let insert_range = {
11831 match completion.old_insert_start.zip(completion.old_insert_end) {
11832 Some((start, end)) => {
11833 let start = deserialize_anchor(start).context("invalid insert old start")?;
11834 let end = deserialize_anchor(end).context("invalid insert old end")?;
11835 Some(start..end)
11836 }
11837 None => None,
11838 }
11839 };
11840 Ok(CoreCompletion {
11841 replace_range: old_replace_start..old_replace_end,
11842 new_text: completion.new_text,
11843 source: match proto::completion::Source::from_i32(completion.source) {
11844 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11845 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11846 insert_range,
11847 server_id: LanguageServerId::from_proto(completion.server_id),
11848 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11849 lsp_defaults: completion
11850 .lsp_defaults
11851 .as_deref()
11852 .map(serde_json::from_slice)
11853 .transpose()?,
11854 resolved: completion.resolved,
11855 },
11856 Some(proto::completion::Source::BufferWord) => {
11857 let word_range = completion
11858 .buffer_word_start
11859 .and_then(deserialize_anchor)
11860 .context("invalid buffer word start")?
11861 ..completion
11862 .buffer_word_end
11863 .and_then(deserialize_anchor)
11864 .context("invalid buffer word end")?;
11865 CompletionSource::BufferWord {
11866 word_range,
11867 resolved: completion.resolved,
11868 }
11869 }
11870 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11871 sort_text: completion
11872 .sort_text
11873 .context("expected sort text to exist")?,
11874 },
11875 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11876 },
11877 })
11878 }
11879
11880 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11881 let (kind, lsp_action) = match &action.lsp_action {
11882 LspAction::Action(code_action) => (
11883 proto::code_action::Kind::Action as i32,
11884 serde_json::to_vec(code_action).unwrap(),
11885 ),
11886 LspAction::Command(command) => (
11887 proto::code_action::Kind::Command as i32,
11888 serde_json::to_vec(command).unwrap(),
11889 ),
11890 LspAction::CodeLens(code_lens) => (
11891 proto::code_action::Kind::CodeLens as i32,
11892 serde_json::to_vec(code_lens).unwrap(),
11893 ),
11894 };
11895
11896 proto::CodeAction {
11897 server_id: action.server_id.0 as u64,
11898 start: Some(serialize_anchor(&action.range.start)),
11899 end: Some(serialize_anchor(&action.range.end)),
11900 lsp_action,
11901 kind,
11902 resolved: action.resolved,
11903 }
11904 }
11905
11906 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11907 let start = action
11908 .start
11909 .and_then(deserialize_anchor)
11910 .context("invalid start")?;
11911 let end = action
11912 .end
11913 .and_then(deserialize_anchor)
11914 .context("invalid end")?;
11915 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11916 Some(proto::code_action::Kind::Action) => {
11917 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11918 }
11919 Some(proto::code_action::Kind::Command) => {
11920 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11921 }
11922 Some(proto::code_action::Kind::CodeLens) => {
11923 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11924 }
11925 None => anyhow::bail!("Unknown action kind {}", action.kind),
11926 };
11927 Ok(CodeAction {
11928 server_id: LanguageServerId(action.server_id as usize),
11929 range: start..end,
11930 resolved: action.resolved,
11931 lsp_action,
11932 })
11933 }
11934
11935 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11936 match &formatting_result {
11937 Ok(_) => self.last_formatting_failure = None,
11938 Err(error) => {
11939 let error_string = format!("{error:#}");
11940 log::error!("Formatting failed: {error_string}");
11941 self.last_formatting_failure
11942 .replace(error_string.lines().join(" "));
11943 }
11944 }
11945 }
11946
11947 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11948 self.lsp_server_capabilities.remove(&for_server);
11949 for lsp_data in self.lsp_data.values_mut() {
11950 lsp_data.remove_server_data(for_server);
11951 }
11952 if let Some(local) = self.as_local_mut() {
11953 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11954 local
11955 .workspace_pull_diagnostics_result_ids
11956 .remove(&for_server);
11957 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11958 buffer_servers.remove(&for_server);
11959 }
11960 }
11961 }
11962
11963 pub fn result_id_for_buffer_pull(
11964 &self,
11965 server_id: LanguageServerId,
11966 buffer_id: BufferId,
11967 registration_id: &Option<SharedString>,
11968 cx: &App,
11969 ) -> Option<SharedString> {
11970 let abs_path = self
11971 .buffer_store
11972 .read(cx)
11973 .get(buffer_id)
11974 .and_then(|b| File::from_dyn(b.read(cx).file()))
11975 .map(|f| f.abs_path(cx))?;
11976 self.as_local()?
11977 .buffer_pull_diagnostics_result_ids
11978 .get(&server_id)?
11979 .get(registration_id)?
11980 .get(&abs_path)?
11981 .clone()
11982 }
11983
11984 /// Gets all result_ids for a workspace diagnostics pull request.
11985 /// 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.
11986 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
11987 pub fn result_ids_for_workspace_refresh(
11988 &self,
11989 server_id: LanguageServerId,
11990 registration_id: &Option<SharedString>,
11991 ) -> HashMap<PathBuf, SharedString> {
11992 let Some(local) = self.as_local() else {
11993 return HashMap::default();
11994 };
11995 local
11996 .workspace_pull_diagnostics_result_ids
11997 .get(&server_id)
11998 .into_iter()
11999 .filter_map(|diagnostics| diagnostics.get(registration_id))
12000 .flatten()
12001 .filter_map(|(abs_path, result_id)| {
12002 let result_id = local
12003 .buffer_pull_diagnostics_result_ids
12004 .get(&server_id)
12005 .and_then(|buffer_ids_result_ids| {
12006 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12007 })
12008 .cloned()
12009 .flatten()
12010 .or_else(|| result_id.clone())?;
12011 Some((abs_path.clone(), result_id))
12012 })
12013 .collect()
12014 }
12015
12016 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12017 if let Some(LanguageServerState::Running {
12018 workspace_diagnostics_refresh_tasks,
12019 ..
12020 }) = self
12021 .as_local_mut()
12022 .and_then(|local| local.language_servers.get_mut(&server_id))
12023 {
12024 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12025 diagnostics.refresh_tx.try_send(()).ok();
12026 }
12027 }
12028 }
12029
12030 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12031 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12032 return;
12033 };
12034 let Some(local) = self.as_local_mut() else {
12035 return;
12036 };
12037
12038 for server_id in buffer.update(cx, |buffer, cx| {
12039 local.language_server_ids_for_buffer(buffer, cx)
12040 }) {
12041 if let Some(LanguageServerState::Running {
12042 workspace_diagnostics_refresh_tasks,
12043 ..
12044 }) = local.language_servers.get_mut(&server_id)
12045 {
12046 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12047 diagnostics.refresh_tx.try_send(()).ok();
12048 }
12049 }
12050 }
12051 }
12052
12053 fn apply_workspace_diagnostic_report(
12054 &mut self,
12055 server_id: LanguageServerId,
12056 report: lsp::WorkspaceDiagnosticReportResult,
12057 registration_id: Option<SharedString>,
12058 cx: &mut Context<Self>,
12059 ) {
12060 let workspace_diagnostics =
12061 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12062 report,
12063 server_id,
12064 registration_id,
12065 );
12066 let mut unchanged_buffers = HashMap::default();
12067 let workspace_diagnostics_updates = workspace_diagnostics
12068 .into_iter()
12069 .filter_map(
12070 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12071 LspPullDiagnostics::Response {
12072 server_id,
12073 uri,
12074 diagnostics,
12075 registration_id,
12076 } => Some((
12077 server_id,
12078 uri,
12079 diagnostics,
12080 workspace_diagnostics.version,
12081 registration_id,
12082 )),
12083 LspPullDiagnostics::Default => None,
12084 },
12085 )
12086 .fold(
12087 HashMap::default(),
12088 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12089 let (result_id, diagnostics) = match diagnostics {
12090 PulledDiagnostics::Unchanged { result_id } => {
12091 unchanged_buffers
12092 .entry(new_registration_id.clone())
12093 .or_insert_with(HashSet::default)
12094 .insert(uri.clone());
12095 (Some(result_id), Vec::new())
12096 }
12097 PulledDiagnostics::Changed {
12098 result_id,
12099 diagnostics,
12100 } => (result_id, diagnostics),
12101 };
12102 let disk_based_sources = Cow::Owned(
12103 self.language_server_adapter_for_id(server_id)
12104 .as_ref()
12105 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12106 .unwrap_or(&[])
12107 .to_vec(),
12108 );
12109
12110 let Some(abs_path) = uri.to_file_path().ok() else {
12111 return acc;
12112 };
12113 let Some((worktree, relative_path)) =
12114 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12115 else {
12116 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12117 return acc;
12118 };
12119 let worktree_id = worktree.read(cx).id();
12120 let project_path = ProjectPath {
12121 worktree_id,
12122 path: relative_path,
12123 };
12124 if let Some(local_lsp_store) = self.as_local_mut() {
12125 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12126 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12127 }
12128 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12129 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12130 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12131 acc.entry(server_id)
12132 .or_insert_with(HashMap::default)
12133 .entry(new_registration_id.clone())
12134 .or_insert_with(Vec::new)
12135 .push(DocumentDiagnosticsUpdate {
12136 server_id,
12137 diagnostics: lsp::PublishDiagnosticsParams {
12138 uri,
12139 diagnostics,
12140 version,
12141 },
12142 result_id,
12143 disk_based_sources,
12144 registration_id: new_registration_id,
12145 });
12146 }
12147 acc
12148 },
12149 );
12150
12151 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12152 for (registration_id, diagnostic_updates) in diagnostic_updates {
12153 self.merge_lsp_diagnostics(
12154 DiagnosticSourceKind::Pulled,
12155 diagnostic_updates,
12156 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12157 DiagnosticSourceKind::Pulled => {
12158 old_diagnostic.registration_id != registration_id
12159 || unchanged_buffers
12160 .get(&old_diagnostic.registration_id)
12161 .is_some_and(|unchanged_buffers| {
12162 unchanged_buffers.contains(&document_uri)
12163 })
12164 }
12165 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12166 },
12167 cx,
12168 )
12169 .log_err();
12170 }
12171 }
12172 }
12173
12174 fn register_server_capabilities(
12175 &mut self,
12176 server_id: LanguageServerId,
12177 params: lsp::RegistrationParams,
12178 cx: &mut Context<Self>,
12179 ) -> anyhow::Result<()> {
12180 let server = self
12181 .language_server_for_id(server_id)
12182 .with_context(|| format!("no server {server_id} found"))?;
12183 for reg in params.registrations {
12184 match reg.method.as_str() {
12185 "workspace/didChangeWatchedFiles" => {
12186 if let Some(options) = reg.register_options {
12187 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12188 let caps = serde_json::from_value(options)?;
12189 local_lsp_store
12190 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12191 true
12192 } else {
12193 false
12194 };
12195 if notify {
12196 notify_server_capabilities_updated(&server, cx);
12197 }
12198 }
12199 }
12200 "workspace/didChangeConfiguration" => {
12201 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12202 }
12203 "workspace/didChangeWorkspaceFolders" => {
12204 // In this case register options is an empty object, we can ignore it
12205 let caps = lsp::WorkspaceFoldersServerCapabilities {
12206 supported: Some(true),
12207 change_notifications: Some(OneOf::Right(reg.id)),
12208 };
12209 server.update_capabilities(|capabilities| {
12210 capabilities
12211 .workspace
12212 .get_or_insert_default()
12213 .workspace_folders = Some(caps);
12214 });
12215 notify_server_capabilities_updated(&server, cx);
12216 }
12217 "workspace/symbol" => {
12218 let options = parse_register_capabilities(reg)?;
12219 server.update_capabilities(|capabilities| {
12220 capabilities.workspace_symbol_provider = Some(options);
12221 });
12222 notify_server_capabilities_updated(&server, cx);
12223 }
12224 "workspace/fileOperations" => {
12225 if let Some(options) = reg.register_options {
12226 let caps = serde_json::from_value(options)?;
12227 server.update_capabilities(|capabilities| {
12228 capabilities
12229 .workspace
12230 .get_or_insert_default()
12231 .file_operations = Some(caps);
12232 });
12233 notify_server_capabilities_updated(&server, cx);
12234 }
12235 }
12236 "workspace/executeCommand" => {
12237 if let Some(options) = reg.register_options {
12238 let options = serde_json::from_value(options)?;
12239 server.update_capabilities(|capabilities| {
12240 capabilities.execute_command_provider = Some(options);
12241 });
12242 notify_server_capabilities_updated(&server, cx);
12243 }
12244 }
12245 "textDocument/rangeFormatting" => {
12246 let options = parse_register_capabilities(reg)?;
12247 server.update_capabilities(|capabilities| {
12248 capabilities.document_range_formatting_provider = Some(options);
12249 });
12250 notify_server_capabilities_updated(&server, cx);
12251 }
12252 "textDocument/onTypeFormatting" => {
12253 if let Some(options) = reg
12254 .register_options
12255 .map(serde_json::from_value)
12256 .transpose()?
12257 {
12258 server.update_capabilities(|capabilities| {
12259 capabilities.document_on_type_formatting_provider = Some(options);
12260 });
12261 notify_server_capabilities_updated(&server, cx);
12262 }
12263 }
12264 "textDocument/formatting" => {
12265 let options = parse_register_capabilities(reg)?;
12266 server.update_capabilities(|capabilities| {
12267 capabilities.document_formatting_provider = Some(options);
12268 });
12269 notify_server_capabilities_updated(&server, cx);
12270 }
12271 "textDocument/rename" => {
12272 let options = parse_register_capabilities(reg)?;
12273 server.update_capabilities(|capabilities| {
12274 capabilities.rename_provider = Some(options);
12275 });
12276 notify_server_capabilities_updated(&server, cx);
12277 }
12278 "textDocument/inlayHint" => {
12279 let options = parse_register_capabilities(reg)?;
12280 server.update_capabilities(|capabilities| {
12281 capabilities.inlay_hint_provider = Some(options);
12282 });
12283 notify_server_capabilities_updated(&server, cx);
12284 }
12285 "textDocument/documentSymbol" => {
12286 let options = parse_register_capabilities(reg)?;
12287 server.update_capabilities(|capabilities| {
12288 capabilities.document_symbol_provider = Some(options);
12289 });
12290 notify_server_capabilities_updated(&server, cx);
12291 }
12292 "textDocument/codeAction" => {
12293 let options = parse_register_capabilities(reg)?;
12294 let provider = match options {
12295 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12296 OneOf::Right(caps) => caps,
12297 };
12298 server.update_capabilities(|capabilities| {
12299 capabilities.code_action_provider = Some(provider);
12300 });
12301 notify_server_capabilities_updated(&server, cx);
12302 }
12303 "textDocument/definition" => {
12304 let options = parse_register_capabilities(reg)?;
12305 server.update_capabilities(|capabilities| {
12306 capabilities.definition_provider = Some(options);
12307 });
12308 notify_server_capabilities_updated(&server, cx);
12309 }
12310 "textDocument/completion" => {
12311 if let Some(caps) = reg
12312 .register_options
12313 .map(serde_json::from_value::<CompletionOptions>)
12314 .transpose()?
12315 {
12316 server.update_capabilities(|capabilities| {
12317 capabilities.completion_provider = Some(caps.clone());
12318 });
12319
12320 if let Some(local) = self.as_local() {
12321 let mut buffers_with_language_server = Vec::new();
12322 for handle in self.buffer_store.read(cx).buffers() {
12323 let buffer_id = handle.read(cx).remote_id();
12324 if local
12325 .buffers_opened_in_servers
12326 .get(&buffer_id)
12327 .filter(|s| s.contains(&server_id))
12328 .is_some()
12329 {
12330 buffers_with_language_server.push(handle);
12331 }
12332 }
12333 let triggers = caps
12334 .trigger_characters
12335 .unwrap_or_default()
12336 .into_iter()
12337 .collect::<BTreeSet<_>>();
12338 for handle in buffers_with_language_server {
12339 let triggers = triggers.clone();
12340 let _ = handle.update(cx, move |buffer, cx| {
12341 buffer.set_completion_triggers(server_id, triggers, cx);
12342 });
12343 }
12344 }
12345 notify_server_capabilities_updated(&server, cx);
12346 }
12347 }
12348 "textDocument/hover" => {
12349 let options = parse_register_capabilities(reg)?;
12350 let provider = match options {
12351 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12352 OneOf::Right(caps) => caps,
12353 };
12354 server.update_capabilities(|capabilities| {
12355 capabilities.hover_provider = Some(provider);
12356 });
12357 notify_server_capabilities_updated(&server, cx);
12358 }
12359 "textDocument/signatureHelp" => {
12360 if let Some(caps) = reg
12361 .register_options
12362 .map(serde_json::from_value)
12363 .transpose()?
12364 {
12365 server.update_capabilities(|capabilities| {
12366 capabilities.signature_help_provider = Some(caps);
12367 });
12368 notify_server_capabilities_updated(&server, cx);
12369 }
12370 }
12371 "textDocument/didChange" => {
12372 if let Some(sync_kind) = reg
12373 .register_options
12374 .and_then(|opts| opts.get("syncKind").cloned())
12375 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12376 .transpose()?
12377 {
12378 server.update_capabilities(|capabilities| {
12379 let mut sync_options =
12380 Self::take_text_document_sync_options(capabilities);
12381 sync_options.change = Some(sync_kind);
12382 capabilities.text_document_sync =
12383 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12384 });
12385 notify_server_capabilities_updated(&server, cx);
12386 }
12387 }
12388 "textDocument/didSave" => {
12389 if let Some(include_text) = reg
12390 .register_options
12391 .map(|opts| {
12392 let transpose = opts
12393 .get("includeText")
12394 .cloned()
12395 .map(serde_json::from_value::<Option<bool>>)
12396 .transpose();
12397 match transpose {
12398 Ok(value) => Ok(value.flatten()),
12399 Err(e) => Err(e),
12400 }
12401 })
12402 .transpose()?
12403 {
12404 server.update_capabilities(|capabilities| {
12405 let mut sync_options =
12406 Self::take_text_document_sync_options(capabilities);
12407 sync_options.save =
12408 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12409 include_text,
12410 }));
12411 capabilities.text_document_sync =
12412 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12413 });
12414 notify_server_capabilities_updated(&server, cx);
12415 }
12416 }
12417 "textDocument/codeLens" => {
12418 if let Some(caps) = reg
12419 .register_options
12420 .map(serde_json::from_value)
12421 .transpose()?
12422 {
12423 server.update_capabilities(|capabilities| {
12424 capabilities.code_lens_provider = Some(caps);
12425 });
12426 notify_server_capabilities_updated(&server, cx);
12427 }
12428 }
12429 "textDocument/diagnostic" => {
12430 if let Some(caps) = reg
12431 .register_options
12432 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12433 .transpose()?
12434 {
12435 let local = self
12436 .as_local_mut()
12437 .context("Expected LSP Store to be local")?;
12438 let state = local
12439 .language_servers
12440 .get_mut(&server_id)
12441 .context("Could not obtain Language Servers state")?;
12442 local
12443 .language_server_dynamic_registrations
12444 .entry(server_id)
12445 .or_default()
12446 .diagnostics
12447 .insert(Some(reg.id.clone()), caps.clone());
12448
12449 let supports_workspace_diagnostics =
12450 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12451 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12452 diagnostic_options.workspace_diagnostics
12453 }
12454 DiagnosticServerCapabilities::RegistrationOptions(
12455 diagnostic_registration_options,
12456 ) => {
12457 diagnostic_registration_options
12458 .diagnostic_options
12459 .workspace_diagnostics
12460 }
12461 };
12462
12463 if supports_workspace_diagnostics(&caps) {
12464 if let LanguageServerState::Running {
12465 workspace_diagnostics_refresh_tasks,
12466 ..
12467 } = state
12468 && let Some(task) = lsp_workspace_diagnostics_refresh(
12469 Some(reg.id.clone()),
12470 caps.clone(),
12471 server.clone(),
12472 cx,
12473 )
12474 {
12475 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12476 }
12477 }
12478
12479 server.update_capabilities(|capabilities| {
12480 capabilities.diagnostic_provider = Some(caps);
12481 });
12482
12483 notify_server_capabilities_updated(&server, cx);
12484 }
12485 }
12486 "textDocument/documentColor" => {
12487 let options = parse_register_capabilities(reg)?;
12488 let provider = match options {
12489 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12490 OneOf::Right(caps) => caps,
12491 };
12492 server.update_capabilities(|capabilities| {
12493 capabilities.color_provider = Some(provider);
12494 });
12495 notify_server_capabilities_updated(&server, cx);
12496 }
12497 _ => log::warn!("unhandled capability registration: {reg:?}"),
12498 }
12499 }
12500
12501 Ok(())
12502 }
12503
12504 fn unregister_server_capabilities(
12505 &mut self,
12506 server_id: LanguageServerId,
12507 params: lsp::UnregistrationParams,
12508 cx: &mut Context<Self>,
12509 ) -> anyhow::Result<()> {
12510 let server = self
12511 .language_server_for_id(server_id)
12512 .with_context(|| format!("no server {server_id} found"))?;
12513 for unreg in params.unregisterations.iter() {
12514 match unreg.method.as_str() {
12515 "workspace/didChangeWatchedFiles" => {
12516 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12517 local_lsp_store
12518 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12519 true
12520 } else {
12521 false
12522 };
12523 if notify {
12524 notify_server_capabilities_updated(&server, cx);
12525 }
12526 }
12527 "workspace/didChangeConfiguration" => {
12528 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12529 }
12530 "workspace/didChangeWorkspaceFolders" => {
12531 server.update_capabilities(|capabilities| {
12532 capabilities
12533 .workspace
12534 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12535 workspace_folders: None,
12536 file_operations: None,
12537 })
12538 .workspace_folders = None;
12539 });
12540 notify_server_capabilities_updated(&server, cx);
12541 }
12542 "workspace/symbol" => {
12543 server.update_capabilities(|capabilities| {
12544 capabilities.workspace_symbol_provider = None
12545 });
12546 notify_server_capabilities_updated(&server, cx);
12547 }
12548 "workspace/fileOperations" => {
12549 server.update_capabilities(|capabilities| {
12550 capabilities
12551 .workspace
12552 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12553 workspace_folders: None,
12554 file_operations: None,
12555 })
12556 .file_operations = None;
12557 });
12558 notify_server_capabilities_updated(&server, cx);
12559 }
12560 "workspace/executeCommand" => {
12561 server.update_capabilities(|capabilities| {
12562 capabilities.execute_command_provider = None;
12563 });
12564 notify_server_capabilities_updated(&server, cx);
12565 }
12566 "textDocument/rangeFormatting" => {
12567 server.update_capabilities(|capabilities| {
12568 capabilities.document_range_formatting_provider = None
12569 });
12570 notify_server_capabilities_updated(&server, cx);
12571 }
12572 "textDocument/onTypeFormatting" => {
12573 server.update_capabilities(|capabilities| {
12574 capabilities.document_on_type_formatting_provider = None;
12575 });
12576 notify_server_capabilities_updated(&server, cx);
12577 }
12578 "textDocument/formatting" => {
12579 server.update_capabilities(|capabilities| {
12580 capabilities.document_formatting_provider = None;
12581 });
12582 notify_server_capabilities_updated(&server, cx);
12583 }
12584 "textDocument/rename" => {
12585 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12586 notify_server_capabilities_updated(&server, cx);
12587 }
12588 "textDocument/codeAction" => {
12589 server.update_capabilities(|capabilities| {
12590 capabilities.code_action_provider = None;
12591 });
12592 notify_server_capabilities_updated(&server, cx);
12593 }
12594 "textDocument/definition" => {
12595 server.update_capabilities(|capabilities| {
12596 capabilities.definition_provider = None;
12597 });
12598 notify_server_capabilities_updated(&server, cx);
12599 }
12600 "textDocument/completion" => {
12601 server.update_capabilities(|capabilities| {
12602 capabilities.completion_provider = None;
12603 });
12604 notify_server_capabilities_updated(&server, cx);
12605 }
12606 "textDocument/hover" => {
12607 server.update_capabilities(|capabilities| {
12608 capabilities.hover_provider = None;
12609 });
12610 notify_server_capabilities_updated(&server, cx);
12611 }
12612 "textDocument/signatureHelp" => {
12613 server.update_capabilities(|capabilities| {
12614 capabilities.signature_help_provider = None;
12615 });
12616 notify_server_capabilities_updated(&server, cx);
12617 }
12618 "textDocument/didChange" => {
12619 server.update_capabilities(|capabilities| {
12620 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12621 sync_options.change = None;
12622 capabilities.text_document_sync =
12623 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12624 });
12625 notify_server_capabilities_updated(&server, cx);
12626 }
12627 "textDocument/didSave" => {
12628 server.update_capabilities(|capabilities| {
12629 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12630 sync_options.save = None;
12631 capabilities.text_document_sync =
12632 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12633 });
12634 notify_server_capabilities_updated(&server, cx);
12635 }
12636 "textDocument/codeLens" => {
12637 server.update_capabilities(|capabilities| {
12638 capabilities.code_lens_provider = None;
12639 });
12640 notify_server_capabilities_updated(&server, cx);
12641 }
12642 "textDocument/diagnostic" => {
12643 let local = self
12644 .as_local_mut()
12645 .context("Expected LSP Store to be local")?;
12646
12647 let state = local
12648 .language_servers
12649 .get_mut(&server_id)
12650 .context("Could not obtain Language Servers state")?;
12651 let registrations = local
12652 .language_server_dynamic_registrations
12653 .get_mut(&server_id)
12654 .with_context(|| {
12655 format!("Expected dynamic registration to exist for server {server_id}")
12656 })?;
12657 registrations.diagnostics
12658 .remove(&Some(unreg.id.clone()))
12659 .with_context(|| format!(
12660 "Attempted to unregister non-existent diagnostic registration with ID {}",
12661 unreg.id)
12662 )?;
12663 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12664
12665 if let LanguageServerState::Running {
12666 workspace_diagnostics_refresh_tasks,
12667 ..
12668 } = state
12669 {
12670 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12671 }
12672
12673 if removed_last_diagnostic_provider {
12674 server.update_capabilities(|capabilities| {
12675 debug_assert!(capabilities.diagnostic_provider.is_some());
12676 capabilities.diagnostic_provider = None;
12677 });
12678 }
12679
12680 notify_server_capabilities_updated(&server, cx);
12681 }
12682 "textDocument/documentColor" => {
12683 server.update_capabilities(|capabilities| {
12684 capabilities.color_provider = None;
12685 });
12686 notify_server_capabilities_updated(&server, cx);
12687 }
12688 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12689 }
12690 }
12691
12692 Ok(())
12693 }
12694
12695 async fn deduplicate_range_based_lsp_requests<T>(
12696 lsp_store: &Entity<Self>,
12697 server_id: Option<LanguageServerId>,
12698 lsp_request_id: LspRequestId,
12699 proto_request: &T::ProtoRequest,
12700 range: Range<Anchor>,
12701 cx: &mut AsyncApp,
12702 ) -> Result<()>
12703 where
12704 T: LspCommand,
12705 T::ProtoRequest: proto::LspRequestMessage,
12706 {
12707 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12708 let version = deserialize_version(proto_request.buffer_version());
12709 let buffer = lsp_store.update(cx, |this, cx| {
12710 this.buffer_store.read(cx).get_existing(buffer_id)
12711 })??;
12712 buffer
12713 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12714 .await?;
12715 lsp_store.update(cx, |lsp_store, cx| {
12716 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12717 let chunks_queried_for = lsp_data
12718 .inlay_hints
12719 .applicable_chunks(&[range])
12720 .collect::<Vec<_>>();
12721 match chunks_queried_for.as_slice() {
12722 &[chunk] => {
12723 let key = LspKey {
12724 request_type: TypeId::of::<T>(),
12725 server_queried: server_id,
12726 };
12727 let previous_request = lsp_data
12728 .chunk_lsp_requests
12729 .entry(key)
12730 .or_default()
12731 .insert(chunk, lsp_request_id);
12732 if let Some((previous_request, running_requests)) =
12733 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12734 {
12735 running_requests.remove(&previous_request);
12736 }
12737 }
12738 _ambiguous_chunks => {
12739 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12740 // there, a buffer version-based check will be performed and outdated requests discarded.
12741 }
12742 }
12743 anyhow::Ok(())
12744 })??;
12745
12746 Ok(())
12747 }
12748
12749 async fn query_lsp_locally<T>(
12750 lsp_store: Entity<Self>,
12751 for_server_id: Option<LanguageServerId>,
12752 sender_id: proto::PeerId,
12753 lsp_request_id: LspRequestId,
12754 proto_request: T::ProtoRequest,
12755 position: Option<Anchor>,
12756 cx: &mut AsyncApp,
12757 ) -> Result<()>
12758 where
12759 T: LspCommand + Clone,
12760 T::ProtoRequest: proto::LspRequestMessage,
12761 <T::ProtoRequest as proto::RequestMessage>::Response:
12762 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12763 {
12764 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12765 let version = deserialize_version(proto_request.buffer_version());
12766 let buffer = lsp_store.update(cx, |this, cx| {
12767 this.buffer_store.read(cx).get_existing(buffer_id)
12768 })??;
12769 buffer
12770 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12771 .await?;
12772 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12773 let request =
12774 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12775 let key = LspKey {
12776 request_type: TypeId::of::<T>(),
12777 server_queried: for_server_id,
12778 };
12779 lsp_store.update(cx, |lsp_store, cx| {
12780 let request_task = match for_server_id {
12781 Some(server_id) => {
12782 let server_task = lsp_store.request_lsp(
12783 buffer.clone(),
12784 LanguageServerToQuery::Other(server_id),
12785 request.clone(),
12786 cx,
12787 );
12788 cx.background_spawn(async move {
12789 let mut responses = Vec::new();
12790 match server_task.await {
12791 Ok(response) => responses.push((server_id, response)),
12792 // rust-analyzer likes to error with this when its still loading up
12793 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12794 Err(e) => log::error!(
12795 "Error handling response for request {request:?}: {e:#}"
12796 ),
12797 }
12798 responses
12799 })
12800 }
12801 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12802 };
12803 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12804 if T::ProtoRequest::stop_previous_requests() {
12805 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12806 lsp_requests.clear();
12807 }
12808 }
12809 lsp_data.lsp_requests.entry(key).or_default().insert(
12810 lsp_request_id,
12811 cx.spawn(async move |lsp_store, cx| {
12812 let response = request_task.await;
12813 lsp_store
12814 .update(cx, |lsp_store, cx| {
12815 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12816 {
12817 let response = response
12818 .into_iter()
12819 .map(|(server_id, response)| {
12820 (
12821 server_id.to_proto(),
12822 T::response_to_proto(
12823 response,
12824 lsp_store,
12825 sender_id,
12826 &buffer_version,
12827 cx,
12828 )
12829 .into(),
12830 )
12831 })
12832 .collect::<HashMap<_, _>>();
12833 match client.send_lsp_response::<T::ProtoRequest>(
12834 project_id,
12835 lsp_request_id,
12836 response,
12837 ) {
12838 Ok(()) => {}
12839 Err(e) => {
12840 log::error!("Failed to send LSP response: {e:#}",)
12841 }
12842 }
12843 }
12844 })
12845 .ok();
12846 }),
12847 );
12848 })?;
12849 Ok(())
12850 }
12851
12852 fn take_text_document_sync_options(
12853 capabilities: &mut lsp::ServerCapabilities,
12854 ) -> lsp::TextDocumentSyncOptions {
12855 match capabilities.text_document_sync.take() {
12856 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12857 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12858 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12859 sync_options.change = Some(sync_kind);
12860 sync_options
12861 }
12862 None => lsp::TextDocumentSyncOptions::default(),
12863 }
12864 }
12865
12866 #[cfg(any(test, feature = "test-support"))]
12867 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12868 Some(
12869 self.lsp_data
12870 .get_mut(&buffer_id)?
12871 .code_lens
12872 .take()?
12873 .update
12874 .take()?
12875 .1,
12876 )
12877 }
12878
12879 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12880 self.downstream_client.clone()
12881 }
12882
12883 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12884 self.worktree_store.clone()
12885 }
12886
12887 /// Gets what's stored in the LSP data for the given buffer.
12888 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12889 self.lsp_data.get_mut(&buffer_id)
12890 }
12891
12892 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12893 /// new [`BufferLspData`] will be created to replace the previous state.
12894 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12895 let (buffer_id, buffer_version) =
12896 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12897 let lsp_data = self
12898 .lsp_data
12899 .entry(buffer_id)
12900 .or_insert_with(|| BufferLspData::new(buffer, cx));
12901 if buffer_version.changed_since(&lsp_data.buffer_version) {
12902 *lsp_data = BufferLspData::new(buffer, cx);
12903 }
12904 lsp_data
12905 }
12906}
12907
12908// Registration with registerOptions as null, should fallback to true.
12909// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12910fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12911 reg: lsp::Registration,
12912) -> Result<OneOf<bool, T>> {
12913 Ok(match reg.register_options {
12914 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12915 None => OneOf::Left(true),
12916 })
12917}
12918
12919fn subscribe_to_binary_statuses(
12920 languages: &Arc<LanguageRegistry>,
12921 cx: &mut Context<'_, LspStore>,
12922) -> Task<()> {
12923 let mut server_statuses = languages.language_server_binary_statuses();
12924 cx.spawn(async move |lsp_store, cx| {
12925 while let Some((server_name, binary_status)) = server_statuses.next().await {
12926 if lsp_store
12927 .update(cx, |_, cx| {
12928 let mut message = None;
12929 let binary_status = match binary_status {
12930 BinaryStatus::None => proto::ServerBinaryStatus::None,
12931 BinaryStatus::CheckingForUpdate => {
12932 proto::ServerBinaryStatus::CheckingForUpdate
12933 }
12934 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12935 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12936 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12937 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12938 BinaryStatus::Failed { error } => {
12939 message = Some(error);
12940 proto::ServerBinaryStatus::Failed
12941 }
12942 };
12943 cx.emit(LspStoreEvent::LanguageServerUpdate {
12944 // Binary updates are about the binary that might not have any language server id at that point.
12945 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12946 language_server_id: LanguageServerId(0),
12947 name: Some(server_name),
12948 message: proto::update_language_server::Variant::StatusUpdate(
12949 proto::StatusUpdate {
12950 message,
12951 status: Some(proto::status_update::Status::Binary(
12952 binary_status as i32,
12953 )),
12954 },
12955 ),
12956 });
12957 })
12958 .is_err()
12959 {
12960 break;
12961 }
12962 }
12963 })
12964}
12965
12966fn lsp_workspace_diagnostics_refresh(
12967 registration_id: Option<String>,
12968 options: DiagnosticServerCapabilities,
12969 server: Arc<LanguageServer>,
12970 cx: &mut Context<'_, LspStore>,
12971) -> Option<WorkspaceRefreshTask> {
12972 let identifier = workspace_diagnostic_identifier(&options)?;
12973 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
12974
12975 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12976 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12977 refresh_tx.try_send(()).ok();
12978
12979 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12980 let mut attempts = 0;
12981 let max_attempts = 50;
12982 let mut requests = 0;
12983
12984 loop {
12985 let Some(()) = refresh_rx.recv().await else {
12986 return;
12987 };
12988
12989 'request: loop {
12990 requests += 1;
12991 if attempts > max_attempts {
12992 log::error!(
12993 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12994 );
12995 return;
12996 }
12997 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12998 cx.background_executor()
12999 .timer(Duration::from_millis(backoff_millis))
13000 .await;
13001 attempts += 1;
13002
13003 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13004 lsp_store
13005 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13006 .into_iter()
13007 .filter_map(|(abs_path, result_id)| {
13008 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13009 Some(lsp::PreviousResultId {
13010 uri,
13011 value: result_id.to_string(),
13012 })
13013 })
13014 .collect()
13015 }) else {
13016 return;
13017 };
13018
13019 let token = if let Some(registration_id) = ®istration_id {
13020 format!(
13021 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13022 server.server_id(),
13023 )
13024 } else {
13025 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13026 };
13027
13028 progress_rx.try_recv().ok();
13029 let timer =
13030 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13031 let progress = pin!(progress_rx.recv().fuse());
13032 let response_result = server
13033 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13034 lsp::WorkspaceDiagnosticParams {
13035 previous_result_ids,
13036 identifier: identifier.clone(),
13037 work_done_progress_params: Default::default(),
13038 partial_result_params: lsp::PartialResultParams {
13039 partial_result_token: Some(lsp::ProgressToken::String(token)),
13040 },
13041 },
13042 select(timer, progress).then(|either| match either {
13043 Either::Left((message, ..)) => ready(message).left_future(),
13044 Either::Right(..) => pending::<String>().right_future(),
13045 }),
13046 )
13047 .await;
13048
13049 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13050 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13051 match response_result {
13052 ConnectionResult::Timeout => {
13053 log::error!("Timeout during workspace diagnostics pull");
13054 continue 'request;
13055 }
13056 ConnectionResult::ConnectionReset => {
13057 log::error!("Server closed a workspace diagnostics pull request");
13058 continue 'request;
13059 }
13060 ConnectionResult::Result(Err(e)) => {
13061 log::error!("Error during workspace diagnostics pull: {e:#}");
13062 break 'request;
13063 }
13064 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13065 attempts = 0;
13066 if lsp_store
13067 .update(cx, |lsp_store, cx| {
13068 lsp_store.apply_workspace_diagnostic_report(
13069 server.server_id(),
13070 pulled_diagnostics,
13071 registration_id_shared.clone(),
13072 cx,
13073 )
13074 })
13075 .is_err()
13076 {
13077 return;
13078 }
13079 break 'request;
13080 }
13081 }
13082 }
13083 }
13084 });
13085
13086 Some(WorkspaceRefreshTask {
13087 refresh_tx,
13088 progress_tx,
13089 task: workspace_query_language_server,
13090 })
13091}
13092
13093fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13094 match &options {
13095 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13096 diagnostic_options.identifier.clone()
13097 }
13098 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13099 let diagnostic_options = ®istration_options.diagnostic_options;
13100 diagnostic_options.identifier.clone()
13101 }
13102 }
13103}
13104
13105fn workspace_diagnostic_identifier(
13106 options: &DiagnosticServerCapabilities,
13107) -> Option<Option<String>> {
13108 match &options {
13109 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13110 if !diagnostic_options.workspace_diagnostics {
13111 return None;
13112 }
13113 Some(diagnostic_options.identifier.clone())
13114 }
13115 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13116 let diagnostic_options = ®istration_options.diagnostic_options;
13117 if !diagnostic_options.workspace_diagnostics {
13118 return None;
13119 }
13120 Some(diagnostic_options.identifier.clone())
13121 }
13122 }
13123}
13124
13125fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13126 let CompletionSource::BufferWord {
13127 word_range,
13128 resolved,
13129 } = &mut completion.source
13130 else {
13131 return;
13132 };
13133 if *resolved {
13134 return;
13135 }
13136
13137 if completion.new_text
13138 != snapshot
13139 .text_for_range(word_range.clone())
13140 .collect::<String>()
13141 {
13142 return;
13143 }
13144
13145 let mut offset = 0;
13146 for chunk in snapshot.chunks(word_range.clone(), true) {
13147 let end_offset = offset + chunk.text.len();
13148 if let Some(highlight_id) = chunk.syntax_highlight_id {
13149 completion
13150 .label
13151 .runs
13152 .push((offset..end_offset, highlight_id));
13153 }
13154 offset = end_offset;
13155 }
13156 *resolved = true;
13157}
13158
13159impl EventEmitter<LspStoreEvent> for LspStore {}
13160
13161fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13162 hover
13163 .contents
13164 .retain(|hover_block| !hover_block.text.trim().is_empty());
13165 if hover.contents.is_empty() {
13166 None
13167 } else {
13168 Some(hover)
13169 }
13170}
13171
13172async fn populate_labels_for_completions(
13173 new_completions: Vec<CoreCompletion>,
13174 language: Option<Arc<Language>>,
13175 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13176) -> Vec<Completion> {
13177 let lsp_completions = new_completions
13178 .iter()
13179 .filter_map(|new_completion| {
13180 new_completion
13181 .source
13182 .lsp_completion(true)
13183 .map(|lsp_completion| lsp_completion.into_owned())
13184 })
13185 .collect::<Vec<_>>();
13186
13187 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13188 lsp_adapter
13189 .labels_for_completions(&lsp_completions, language)
13190 .await
13191 .log_err()
13192 .unwrap_or_default()
13193 } else {
13194 Vec::new()
13195 }
13196 .into_iter()
13197 .fuse();
13198
13199 let mut completions = Vec::new();
13200 for completion in new_completions {
13201 match completion.source.lsp_completion(true) {
13202 Some(lsp_completion) => {
13203 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13204
13205 let mut label = labels.next().flatten().unwrap_or_else(|| {
13206 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13207 });
13208 ensure_uniform_list_compatible_label(&mut label);
13209 completions.push(Completion {
13210 label,
13211 documentation,
13212 replace_range: completion.replace_range,
13213 new_text: completion.new_text,
13214 insert_text_mode: lsp_completion.insert_text_mode,
13215 source: completion.source,
13216 icon_path: None,
13217 confirm: None,
13218 match_start: None,
13219 snippet_deduplication_key: None,
13220 });
13221 }
13222 None => {
13223 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13224 ensure_uniform_list_compatible_label(&mut label);
13225 completions.push(Completion {
13226 label,
13227 documentation: None,
13228 replace_range: completion.replace_range,
13229 new_text: completion.new_text,
13230 source: completion.source,
13231 insert_text_mode: None,
13232 icon_path: None,
13233 confirm: None,
13234 match_start: None,
13235 snippet_deduplication_key: None,
13236 });
13237 }
13238 }
13239 }
13240 completions
13241}
13242
13243#[derive(Debug)]
13244pub enum LanguageServerToQuery {
13245 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13246 FirstCapable,
13247 /// Query a specific language server.
13248 Other(LanguageServerId),
13249}
13250
13251#[derive(Default)]
13252struct RenamePathsWatchedForServer {
13253 did_rename: Vec<RenameActionPredicate>,
13254 will_rename: Vec<RenameActionPredicate>,
13255}
13256
13257impl RenamePathsWatchedForServer {
13258 fn with_did_rename_patterns(
13259 mut self,
13260 did_rename: Option<&FileOperationRegistrationOptions>,
13261 ) -> Self {
13262 if let Some(did_rename) = did_rename {
13263 self.did_rename = did_rename
13264 .filters
13265 .iter()
13266 .filter_map(|filter| filter.try_into().log_err())
13267 .collect();
13268 }
13269 self
13270 }
13271 fn with_will_rename_patterns(
13272 mut self,
13273 will_rename: Option<&FileOperationRegistrationOptions>,
13274 ) -> Self {
13275 if let Some(will_rename) = will_rename {
13276 self.will_rename = will_rename
13277 .filters
13278 .iter()
13279 .filter_map(|filter| filter.try_into().log_err())
13280 .collect();
13281 }
13282 self
13283 }
13284
13285 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13286 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13287 }
13288 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13289 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13290 }
13291}
13292
13293impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13294 type Error = globset::Error;
13295 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13296 Ok(Self {
13297 kind: ops.pattern.matches.clone(),
13298 glob: GlobBuilder::new(&ops.pattern.glob)
13299 .case_insensitive(
13300 ops.pattern
13301 .options
13302 .as_ref()
13303 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13304 )
13305 .build()?
13306 .compile_matcher(),
13307 })
13308 }
13309}
13310struct RenameActionPredicate {
13311 glob: GlobMatcher,
13312 kind: Option<FileOperationPatternKind>,
13313}
13314
13315impl RenameActionPredicate {
13316 // Returns true if language server should be notified
13317 fn eval(&self, path: &str, is_dir: bool) -> bool {
13318 self.kind.as_ref().is_none_or(|kind| {
13319 let expected_kind = if is_dir {
13320 FileOperationPatternKind::Folder
13321 } else {
13322 FileOperationPatternKind::File
13323 };
13324 kind == &expected_kind
13325 }) && self.glob.is_match(path)
13326 }
13327}
13328
13329#[derive(Default)]
13330struct LanguageServerWatchedPaths {
13331 worktree_paths: HashMap<WorktreeId, GlobSet>,
13332 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13333}
13334
13335#[derive(Default)]
13336struct LanguageServerWatchedPathsBuilder {
13337 worktree_paths: HashMap<WorktreeId, GlobSet>,
13338 abs_paths: HashMap<Arc<Path>, GlobSet>,
13339}
13340
13341impl LanguageServerWatchedPathsBuilder {
13342 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13343 self.worktree_paths.insert(worktree_id, glob_set);
13344 }
13345 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13346 self.abs_paths.insert(path, glob_set);
13347 }
13348 fn build(
13349 self,
13350 fs: Arc<dyn Fs>,
13351 language_server_id: LanguageServerId,
13352 cx: &mut Context<LspStore>,
13353 ) -> LanguageServerWatchedPaths {
13354 let lsp_store = cx.weak_entity();
13355
13356 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13357 let abs_paths = self
13358 .abs_paths
13359 .into_iter()
13360 .map(|(abs_path, globset)| {
13361 let task = cx.spawn({
13362 let abs_path = abs_path.clone();
13363 let fs = fs.clone();
13364
13365 let lsp_store = lsp_store.clone();
13366 async move |_, cx| {
13367 maybe!(async move {
13368 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13369 while let Some(update) = push_updates.0.next().await {
13370 let action = lsp_store
13371 .update(cx, |this, _| {
13372 let Some(local) = this.as_local() else {
13373 return ControlFlow::Break(());
13374 };
13375 let Some(watcher) = local
13376 .language_server_watched_paths
13377 .get(&language_server_id)
13378 else {
13379 return ControlFlow::Break(());
13380 };
13381 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13382 "Watched abs path is not registered with a watcher",
13383 );
13384 let matching_entries = update
13385 .into_iter()
13386 .filter(|event| globs.is_match(&event.path))
13387 .collect::<Vec<_>>();
13388 this.lsp_notify_abs_paths_changed(
13389 language_server_id,
13390 matching_entries,
13391 );
13392 ControlFlow::Continue(())
13393 })
13394 .ok()?;
13395
13396 if action.is_break() {
13397 break;
13398 }
13399 }
13400 Some(())
13401 })
13402 .await;
13403 }
13404 });
13405 (abs_path, (globset, task))
13406 })
13407 .collect();
13408 LanguageServerWatchedPaths {
13409 worktree_paths: self.worktree_paths,
13410 abs_paths,
13411 }
13412 }
13413}
13414
13415struct LspBufferSnapshot {
13416 version: i32,
13417 snapshot: TextBufferSnapshot,
13418}
13419
13420/// A prompt requested by LSP server.
13421#[derive(Clone, Debug)]
13422pub struct LanguageServerPromptRequest {
13423 pub level: PromptLevel,
13424 pub message: String,
13425 pub actions: Vec<MessageActionItem>,
13426 pub lsp_name: String,
13427 pub(crate) response_channel: Sender<MessageActionItem>,
13428}
13429
13430impl LanguageServerPromptRequest {
13431 pub async fn respond(self, index: usize) -> Option<()> {
13432 if let Some(response) = self.actions.into_iter().nth(index) {
13433 self.response_channel.send(response).await.ok()
13434 } else {
13435 None
13436 }
13437 }
13438}
13439impl PartialEq for LanguageServerPromptRequest {
13440 fn eq(&self, other: &Self) -> bool {
13441 self.message == other.message && self.actions == other.actions
13442 }
13443}
13444
13445#[derive(Clone, Debug, PartialEq)]
13446pub enum LanguageServerLogType {
13447 Log(MessageType),
13448 Trace { verbose_info: Option<String> },
13449 Rpc { received: bool },
13450}
13451
13452impl LanguageServerLogType {
13453 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13454 match self {
13455 Self::Log(log_type) => {
13456 use proto::log_message::LogLevel;
13457 let level = match *log_type {
13458 MessageType::ERROR => LogLevel::Error,
13459 MessageType::WARNING => LogLevel::Warning,
13460 MessageType::INFO => LogLevel::Info,
13461 MessageType::LOG => LogLevel::Log,
13462 other => {
13463 log::warn!("Unknown lsp log message type: {other:?}");
13464 LogLevel::Log
13465 }
13466 };
13467 proto::language_server_log::LogType::Log(proto::LogMessage {
13468 level: level as i32,
13469 })
13470 }
13471 Self::Trace { verbose_info } => {
13472 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13473 verbose_info: verbose_info.to_owned(),
13474 })
13475 }
13476 Self::Rpc { received } => {
13477 let kind = if *received {
13478 proto::rpc_message::Kind::Received
13479 } else {
13480 proto::rpc_message::Kind::Sent
13481 };
13482 let kind = kind as i32;
13483 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13484 }
13485 }
13486 }
13487
13488 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13489 use proto::log_message::LogLevel;
13490 use proto::rpc_message;
13491 match log_type {
13492 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13493 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13494 LogLevel::Error => MessageType::ERROR,
13495 LogLevel::Warning => MessageType::WARNING,
13496 LogLevel::Info => MessageType::INFO,
13497 LogLevel::Log => MessageType::LOG,
13498 },
13499 ),
13500 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13501 verbose_info: trace_message.verbose_info,
13502 },
13503 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13504 received: match rpc_message::Kind::from_i32(message.kind)
13505 .unwrap_or(rpc_message::Kind::Received)
13506 {
13507 rpc_message::Kind::Received => true,
13508 rpc_message::Kind::Sent => false,
13509 },
13510 },
13511 }
13512 }
13513}
13514
13515pub struct WorkspaceRefreshTask {
13516 refresh_tx: mpsc::Sender<()>,
13517 progress_tx: mpsc::Sender<()>,
13518 #[allow(dead_code)]
13519 task: Task<()>,
13520}
13521
13522pub enum LanguageServerState {
13523 Starting {
13524 startup: Task<Option<Arc<LanguageServer>>>,
13525 /// List of language servers that will be added to the workspace once it's initialization completes.
13526 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13527 },
13528
13529 Running {
13530 adapter: Arc<CachedLspAdapter>,
13531 server: Arc<LanguageServer>,
13532 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13533 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13534 },
13535}
13536
13537impl LanguageServerState {
13538 fn add_workspace_folder(&self, uri: Uri) {
13539 match self {
13540 LanguageServerState::Starting {
13541 pending_workspace_folders,
13542 ..
13543 } => {
13544 pending_workspace_folders.lock().insert(uri);
13545 }
13546 LanguageServerState::Running { server, .. } => {
13547 server.add_workspace_folder(uri);
13548 }
13549 }
13550 }
13551 fn _remove_workspace_folder(&self, uri: Uri) {
13552 match self {
13553 LanguageServerState::Starting {
13554 pending_workspace_folders,
13555 ..
13556 } => {
13557 pending_workspace_folders.lock().remove(&uri);
13558 }
13559 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13560 }
13561 }
13562}
13563
13564impl std::fmt::Debug for LanguageServerState {
13565 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13566 match self {
13567 LanguageServerState::Starting { .. } => {
13568 f.debug_struct("LanguageServerState::Starting").finish()
13569 }
13570 LanguageServerState::Running { .. } => {
13571 f.debug_struct("LanguageServerState::Running").finish()
13572 }
13573 }
13574 }
13575}
13576
13577#[derive(Clone, Debug, Serialize)]
13578pub struct LanguageServerProgress {
13579 pub is_disk_based_diagnostics_progress: bool,
13580 pub is_cancellable: bool,
13581 pub title: Option<String>,
13582 pub message: Option<String>,
13583 pub percentage: Option<usize>,
13584 #[serde(skip_serializing)]
13585 pub last_update_at: Instant,
13586}
13587
13588#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13589pub struct DiagnosticSummary {
13590 pub error_count: usize,
13591 pub warning_count: usize,
13592}
13593
13594impl DiagnosticSummary {
13595 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13596 let mut this = Self {
13597 error_count: 0,
13598 warning_count: 0,
13599 };
13600
13601 for entry in diagnostics {
13602 if entry.diagnostic.is_primary {
13603 match entry.diagnostic.severity {
13604 DiagnosticSeverity::ERROR => this.error_count += 1,
13605 DiagnosticSeverity::WARNING => this.warning_count += 1,
13606 _ => {}
13607 }
13608 }
13609 }
13610
13611 this
13612 }
13613
13614 pub fn is_empty(&self) -> bool {
13615 self.error_count == 0 && self.warning_count == 0
13616 }
13617
13618 pub fn to_proto(
13619 self,
13620 language_server_id: LanguageServerId,
13621 path: &RelPath,
13622 ) -> proto::DiagnosticSummary {
13623 proto::DiagnosticSummary {
13624 path: path.to_proto(),
13625 language_server_id: language_server_id.0 as u64,
13626 error_count: self.error_count as u32,
13627 warning_count: self.warning_count as u32,
13628 }
13629 }
13630}
13631
13632#[derive(Clone, Debug)]
13633pub enum CompletionDocumentation {
13634 /// There is no documentation for this completion.
13635 Undocumented,
13636 /// A single line of documentation.
13637 SingleLine(SharedString),
13638 /// Multiple lines of plain text documentation.
13639 MultiLinePlainText(SharedString),
13640 /// Markdown documentation.
13641 MultiLineMarkdown(SharedString),
13642 /// Both single line and multiple lines of plain text documentation.
13643 SingleLineAndMultiLinePlainText {
13644 single_line: SharedString,
13645 plain_text: Option<SharedString>,
13646 },
13647}
13648
13649impl CompletionDocumentation {
13650 #[cfg(any(test, feature = "test-support"))]
13651 pub fn text(&self) -> SharedString {
13652 match self {
13653 CompletionDocumentation::Undocumented => "".into(),
13654 CompletionDocumentation::SingleLine(s) => s.clone(),
13655 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13656 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13657 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13658 single_line.clone()
13659 }
13660 }
13661 }
13662}
13663
13664impl From<lsp::Documentation> for CompletionDocumentation {
13665 fn from(docs: lsp::Documentation) -> Self {
13666 match docs {
13667 lsp::Documentation::String(text) => {
13668 if text.lines().count() <= 1 {
13669 CompletionDocumentation::SingleLine(text.into())
13670 } else {
13671 CompletionDocumentation::MultiLinePlainText(text.into())
13672 }
13673 }
13674
13675 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13676 lsp::MarkupKind::PlainText => {
13677 if value.lines().count() <= 1 {
13678 CompletionDocumentation::SingleLine(value.into())
13679 } else {
13680 CompletionDocumentation::MultiLinePlainText(value.into())
13681 }
13682 }
13683
13684 lsp::MarkupKind::Markdown => {
13685 CompletionDocumentation::MultiLineMarkdown(value.into())
13686 }
13687 },
13688 }
13689 }
13690}
13691
13692pub enum ResolvedHint {
13693 Resolved(InlayHint),
13694 Resolving(Shared<Task<()>>),
13695}
13696
13697fn glob_literal_prefix(glob: &Path) -> PathBuf {
13698 glob.components()
13699 .take_while(|component| match component {
13700 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13701 _ => true,
13702 })
13703 .collect()
13704}
13705
13706pub struct SshLspAdapter {
13707 name: LanguageServerName,
13708 binary: LanguageServerBinary,
13709 initialization_options: Option<String>,
13710 code_action_kinds: Option<Vec<CodeActionKind>>,
13711}
13712
13713impl SshLspAdapter {
13714 pub fn new(
13715 name: LanguageServerName,
13716 binary: LanguageServerBinary,
13717 initialization_options: Option<String>,
13718 code_action_kinds: Option<String>,
13719 ) -> Self {
13720 Self {
13721 name,
13722 binary,
13723 initialization_options,
13724 code_action_kinds: code_action_kinds
13725 .as_ref()
13726 .and_then(|c| serde_json::from_str(c).ok()),
13727 }
13728 }
13729}
13730
13731impl LspInstaller for SshLspAdapter {
13732 type BinaryVersion = ();
13733 async fn check_if_user_installed(
13734 &self,
13735 _: &dyn LspAdapterDelegate,
13736 _: Option<Toolchain>,
13737 _: &AsyncApp,
13738 ) -> Option<LanguageServerBinary> {
13739 Some(self.binary.clone())
13740 }
13741
13742 async fn cached_server_binary(
13743 &self,
13744 _: PathBuf,
13745 _: &dyn LspAdapterDelegate,
13746 ) -> Option<LanguageServerBinary> {
13747 None
13748 }
13749
13750 async fn fetch_latest_server_version(
13751 &self,
13752 _: &dyn LspAdapterDelegate,
13753 _: bool,
13754 _: &mut AsyncApp,
13755 ) -> Result<()> {
13756 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13757 }
13758
13759 async fn fetch_server_binary(
13760 &self,
13761 _: (),
13762 _: PathBuf,
13763 _: &dyn LspAdapterDelegate,
13764 ) -> Result<LanguageServerBinary> {
13765 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13766 }
13767}
13768
13769#[async_trait(?Send)]
13770impl LspAdapter for SshLspAdapter {
13771 fn name(&self) -> LanguageServerName {
13772 self.name.clone()
13773 }
13774
13775 async fn initialization_options(
13776 self: Arc<Self>,
13777 _: &Arc<dyn LspAdapterDelegate>,
13778 ) -> Result<Option<serde_json::Value>> {
13779 let Some(options) = &self.initialization_options else {
13780 return Ok(None);
13781 };
13782 let result = serde_json::from_str(options)?;
13783 Ok(result)
13784 }
13785
13786 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13787 self.code_action_kinds.clone()
13788 }
13789}
13790
13791pub fn language_server_settings<'a>(
13792 delegate: &'a dyn LspAdapterDelegate,
13793 language: &LanguageServerName,
13794 cx: &'a App,
13795) -> Option<&'a LspSettings> {
13796 language_server_settings_for(
13797 SettingsLocation {
13798 worktree_id: delegate.worktree_id(),
13799 path: RelPath::empty(),
13800 },
13801 language,
13802 cx,
13803 )
13804}
13805
13806pub fn language_server_settings_for<'a>(
13807 location: SettingsLocation<'a>,
13808 language: &LanguageServerName,
13809 cx: &'a App,
13810) -> Option<&'a LspSettings> {
13811 ProjectSettings::get(Some(location), cx).lsp.get(language)
13812}
13813
13814pub struct LocalLspAdapterDelegate {
13815 lsp_store: WeakEntity<LspStore>,
13816 worktree: worktree::Snapshot,
13817 fs: Arc<dyn Fs>,
13818 http_client: Arc<dyn HttpClient>,
13819 language_registry: Arc<LanguageRegistry>,
13820 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13821}
13822
13823impl LocalLspAdapterDelegate {
13824 pub fn new(
13825 language_registry: Arc<LanguageRegistry>,
13826 environment: &Entity<ProjectEnvironment>,
13827 lsp_store: WeakEntity<LspStore>,
13828 worktree: &Entity<Worktree>,
13829 http_client: Arc<dyn HttpClient>,
13830 fs: Arc<dyn Fs>,
13831 cx: &mut App,
13832 ) -> Arc<Self> {
13833 let load_shell_env_task =
13834 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13835
13836 Arc::new(Self {
13837 lsp_store,
13838 worktree: worktree.read(cx).snapshot(),
13839 fs,
13840 http_client,
13841 language_registry,
13842 load_shell_env_task,
13843 })
13844 }
13845
13846 fn from_local_lsp(
13847 local: &LocalLspStore,
13848 worktree: &Entity<Worktree>,
13849 cx: &mut App,
13850 ) -> Arc<Self> {
13851 Self::new(
13852 local.languages.clone(),
13853 &local.environment,
13854 local.weak.clone(),
13855 worktree,
13856 local.http_client.clone(),
13857 local.fs.clone(),
13858 cx,
13859 )
13860 }
13861}
13862
13863#[async_trait]
13864impl LspAdapterDelegate for LocalLspAdapterDelegate {
13865 fn show_notification(&self, message: &str, cx: &mut App) {
13866 self.lsp_store
13867 .update(cx, |_, cx| {
13868 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13869 })
13870 .ok();
13871 }
13872
13873 fn http_client(&self) -> Arc<dyn HttpClient> {
13874 self.http_client.clone()
13875 }
13876
13877 fn worktree_id(&self) -> WorktreeId {
13878 self.worktree.id()
13879 }
13880
13881 fn worktree_root_path(&self) -> &Path {
13882 self.worktree.abs_path().as_ref()
13883 }
13884
13885 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13886 self.worktree.resolve_executable_path(path)
13887 }
13888
13889 async fn shell_env(&self) -> HashMap<String, String> {
13890 let task = self.load_shell_env_task.clone();
13891 task.await.unwrap_or_default()
13892 }
13893
13894 async fn npm_package_installed_version(
13895 &self,
13896 package_name: &str,
13897 ) -> Result<Option<(PathBuf, String)>> {
13898 let local_package_directory = self.worktree_root_path();
13899 let node_modules_directory = local_package_directory.join("node_modules");
13900
13901 if let Some(version) =
13902 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13903 {
13904 return Ok(Some((node_modules_directory, version)));
13905 }
13906 let Some(npm) = self.which("npm".as_ref()).await else {
13907 log::warn!(
13908 "Failed to find npm executable for {:?}",
13909 local_package_directory
13910 );
13911 return Ok(None);
13912 };
13913
13914 let env = self.shell_env().await;
13915 let output = util::command::new_smol_command(&npm)
13916 .args(["root", "-g"])
13917 .envs(env)
13918 .current_dir(local_package_directory)
13919 .output()
13920 .await?;
13921 let global_node_modules =
13922 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13923
13924 if let Some(version) =
13925 read_package_installed_version(global_node_modules.clone(), package_name).await?
13926 {
13927 return Ok(Some((global_node_modules, version)));
13928 }
13929 return Ok(None);
13930 }
13931
13932 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13933 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13934 if self.fs.is_file(&worktree_abs_path).await {
13935 worktree_abs_path.pop();
13936 }
13937
13938 let env = self.shell_env().await;
13939
13940 let shell_path = env.get("PATH").cloned();
13941
13942 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13943 }
13944
13945 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13946 let mut working_dir = self.worktree_root_path().to_path_buf();
13947 if self.fs.is_file(&working_dir).await {
13948 working_dir.pop();
13949 }
13950 let output = util::command::new_smol_command(&command.path)
13951 .args(command.arguments)
13952 .envs(command.env.clone().unwrap_or_default())
13953 .current_dir(working_dir)
13954 .output()
13955 .await?;
13956
13957 anyhow::ensure!(
13958 output.status.success(),
13959 "{}, stdout: {:?}, stderr: {:?}",
13960 output.status,
13961 String::from_utf8_lossy(&output.stdout),
13962 String::from_utf8_lossy(&output.stderr)
13963 );
13964 Ok(())
13965 }
13966
13967 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13968 self.language_registry
13969 .update_lsp_binary_status(server_name, status);
13970 }
13971
13972 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13973 self.language_registry
13974 .all_lsp_adapters()
13975 .into_iter()
13976 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13977 .collect()
13978 }
13979
13980 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13981 let dir = self.language_registry.language_server_download_dir(name)?;
13982
13983 if !dir.exists() {
13984 smol::fs::create_dir_all(&dir)
13985 .await
13986 .context("failed to create container directory")
13987 .log_err()?;
13988 }
13989
13990 Some(dir)
13991 }
13992
13993 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13994 let entry = self
13995 .worktree
13996 .entry_for_path(path)
13997 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13998 let abs_path = self.worktree.absolutize(&entry.path);
13999 self.fs.load(&abs_path).await
14000 }
14001}
14002
14003async fn populate_labels_for_symbols(
14004 symbols: Vec<CoreSymbol>,
14005 language_registry: &Arc<LanguageRegistry>,
14006 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14007 output: &mut Vec<Symbol>,
14008) {
14009 #[allow(clippy::mutable_key_type)]
14010 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14011
14012 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14013 for symbol in symbols {
14014 let Some(file_name) = symbol.path.file_name() else {
14015 continue;
14016 };
14017 let language = language_registry
14018 .load_language_for_file_path(Path::new(file_name))
14019 .await
14020 .ok()
14021 .or_else(|| {
14022 unknown_paths.insert(file_name.into());
14023 None
14024 });
14025 symbols_by_language
14026 .entry(language)
14027 .or_default()
14028 .push(symbol);
14029 }
14030
14031 for unknown_path in unknown_paths {
14032 log::info!("no language found for symbol in file {unknown_path:?}");
14033 }
14034
14035 let mut label_params = Vec::new();
14036 for (language, mut symbols) in symbols_by_language {
14037 label_params.clear();
14038 label_params.extend(
14039 symbols
14040 .iter_mut()
14041 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14042 );
14043
14044 let mut labels = Vec::new();
14045 if let Some(language) = language {
14046 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14047 language_registry
14048 .lsp_adapters(&language.name())
14049 .first()
14050 .cloned()
14051 });
14052 if let Some(lsp_adapter) = lsp_adapter {
14053 labels = lsp_adapter
14054 .labels_for_symbols(&label_params, &language)
14055 .await
14056 .log_err()
14057 .unwrap_or_default();
14058 }
14059 }
14060
14061 for ((symbol, (name, _)), label) in symbols
14062 .into_iter()
14063 .zip(label_params.drain(..))
14064 .zip(labels.into_iter().chain(iter::repeat(None)))
14065 {
14066 output.push(Symbol {
14067 language_server_name: symbol.language_server_name,
14068 source_worktree_id: symbol.source_worktree_id,
14069 source_language_server_id: symbol.source_language_server_id,
14070 path: symbol.path,
14071 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14072 name,
14073 kind: symbol.kind,
14074 range: symbol.range,
14075 });
14076 }
14077 }
14078}
14079
14080fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14081 match server.capabilities().text_document_sync.as_ref()? {
14082 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14083 // Server wants didSave but didn't specify includeText.
14084 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14085 // Server doesn't want didSave at all.
14086 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14087 // Server provided SaveOptions.
14088 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14089 Some(save_options.include_text.unwrap_or(false))
14090 }
14091 },
14092 // We do not have any save info. Kind affects didChange only.
14093 lsp::TextDocumentSyncCapability::Kind(_) => None,
14094 }
14095}
14096
14097/// Completion items are displayed in a `UniformList`.
14098/// Usually, those items are single-line strings, but in LSP responses,
14099/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14100/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14101/// 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,
14102/// breaking the completions menu presentation.
14103///
14104/// 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.
14105fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14106 let mut new_text = String::with_capacity(label.text.len());
14107 let mut offset_map = vec![0; label.text.len() + 1];
14108 let mut last_char_was_space = false;
14109 let mut new_idx = 0;
14110 let chars = label.text.char_indices().fuse();
14111 let mut newlines_removed = false;
14112
14113 for (idx, c) in chars {
14114 offset_map[idx] = new_idx;
14115
14116 match c {
14117 '\n' if last_char_was_space => {
14118 newlines_removed = true;
14119 }
14120 '\t' | ' ' if last_char_was_space => {}
14121 '\n' if !last_char_was_space => {
14122 new_text.push(' ');
14123 new_idx += 1;
14124 last_char_was_space = true;
14125 newlines_removed = true;
14126 }
14127 ' ' | '\t' => {
14128 new_text.push(' ');
14129 new_idx += 1;
14130 last_char_was_space = true;
14131 }
14132 _ => {
14133 new_text.push(c);
14134 new_idx += c.len_utf8();
14135 last_char_was_space = false;
14136 }
14137 }
14138 }
14139 offset_map[label.text.len()] = new_idx;
14140
14141 // Only modify the label if newlines were removed.
14142 if !newlines_removed {
14143 return;
14144 }
14145
14146 let last_index = new_idx;
14147 let mut run_ranges_errors = Vec::new();
14148 label.runs.retain_mut(|(range, _)| {
14149 match offset_map.get(range.start) {
14150 Some(&start) => range.start = start,
14151 None => {
14152 run_ranges_errors.push(range.clone());
14153 return false;
14154 }
14155 }
14156
14157 match offset_map.get(range.end) {
14158 Some(&end) => range.end = end,
14159 None => {
14160 run_ranges_errors.push(range.clone());
14161 range.end = last_index;
14162 }
14163 }
14164 true
14165 });
14166 if !run_ranges_errors.is_empty() {
14167 log::error!(
14168 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14169 label.text
14170 );
14171 }
14172
14173 let mut wrong_filter_range = None;
14174 if label.filter_range == (0..label.text.len()) {
14175 label.filter_range = 0..new_text.len();
14176 } else {
14177 let mut original_filter_range = Some(label.filter_range.clone());
14178 match offset_map.get(label.filter_range.start) {
14179 Some(&start) => label.filter_range.start = start,
14180 None => {
14181 wrong_filter_range = original_filter_range.take();
14182 label.filter_range.start = last_index;
14183 }
14184 }
14185
14186 match offset_map.get(label.filter_range.end) {
14187 Some(&end) => label.filter_range.end = end,
14188 None => {
14189 wrong_filter_range = original_filter_range.take();
14190 label.filter_range.end = last_index;
14191 }
14192 }
14193 }
14194 if let Some(wrong_filter_range) = wrong_filter_range {
14195 log::error!(
14196 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14197 label.text
14198 );
14199 }
14200
14201 label.text = new_text;
14202}
14203
14204#[cfg(test)]
14205mod tests {
14206 use language::HighlightId;
14207
14208 use super::*;
14209
14210 #[test]
14211 fn test_glob_literal_prefix() {
14212 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14213 assert_eq!(
14214 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14215 Path::new("node_modules")
14216 );
14217 assert_eq!(
14218 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14219 Path::new("foo")
14220 );
14221 assert_eq!(
14222 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14223 Path::new("foo/bar/baz.js")
14224 );
14225
14226 #[cfg(target_os = "windows")]
14227 {
14228 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14229 assert_eq!(
14230 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14231 Path::new("node_modules")
14232 );
14233 assert_eq!(
14234 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14235 Path::new("foo")
14236 );
14237 assert_eq!(
14238 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14239 Path::new("foo/bar/baz.js")
14240 );
14241 }
14242 }
14243
14244 #[test]
14245 fn test_multi_len_chars_normalization() {
14246 let mut label = CodeLabel::new(
14247 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14248 0..6,
14249 vec![(0..6, HighlightId(1))],
14250 );
14251 ensure_uniform_list_compatible_label(&mut label);
14252 assert_eq!(
14253 label,
14254 CodeLabel::new(
14255 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14256 0..6,
14257 vec![(0..6, HighlightId(1))],
14258 )
14259 );
14260 }
14261}