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
204#[derive(Clone, PartialEq, Eq, Hash)]
205pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
206
207struct OpenLspBuffer(Entity<Buffer>);
208
209impl FormatTrigger {
210 fn from_proto(value: i32) -> FormatTrigger {
211 match value {
212 0 => FormatTrigger::Save,
213 1 => FormatTrigger::Manual,
214 _ => FormatTrigger::Save,
215 }
216 }
217}
218
219#[derive(Clone)]
220struct UnifiedLanguageServer {
221 id: LanguageServerId,
222 project_roots: HashSet<Arc<RelPath>>,
223}
224
225#[derive(Clone, Debug, Hash, PartialEq, Eq)]
226struct LanguageServerSeed {
227 worktree_id: WorktreeId,
228 name: LanguageServerName,
229 toolchain: Option<Toolchain>,
230 settings: Arc<LspSettings>,
231}
232
233#[derive(Debug)]
234pub struct DocumentDiagnosticsUpdate<'a, D> {
235 pub diagnostics: D,
236 pub result_id: Option<SharedString>,
237 pub registration_id: Option<SharedString>,
238 pub server_id: LanguageServerId,
239 pub disk_based_sources: Cow<'a, [String]>,
240}
241
242pub struct DocumentDiagnostics {
243 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
244 document_abs_path: PathBuf,
245 version: Option<i32>,
246}
247
248#[derive(Default, Debug)]
249struct DynamicRegistrations {
250 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
251 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
252}
253
254pub struct LocalLspStore {
255 weak: WeakEntity<LspStore>,
256 worktree_store: Entity<WorktreeStore>,
257 toolchain_store: Entity<LocalToolchainStore>,
258 http_client: Arc<dyn HttpClient>,
259 environment: Entity<ProjectEnvironment>,
260 fs: Arc<dyn Fs>,
261 languages: Arc<LanguageRegistry>,
262 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
263 yarn: Entity<YarnPathStore>,
264 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
265 buffers_being_formatted: HashSet<BufferId>,
266 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
267 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
268 watched_manifest_filenames: HashSet<ManifestName>,
269 language_server_paths_watched_for_rename:
270 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
271 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
272 supplementary_language_servers:
273 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
274 prettier_store: Entity<PrettierStore>,
275 next_diagnostic_group_id: usize,
276 diagnostics: HashMap<
277 WorktreeId,
278 HashMap<
279 Arc<RelPath>,
280 Vec<(
281 LanguageServerId,
282 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
283 )>,
284 >,
285 >,
286 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
287 _subscription: gpui::Subscription,
288 lsp_tree: LanguageServerTree,
289 registered_buffers: HashMap<BufferId, usize>,
290 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
291 buffer_pull_diagnostics_result_ids: HashMap<
292 LanguageServerId,
293 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
294 >,
295 workspace_pull_diagnostics_result_ids: HashMap<
296 LanguageServerId,
297 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
298 >,
299}
300
301impl LocalLspStore {
302 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
303 pub fn running_language_server_for_id(
304 &self,
305 id: LanguageServerId,
306 ) -> Option<&Arc<LanguageServer>> {
307 let language_server_state = self.language_servers.get(&id)?;
308
309 match language_server_state {
310 LanguageServerState::Running { server, .. } => Some(server),
311 LanguageServerState::Starting { .. } => None,
312 }
313 }
314
315 fn get_or_insert_language_server(
316 &mut self,
317 worktree_handle: &Entity<Worktree>,
318 delegate: Arc<LocalLspAdapterDelegate>,
319 disposition: &Arc<LaunchDisposition>,
320 language_name: &LanguageName,
321 cx: &mut App,
322 ) -> LanguageServerId {
323 let key = LanguageServerSeed {
324 worktree_id: worktree_handle.read(cx).id(),
325 name: disposition.server_name.clone(),
326 settings: disposition.settings.clone(),
327 toolchain: disposition.toolchain.clone(),
328 };
329 if let Some(state) = self.language_server_ids.get_mut(&key) {
330 state.project_roots.insert(disposition.path.path.clone());
331 state.id
332 } else {
333 let adapter = self
334 .languages
335 .lsp_adapters(language_name)
336 .into_iter()
337 .find(|adapter| adapter.name() == disposition.server_name)
338 .expect("To find LSP adapter");
339 let new_language_server_id = self.start_language_server(
340 worktree_handle,
341 delegate,
342 adapter,
343 disposition.settings.clone(),
344 key.clone(),
345 cx,
346 );
347 if let Some(state) = self.language_server_ids.get_mut(&key) {
348 state.project_roots.insert(disposition.path.path.clone());
349 } else {
350 debug_assert!(
351 false,
352 "Expected `start_language_server` to ensure that `key` exists in a map"
353 );
354 }
355 new_language_server_id
356 }
357 }
358
359 fn start_language_server(
360 &mut self,
361 worktree_handle: &Entity<Worktree>,
362 delegate: Arc<LocalLspAdapterDelegate>,
363 adapter: Arc<CachedLspAdapter>,
364 settings: Arc<LspSettings>,
365 key: LanguageServerSeed,
366 cx: &mut App,
367 ) -> LanguageServerId {
368 let worktree = worktree_handle.read(cx);
369
370 let root_path = worktree.abs_path();
371 let toolchain = key.toolchain.clone();
372 let override_options = settings.initialization_options.clone();
373
374 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
375
376 let server_id = self.languages.next_language_server_id();
377 log::trace!(
378 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
379 adapter.name.0
380 );
381
382 let binary = self.get_language_server_binary(
383 adapter.clone(),
384 settings,
385 toolchain.clone(),
386 delegate.clone(),
387 true,
388 cx,
389 );
390 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
391
392 let pending_server = cx.spawn({
393 let adapter = adapter.clone();
394 let server_name = adapter.name.clone();
395 let stderr_capture = stderr_capture.clone();
396 #[cfg(any(test, feature = "test-support"))]
397 let lsp_store = self.weak.clone();
398 let pending_workspace_folders = pending_workspace_folders.clone();
399 async move |cx| {
400 let binary = binary.await?;
401 #[cfg(any(test, feature = "test-support"))]
402 if let Some(server) = lsp_store
403 .update(&mut cx.clone(), |this, cx| {
404 this.languages.create_fake_language_server(
405 server_id,
406 &server_name,
407 binary.clone(),
408 &mut cx.to_async(),
409 )
410 })
411 .ok()
412 .flatten()
413 {
414 return Ok(server);
415 }
416
417 let code_action_kinds = adapter.code_action_kinds();
418 lsp::LanguageServer::new(
419 stderr_capture,
420 server_id,
421 server_name,
422 binary,
423 &root_path,
424 code_action_kinds,
425 Some(pending_workspace_folders),
426 cx,
427 )
428 }
429 });
430
431 let startup = {
432 let server_name = adapter.name.0.clone();
433 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
434 let key = key.clone();
435 let adapter = adapter.clone();
436 let lsp_store = self.weak.clone();
437 let pending_workspace_folders = pending_workspace_folders.clone();
438
439 let pull_diagnostics = ProjectSettings::get_global(cx)
440 .diagnostics
441 .lsp_pull_diagnostics
442 .enabled;
443 cx.spawn(async move |cx| {
444 let result = async {
445 let language_server = pending_server.await?;
446
447 let workspace_config = Self::workspace_configuration_for_adapter(
448 adapter.adapter.clone(),
449 &delegate,
450 toolchain,
451 None,
452 cx,
453 )
454 .await?;
455
456 let mut initialization_options = Self::initialization_options_for_adapter(
457 adapter.adapter.clone(),
458 &delegate,
459 )
460 .await?;
461
462 match (&mut initialization_options, override_options) {
463 (Some(initialization_options), Some(override_options)) => {
464 merge_json_value_into(override_options, initialization_options);
465 }
466 (None, override_options) => initialization_options = override_options,
467 _ => {}
468 }
469
470 let initialization_params = cx.update(|cx| {
471 let mut params =
472 language_server.default_initialize_params(pull_diagnostics, cx);
473 params.initialization_options = initialization_options;
474 adapter.adapter.prepare_initialize_params(params, cx)
475 })??;
476
477 Self::setup_lsp_messages(
478 lsp_store.clone(),
479 &language_server,
480 delegate.clone(),
481 adapter.clone(),
482 );
483
484 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
485 settings: workspace_config,
486 };
487 let language_server = cx
488 .update(|cx| {
489 language_server.initialize(
490 initialization_params,
491 Arc::new(did_change_configuration_params.clone()),
492 cx,
493 )
494 })?
495 .await
496 .inspect_err(|_| {
497 if let Some(lsp_store) = lsp_store.upgrade() {
498 lsp_store
499 .update(cx, |lsp_store, cx| {
500 lsp_store.cleanup_lsp_data(server_id);
501 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
502 })
503 .ok();
504 }
505 })?;
506
507 language_server.notify::<lsp::notification::DidChangeConfiguration>(
508 did_change_configuration_params,
509 )?;
510
511 anyhow::Ok(language_server)
512 }
513 .await;
514
515 match result {
516 Ok(server) => {
517 lsp_store
518 .update(cx, |lsp_store, cx| {
519 lsp_store.insert_newly_running_language_server(
520 adapter,
521 server.clone(),
522 server_id,
523 key,
524 pending_workspace_folders,
525 cx,
526 );
527 })
528 .ok();
529 stderr_capture.lock().take();
530 Some(server)
531 }
532
533 Err(err) => {
534 let log = stderr_capture.lock().take().unwrap_or_default();
535 delegate.update_status(
536 adapter.name(),
537 BinaryStatus::Failed {
538 error: if log.is_empty() {
539 format!("{err:#}")
540 } else {
541 format!("{err:#}\n-- stderr --\n{log}")
542 },
543 },
544 );
545 log::error!("Failed to start language server {server_name:?}: {err:?}");
546 if !log.is_empty() {
547 log::error!("server stderr: {log}");
548 }
549 None
550 }
551 }
552 })
553 };
554 let state = LanguageServerState::Starting {
555 startup,
556 pending_workspace_folders,
557 };
558
559 self.languages
560 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
561
562 self.language_servers.insert(server_id, state);
563 self.language_server_ids
564 .entry(key)
565 .or_insert(UnifiedLanguageServer {
566 id: server_id,
567 project_roots: Default::default(),
568 });
569 server_id
570 }
571
572 fn get_language_server_binary(
573 &self,
574 adapter: Arc<CachedLspAdapter>,
575 settings: Arc<LspSettings>,
576 toolchain: Option<Toolchain>,
577 delegate: Arc<dyn LspAdapterDelegate>,
578 allow_binary_download: bool,
579 cx: &mut App,
580 ) -> Task<Result<LanguageServerBinary>> {
581 if let Some(settings) = &settings.binary
582 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
583 {
584 let settings = settings.clone();
585
586 return cx.background_spawn(async move {
587 let mut env = delegate.shell_env().await;
588 env.extend(settings.env.unwrap_or_default());
589
590 Ok(LanguageServerBinary {
591 path: delegate.resolve_executable_path(path),
592 env: Some(env),
593 arguments: settings
594 .arguments
595 .unwrap_or_default()
596 .iter()
597 .map(Into::into)
598 .collect(),
599 })
600 });
601 }
602 let lsp_binary_options = LanguageServerBinaryOptions {
603 allow_path_lookup: !settings
604 .binary
605 .as_ref()
606 .and_then(|b| b.ignore_system_version)
607 .unwrap_or_default(),
608 allow_binary_download,
609 pre_release: settings
610 .fetch
611 .as_ref()
612 .and_then(|f| f.pre_release)
613 .unwrap_or(false),
614 };
615
616 cx.spawn(async move |cx| {
617 let (existing_binary, maybe_download_binary) = adapter
618 .clone()
619 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
620 .await
621 .await;
622
623 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
624
625 let mut binary = match (existing_binary, maybe_download_binary) {
626 (binary, None) => binary?,
627 (Err(_), Some(downloader)) => downloader.await?,
628 (Ok(existing_binary), Some(downloader)) => {
629 let mut download_timeout = cx
630 .background_executor()
631 .timer(SERVER_DOWNLOAD_TIMEOUT)
632 .fuse();
633 let mut downloader = downloader.fuse();
634 futures::select! {
635 _ = download_timeout => {
636 // Return existing binary and kick the existing work to the background.
637 cx.spawn(async move |_| downloader.await).detach();
638 Ok(existing_binary)
639 },
640 downloaded_or_existing_binary = downloader => {
641 // If download fails, this results in the existing binary.
642 downloaded_or_existing_binary
643 }
644 }?
645 }
646 };
647 let mut shell_env = delegate.shell_env().await;
648
649 shell_env.extend(binary.env.unwrap_or_default());
650
651 if let Some(settings) = settings.binary.as_ref() {
652 if let Some(arguments) = &settings.arguments {
653 binary.arguments = arguments.iter().map(Into::into).collect();
654 }
655 if let Some(env) = &settings.env {
656 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
657 }
658 }
659
660 binary.env = Some(shell_env);
661 Ok(binary)
662 })
663 }
664
665 fn setup_lsp_messages(
666 lsp_store: WeakEntity<LspStore>,
667 language_server: &LanguageServer,
668 delegate: Arc<dyn LspAdapterDelegate>,
669 adapter: Arc<CachedLspAdapter>,
670 ) {
671 let name = language_server.name();
672 let server_id = language_server.server_id();
673 language_server
674 .on_notification::<lsp::notification::PublishDiagnostics, _>({
675 let adapter = adapter.clone();
676 let this = lsp_store.clone();
677 move |mut params, cx| {
678 let adapter = adapter.clone();
679 if let Some(this) = this.upgrade() {
680 this.update(cx, |this, cx| {
681 {
682 let buffer = params
683 .uri
684 .to_file_path()
685 .map(|file_path| this.get_buffer(&file_path, cx))
686 .ok()
687 .flatten();
688 adapter.process_diagnostics(&mut params, server_id, buffer);
689 }
690
691 this.merge_lsp_diagnostics(
692 DiagnosticSourceKind::Pushed,
693 vec![DocumentDiagnosticsUpdate {
694 server_id,
695 diagnostics: params,
696 result_id: None,
697 disk_based_sources: Cow::Borrowed(
698 &adapter.disk_based_diagnostic_sources,
699 ),
700 registration_id: None,
701 }],
702 |_, diagnostic, cx| match diagnostic.source_kind {
703 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
704 adapter.retain_old_diagnostic(diagnostic, cx)
705 }
706 DiagnosticSourceKind::Pulled => true,
707 },
708 cx,
709 )
710 .log_err();
711 })
712 .ok();
713 }
714 }
715 })
716 .detach();
717 language_server
718 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
719 let adapter = adapter.adapter.clone();
720 let delegate = delegate.clone();
721 let this = lsp_store.clone();
722 move |params, cx| {
723 let adapter = adapter.clone();
724 let delegate = delegate.clone();
725 let this = this.clone();
726 let mut cx = cx.clone();
727 async move {
728 let toolchain_for_id = this
729 .update(&mut cx, |this, _| {
730 this.as_local()?.language_server_ids.iter().find_map(
731 |(seed, value)| {
732 (value.id == server_id).then(|| seed.toolchain.clone())
733 },
734 )
735 })?
736 .context("Expected the LSP store to be in a local mode")?;
737
738 let mut scope_uri_to_workspace_config = BTreeMap::new();
739 for item in ¶ms.items {
740 let scope_uri = item.scope_uri.clone();
741 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
742 scope_uri_to_workspace_config.entry(scope_uri.clone())
743 else {
744 // We've already queried workspace configuration of this URI.
745 continue;
746 };
747 let workspace_config = Self::workspace_configuration_for_adapter(
748 adapter.clone(),
749 &delegate,
750 toolchain_for_id.clone(),
751 scope_uri,
752 &mut cx,
753 )
754 .await?;
755 new_scope_uri.insert(workspace_config);
756 }
757
758 Ok(params
759 .items
760 .into_iter()
761 .filter_map(|item| {
762 let workspace_config =
763 scope_uri_to_workspace_config.get(&item.scope_uri)?;
764 if let Some(section) = &item.section {
765 Some(
766 workspace_config
767 .get(section)
768 .cloned()
769 .unwrap_or(serde_json::Value::Null),
770 )
771 } else {
772 Some(workspace_config.clone())
773 }
774 })
775 .collect())
776 }
777 }
778 })
779 .detach();
780
781 language_server
782 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
783 let this = lsp_store.clone();
784 move |_, cx| {
785 let this = this.clone();
786 let cx = cx.clone();
787 async move {
788 let Some(server) =
789 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
790 else {
791 return Ok(None);
792 };
793 let root = server.workspace_folders();
794 Ok(Some(
795 root.into_iter()
796 .map(|uri| WorkspaceFolder {
797 uri,
798 name: Default::default(),
799 })
800 .collect(),
801 ))
802 }
803 }
804 })
805 .detach();
806 // Even though we don't have handling for these requests, respond to them to
807 // avoid stalling any language server like `gopls` which waits for a response
808 // to these requests when initializing.
809 language_server
810 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
811 let this = lsp_store.clone();
812 move |params, cx| {
813 let this = this.clone();
814 let mut cx = cx.clone();
815 async move {
816 this.update(&mut cx, |this, _| {
817 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
818 {
819 status
820 .progress_tokens
821 .insert(ProgressToken::from_lsp(params.token));
822 }
823 })?;
824
825 Ok(())
826 }
827 }
828 })
829 .detach();
830
831 language_server
832 .on_request::<lsp::request::RegisterCapability, _, _>({
833 let lsp_store = lsp_store.clone();
834 move |params, cx| {
835 let lsp_store = lsp_store.clone();
836 let mut cx = cx.clone();
837 async move {
838 lsp_store
839 .update(&mut cx, |lsp_store, cx| {
840 if lsp_store.as_local().is_some() {
841 match lsp_store
842 .register_server_capabilities(server_id, params, cx)
843 {
844 Ok(()) => {}
845 Err(e) => {
846 log::error!(
847 "Failed to register server capabilities: {e:#}"
848 );
849 }
850 };
851 }
852 })
853 .ok();
854 Ok(())
855 }
856 }
857 })
858 .detach();
859
860 language_server
861 .on_request::<lsp::request::UnregisterCapability, _, _>({
862 let lsp_store = lsp_store.clone();
863 move |params, cx| {
864 let lsp_store = lsp_store.clone();
865 let mut cx = cx.clone();
866 async move {
867 lsp_store
868 .update(&mut cx, |lsp_store, cx| {
869 if lsp_store.as_local().is_some() {
870 match lsp_store
871 .unregister_server_capabilities(server_id, params, cx)
872 {
873 Ok(()) => {}
874 Err(e) => {
875 log::error!(
876 "Failed to unregister server capabilities: {e:#}"
877 );
878 }
879 }
880 }
881 })
882 .ok();
883 Ok(())
884 }
885 }
886 })
887 .detach();
888
889 language_server
890 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
891 let this = lsp_store.clone();
892 move |params, cx| {
893 let mut cx = cx.clone();
894 let this = this.clone();
895 async move {
896 LocalLspStore::on_lsp_workspace_edit(
897 this.clone(),
898 params,
899 server_id,
900 &mut cx,
901 )
902 .await
903 }
904 }
905 })
906 .detach();
907
908 language_server
909 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
910 let lsp_store = lsp_store.clone();
911 let request_id = Arc::new(AtomicUsize::new(0));
912 move |(), cx| {
913 let lsp_store = lsp_store.clone();
914 let request_id = request_id.clone();
915 let mut cx = cx.clone();
916 async move {
917 lsp_store
918 .update(&mut cx, |lsp_store, cx| {
919 let request_id =
920 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
921 cx.emit(LspStoreEvent::RefreshInlayHints {
922 server_id,
923 request_id,
924 });
925 lsp_store
926 .downstream_client
927 .as_ref()
928 .map(|(client, project_id)| {
929 client.send(proto::RefreshInlayHints {
930 project_id: *project_id,
931 server_id: server_id.to_proto(),
932 request_id: request_id.map(|id| id as u64),
933 })
934 })
935 })?
936 .transpose()?;
937 Ok(())
938 }
939 }
940 })
941 .detach();
942
943 language_server
944 .on_request::<lsp::request::CodeLensRefresh, _, _>({
945 let this = lsp_store.clone();
946 move |(), cx| {
947 let this = this.clone();
948 let mut cx = cx.clone();
949 async move {
950 this.update(&mut cx, |this, cx| {
951 cx.emit(LspStoreEvent::RefreshCodeLens);
952 this.downstream_client.as_ref().map(|(client, project_id)| {
953 client.send(proto::RefreshCodeLens {
954 project_id: *project_id,
955 })
956 })
957 })?
958 .transpose()?;
959 Ok(())
960 }
961 }
962 })
963 .detach();
964
965 language_server
966 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
967 let this = lsp_store.clone();
968 move |(), cx| {
969 let this = this.clone();
970 let mut cx = cx.clone();
971 async move {
972 this.update(&mut cx, |lsp_store, _| {
973 lsp_store.pull_workspace_diagnostics(server_id);
974 lsp_store
975 .downstream_client
976 .as_ref()
977 .map(|(client, project_id)| {
978 client.send(proto::PullWorkspaceDiagnostics {
979 project_id: *project_id,
980 server_id: server_id.to_proto(),
981 })
982 })
983 })?
984 .transpose()?;
985 Ok(())
986 }
987 }
988 })
989 .detach();
990
991 language_server
992 .on_request::<lsp::request::ShowMessageRequest, _, _>({
993 let this = lsp_store.clone();
994 let name = name.to_string();
995 move |params, cx| {
996 let this = this.clone();
997 let name = name.to_string();
998 let mut cx = cx.clone();
999 async move {
1000 let actions = params.actions.unwrap_or_default();
1001 let (tx, rx) = smol::channel::bounded(1);
1002 let request = LanguageServerPromptRequest {
1003 level: match params.typ {
1004 lsp::MessageType::ERROR => PromptLevel::Critical,
1005 lsp::MessageType::WARNING => PromptLevel::Warning,
1006 _ => PromptLevel::Info,
1007 },
1008 message: params.message,
1009 actions,
1010 response_channel: tx,
1011 lsp_name: name.clone(),
1012 };
1013
1014 let did_update = this
1015 .update(&mut cx, |_, cx| {
1016 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1017 })
1018 .is_ok();
1019 if did_update {
1020 let response = rx.recv().await.ok();
1021 Ok(response)
1022 } else {
1023 Ok(None)
1024 }
1025 }
1026 }
1027 })
1028 .detach();
1029 language_server
1030 .on_notification::<lsp::notification::ShowMessage, _>({
1031 let this = lsp_store.clone();
1032 let name = name.to_string();
1033 move |params, cx| {
1034 let this = this.clone();
1035 let name = name.to_string();
1036 let mut cx = cx.clone();
1037
1038 let (tx, _) = smol::channel::bounded(1);
1039 let request = LanguageServerPromptRequest {
1040 level: match params.typ {
1041 lsp::MessageType::ERROR => PromptLevel::Critical,
1042 lsp::MessageType::WARNING => PromptLevel::Warning,
1043 _ => PromptLevel::Info,
1044 },
1045 message: params.message,
1046 actions: vec![],
1047 response_channel: tx,
1048 lsp_name: name,
1049 };
1050
1051 let _ = this.update(&mut cx, |_, cx| {
1052 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1053 });
1054 }
1055 })
1056 .detach();
1057
1058 let disk_based_diagnostics_progress_token =
1059 adapter.disk_based_diagnostics_progress_token.clone();
1060
1061 language_server
1062 .on_notification::<lsp::notification::Progress, _>({
1063 let this = lsp_store.clone();
1064 move |params, cx| {
1065 if let Some(this) = this.upgrade() {
1066 this.update(cx, |this, cx| {
1067 this.on_lsp_progress(
1068 params,
1069 server_id,
1070 disk_based_diagnostics_progress_token.clone(),
1071 cx,
1072 );
1073 })
1074 .ok();
1075 }
1076 }
1077 })
1078 .detach();
1079
1080 language_server
1081 .on_notification::<lsp::notification::LogMessage, _>({
1082 let this = lsp_store.clone();
1083 move |params, cx| {
1084 if let Some(this) = this.upgrade() {
1085 this.update(cx, |_, cx| {
1086 cx.emit(LspStoreEvent::LanguageServerLog(
1087 server_id,
1088 LanguageServerLogType::Log(params.typ),
1089 params.message,
1090 ));
1091 })
1092 .ok();
1093 }
1094 }
1095 })
1096 .detach();
1097
1098 language_server
1099 .on_notification::<lsp::notification::LogTrace, _>({
1100 let this = lsp_store.clone();
1101 move |params, cx| {
1102 let mut cx = cx.clone();
1103 if let Some(this) = this.upgrade() {
1104 this.update(&mut cx, |_, cx| {
1105 cx.emit(LspStoreEvent::LanguageServerLog(
1106 server_id,
1107 LanguageServerLogType::Trace {
1108 verbose_info: params.verbose,
1109 },
1110 params.message,
1111 ));
1112 })
1113 .ok();
1114 }
1115 }
1116 })
1117 .detach();
1118
1119 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1120 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1121 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1122 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1123 }
1124
1125 fn shutdown_language_servers_on_quit(
1126 &mut self,
1127 _: &mut Context<LspStore>,
1128 ) -> impl Future<Output = ()> + use<> {
1129 let shutdown_futures = self
1130 .language_servers
1131 .drain()
1132 .map(|(_, server_state)| Self::shutdown_server(server_state))
1133 .collect::<Vec<_>>();
1134
1135 async move {
1136 join_all(shutdown_futures).await;
1137 }
1138 }
1139
1140 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1141 match server_state {
1142 LanguageServerState::Running { server, .. } => {
1143 if let Some(shutdown) = server.shutdown() {
1144 shutdown.await;
1145 }
1146 }
1147 LanguageServerState::Starting { startup, .. } => {
1148 if let Some(server) = startup.await
1149 && let Some(shutdown) = server.shutdown()
1150 {
1151 shutdown.await;
1152 }
1153 }
1154 }
1155 Ok(())
1156 }
1157
1158 fn language_servers_for_worktree(
1159 &self,
1160 worktree_id: WorktreeId,
1161 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1162 self.language_server_ids
1163 .iter()
1164 .filter_map(move |(seed, state)| {
1165 if seed.worktree_id != worktree_id {
1166 return None;
1167 }
1168
1169 if let Some(LanguageServerState::Running { server, .. }) =
1170 self.language_servers.get(&state.id)
1171 {
1172 Some(server)
1173 } else {
1174 None
1175 }
1176 })
1177 }
1178
1179 fn language_server_ids_for_project_path(
1180 &self,
1181 project_path: ProjectPath,
1182 language: &Language,
1183 cx: &mut App,
1184 ) -> Vec<LanguageServerId> {
1185 let Some(worktree) = self
1186 .worktree_store
1187 .read(cx)
1188 .worktree_for_id(project_path.worktree_id, cx)
1189 else {
1190 return Vec::new();
1191 };
1192 let delegate: Arc<dyn ManifestDelegate> =
1193 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1194
1195 self.lsp_tree
1196 .get(
1197 project_path,
1198 language.name(),
1199 language.manifest(),
1200 &delegate,
1201 cx,
1202 )
1203 .collect::<Vec<_>>()
1204 }
1205
1206 fn language_server_ids_for_buffer(
1207 &self,
1208 buffer: &Buffer,
1209 cx: &mut App,
1210 ) -> Vec<LanguageServerId> {
1211 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1212 let worktree_id = file.worktree_id(cx);
1213
1214 let path: Arc<RelPath> = file
1215 .path()
1216 .parent()
1217 .map(Arc::from)
1218 .unwrap_or_else(|| file.path().clone());
1219 let worktree_path = ProjectPath { worktree_id, path };
1220 self.language_server_ids_for_project_path(worktree_path, language, cx)
1221 } else {
1222 Vec::new()
1223 }
1224 }
1225
1226 fn language_servers_for_buffer<'a>(
1227 &'a self,
1228 buffer: &'a Buffer,
1229 cx: &'a mut App,
1230 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1231 self.language_server_ids_for_buffer(buffer, cx)
1232 .into_iter()
1233 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1234 LanguageServerState::Running {
1235 adapter, server, ..
1236 } => Some((adapter, server)),
1237 _ => None,
1238 })
1239 }
1240
1241 async fn execute_code_action_kind_locally(
1242 lsp_store: WeakEntity<LspStore>,
1243 mut buffers: Vec<Entity<Buffer>>,
1244 kind: CodeActionKind,
1245 push_to_history: bool,
1246 cx: &mut AsyncApp,
1247 ) -> anyhow::Result<ProjectTransaction> {
1248 // Do not allow multiple concurrent code actions requests for the
1249 // same buffer.
1250 lsp_store.update(cx, |this, cx| {
1251 let this = this.as_local_mut().unwrap();
1252 buffers.retain(|buffer| {
1253 this.buffers_being_formatted
1254 .insert(buffer.read(cx).remote_id())
1255 });
1256 })?;
1257 let _cleanup = defer({
1258 let this = lsp_store.clone();
1259 let mut cx = cx.clone();
1260 let buffers = &buffers;
1261 move || {
1262 this.update(&mut cx, |this, cx| {
1263 let this = this.as_local_mut().unwrap();
1264 for buffer in buffers {
1265 this.buffers_being_formatted
1266 .remove(&buffer.read(cx).remote_id());
1267 }
1268 })
1269 .ok();
1270 }
1271 });
1272 let mut project_transaction = ProjectTransaction::default();
1273
1274 for buffer in &buffers {
1275 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1276 buffer.update(cx, |buffer, cx| {
1277 lsp_store
1278 .as_local()
1279 .unwrap()
1280 .language_servers_for_buffer(buffer, cx)
1281 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1282 .collect::<Vec<_>>()
1283 })
1284 })?;
1285 for (_, language_server) in adapters_and_servers.iter() {
1286 let actions = Self::get_server_code_actions_from_action_kinds(
1287 &lsp_store,
1288 language_server.server_id(),
1289 vec![kind.clone()],
1290 buffer,
1291 cx,
1292 )
1293 .await?;
1294 Self::execute_code_actions_on_server(
1295 &lsp_store,
1296 language_server,
1297 actions,
1298 push_to_history,
1299 &mut project_transaction,
1300 cx,
1301 )
1302 .await?;
1303 }
1304 }
1305 Ok(project_transaction)
1306 }
1307
1308 async fn format_locally(
1309 lsp_store: WeakEntity<LspStore>,
1310 mut buffers: Vec<FormattableBuffer>,
1311 push_to_history: bool,
1312 trigger: FormatTrigger,
1313 logger: zlog::Logger,
1314 cx: &mut AsyncApp,
1315 ) -> anyhow::Result<ProjectTransaction> {
1316 // Do not allow multiple concurrent formatting requests for the
1317 // same buffer.
1318 lsp_store.update(cx, |this, cx| {
1319 let this = this.as_local_mut().unwrap();
1320 buffers.retain(|buffer| {
1321 this.buffers_being_formatted
1322 .insert(buffer.handle.read(cx).remote_id())
1323 });
1324 })?;
1325
1326 let _cleanup = defer({
1327 let this = lsp_store.clone();
1328 let mut cx = cx.clone();
1329 let buffers = &buffers;
1330 move || {
1331 this.update(&mut cx, |this, cx| {
1332 let this = this.as_local_mut().unwrap();
1333 for buffer in buffers {
1334 this.buffers_being_formatted
1335 .remove(&buffer.handle.read(cx).remote_id());
1336 }
1337 })
1338 .ok();
1339 }
1340 });
1341
1342 let mut project_transaction = ProjectTransaction::default();
1343
1344 for buffer in &buffers {
1345 zlog::debug!(
1346 logger =>
1347 "formatting buffer '{:?}'",
1348 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1349 );
1350 // Create an empty transaction to hold all of the formatting edits.
1351 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1352 // ensure no transactions created while formatting are
1353 // grouped with the previous transaction in the history
1354 // based on the transaction group interval
1355 buffer.finalize_last_transaction();
1356 buffer
1357 .start_transaction()
1358 .context("transaction already open")?;
1359 buffer.end_transaction(cx);
1360 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1361 buffer.finalize_last_transaction();
1362 anyhow::Ok(transaction_id)
1363 })??;
1364
1365 let result = Self::format_buffer_locally(
1366 lsp_store.clone(),
1367 buffer,
1368 formatting_transaction_id,
1369 trigger,
1370 logger,
1371 cx,
1372 )
1373 .await;
1374
1375 buffer.handle.update(cx, |buffer, cx| {
1376 let Some(formatting_transaction) =
1377 buffer.get_transaction(formatting_transaction_id).cloned()
1378 else {
1379 zlog::warn!(logger => "no formatting transaction");
1380 return;
1381 };
1382 if formatting_transaction.edit_ids.is_empty() {
1383 zlog::debug!(logger => "no changes made while formatting");
1384 buffer.forget_transaction(formatting_transaction_id);
1385 return;
1386 }
1387 if !push_to_history {
1388 zlog::trace!(logger => "forgetting format transaction");
1389 buffer.forget_transaction(formatting_transaction.id);
1390 }
1391 project_transaction
1392 .0
1393 .insert(cx.entity(), formatting_transaction);
1394 })?;
1395
1396 result?;
1397 }
1398
1399 Ok(project_transaction)
1400 }
1401
1402 async fn format_buffer_locally(
1403 lsp_store: WeakEntity<LspStore>,
1404 buffer: &FormattableBuffer,
1405 formatting_transaction_id: clock::Lamport,
1406 trigger: FormatTrigger,
1407 logger: zlog::Logger,
1408 cx: &mut AsyncApp,
1409 ) -> Result<()> {
1410 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1411 buffer.handle.update(cx, |buffer, cx| {
1412 let adapters_and_servers = lsp_store
1413 .as_local()
1414 .unwrap()
1415 .language_servers_for_buffer(buffer, cx)
1416 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1417 .collect::<Vec<_>>();
1418 let settings =
1419 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1420 .into_owned();
1421 (adapters_and_servers, settings)
1422 })
1423 })?;
1424
1425 /// Apply edits to the buffer that will become part of the formatting transaction.
1426 /// Fails if the buffer has been edited since the start of that transaction.
1427 fn extend_formatting_transaction(
1428 buffer: &FormattableBuffer,
1429 formatting_transaction_id: text::TransactionId,
1430 cx: &mut AsyncApp,
1431 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1432 ) -> anyhow::Result<()> {
1433 buffer.handle.update(cx, |buffer, cx| {
1434 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1435 if last_transaction_id != Some(formatting_transaction_id) {
1436 anyhow::bail!("Buffer edited while formatting. Aborting")
1437 }
1438 buffer.start_transaction();
1439 operation(buffer, cx);
1440 if let Some(transaction_id) = buffer.end_transaction(cx) {
1441 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1442 }
1443 Ok(())
1444 })?
1445 }
1446
1447 // handle whitespace formatting
1448 if settings.remove_trailing_whitespace_on_save {
1449 zlog::trace!(logger => "removing trailing whitespace");
1450 let diff = buffer
1451 .handle
1452 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1453 .await;
1454 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1455 buffer.apply_diff(diff, cx);
1456 })?;
1457 }
1458
1459 if settings.ensure_final_newline_on_save {
1460 zlog::trace!(logger => "ensuring final newline");
1461 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1462 buffer.ensure_final_newline(cx);
1463 })?;
1464 }
1465
1466 // Formatter for `code_actions_on_format` that runs before
1467 // the rest of the formatters
1468 let mut code_actions_on_format_formatters = None;
1469 let should_run_code_actions_on_format = !matches!(
1470 (trigger, &settings.format_on_save),
1471 (FormatTrigger::Save, &FormatOnSave::Off)
1472 );
1473 if should_run_code_actions_on_format {
1474 let have_code_actions_to_run_on_format = settings
1475 .code_actions_on_format
1476 .values()
1477 .any(|enabled| *enabled);
1478 if have_code_actions_to_run_on_format {
1479 zlog::trace!(logger => "going to run code actions on format");
1480 code_actions_on_format_formatters = Some(
1481 settings
1482 .code_actions_on_format
1483 .iter()
1484 .filter_map(|(action, enabled)| enabled.then_some(action))
1485 .cloned()
1486 .map(Formatter::CodeAction)
1487 .collect::<Vec<_>>(),
1488 );
1489 }
1490 }
1491
1492 let formatters = match (trigger, &settings.format_on_save) {
1493 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1494 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1495 settings.formatter.as_ref()
1496 }
1497 };
1498
1499 let formatters = code_actions_on_format_formatters
1500 .iter()
1501 .flatten()
1502 .chain(formatters);
1503
1504 for formatter in formatters {
1505 let formatter = if formatter == &Formatter::Auto {
1506 if settings.prettier.allowed {
1507 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1508 &Formatter::Prettier
1509 } else {
1510 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1511 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1512 }
1513 } else {
1514 formatter
1515 };
1516 match formatter {
1517 Formatter::Auto => unreachable!("Auto resolved above"),
1518 Formatter::Prettier => {
1519 let logger = zlog::scoped!(logger => "prettier");
1520 zlog::trace!(logger => "formatting");
1521 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1522
1523 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1524 lsp_store.prettier_store().unwrap().downgrade()
1525 })?;
1526 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1527 .await
1528 .transpose()?;
1529 let Some(diff) = diff else {
1530 zlog::trace!(logger => "No changes");
1531 continue;
1532 };
1533
1534 extend_formatting_transaction(
1535 buffer,
1536 formatting_transaction_id,
1537 cx,
1538 |buffer, cx| {
1539 buffer.apply_diff(diff, cx);
1540 },
1541 )?;
1542 }
1543 Formatter::External { command, arguments } => {
1544 let logger = zlog::scoped!(logger => "command");
1545 zlog::trace!(logger => "formatting");
1546 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1547
1548 let diff = Self::format_via_external_command(
1549 buffer,
1550 command.as_ref(),
1551 arguments.as_deref(),
1552 cx,
1553 )
1554 .await
1555 .with_context(|| {
1556 format!("Failed to format buffer via external command: {}", command)
1557 })?;
1558 let Some(diff) = diff else {
1559 zlog::trace!(logger => "No changes");
1560 continue;
1561 };
1562
1563 extend_formatting_transaction(
1564 buffer,
1565 formatting_transaction_id,
1566 cx,
1567 |buffer, cx| {
1568 buffer.apply_diff(diff, cx);
1569 },
1570 )?;
1571 }
1572 Formatter::LanguageServer(specifier) => {
1573 let logger = zlog::scoped!(logger => "language-server");
1574 zlog::trace!(logger => "formatting");
1575 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1576
1577 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1578 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1579 continue;
1580 };
1581
1582 let language_server = match specifier {
1583 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1584 adapters_and_servers.iter().find_map(|(adapter, server)| {
1585 if adapter.name.0.as_ref() == name {
1586 Some(server.clone())
1587 } else {
1588 None
1589 }
1590 })
1591 }
1592 settings::LanguageServerFormatterSpecifier::Current => {
1593 adapters_and_servers.first().map(|e| e.1.clone())
1594 }
1595 };
1596
1597 let Some(language_server) = language_server else {
1598 log::debug!(
1599 "No language server found to format buffer '{:?}'. Skipping",
1600 buffer_path_abs.as_path().to_string_lossy()
1601 );
1602 continue;
1603 };
1604
1605 zlog::trace!(
1606 logger =>
1607 "Formatting buffer '{:?}' using language server '{:?}'",
1608 buffer_path_abs.as_path().to_string_lossy(),
1609 language_server.name()
1610 );
1611
1612 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1613 zlog::trace!(logger => "formatting ranges");
1614 Self::format_ranges_via_lsp(
1615 &lsp_store,
1616 &buffer.handle,
1617 ranges,
1618 buffer_path_abs,
1619 &language_server,
1620 &settings,
1621 cx,
1622 )
1623 .await
1624 .context("Failed to format ranges via language server")?
1625 } else {
1626 zlog::trace!(logger => "formatting full");
1627 Self::format_via_lsp(
1628 &lsp_store,
1629 &buffer.handle,
1630 buffer_path_abs,
1631 &language_server,
1632 &settings,
1633 cx,
1634 )
1635 .await
1636 .context("failed to format via language server")?
1637 };
1638
1639 if edits.is_empty() {
1640 zlog::trace!(logger => "No changes");
1641 continue;
1642 }
1643 extend_formatting_transaction(
1644 buffer,
1645 formatting_transaction_id,
1646 cx,
1647 |buffer, cx| {
1648 buffer.edit(edits, None, cx);
1649 },
1650 )?;
1651 }
1652 Formatter::CodeAction(code_action_name) => {
1653 let logger = zlog::scoped!(logger => "code-actions");
1654 zlog::trace!(logger => "formatting");
1655 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1656
1657 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1658 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1659 continue;
1660 };
1661
1662 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1663 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1664
1665 let mut actions_and_servers = Vec::new();
1666
1667 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1668 let actions_result = Self::get_server_code_actions_from_action_kinds(
1669 &lsp_store,
1670 language_server.server_id(),
1671 vec![code_action_kind.clone()],
1672 &buffer.handle,
1673 cx,
1674 )
1675 .await
1676 .with_context(|| {
1677 format!(
1678 "Failed to resolve code action {:?} with language server {}",
1679 code_action_kind,
1680 language_server.name()
1681 )
1682 });
1683 let Ok(actions) = actions_result else {
1684 // note: it may be better to set result to the error and break formatters here
1685 // but for now we try to execute the actions that we can resolve and skip the rest
1686 zlog::error!(
1687 logger =>
1688 "Failed to resolve code action {:?} with language server {}",
1689 code_action_kind,
1690 language_server.name()
1691 );
1692 continue;
1693 };
1694 for action in actions {
1695 actions_and_servers.push((action, index));
1696 }
1697 }
1698
1699 if actions_and_servers.is_empty() {
1700 zlog::warn!(logger => "No code actions were resolved, continuing");
1701 continue;
1702 }
1703
1704 'actions: for (mut action, server_index) in actions_and_servers {
1705 let server = &adapters_and_servers[server_index].1;
1706
1707 let describe_code_action = |action: &CodeAction| {
1708 format!(
1709 "code action '{}' with title \"{}\" on server {}",
1710 action
1711 .lsp_action
1712 .action_kind()
1713 .unwrap_or("unknown".into())
1714 .as_str(),
1715 action.lsp_action.title(),
1716 server.name(),
1717 )
1718 };
1719
1720 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1721
1722 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1723 zlog::error!(
1724 logger =>
1725 "Failed to resolve {}. Error: {}",
1726 describe_code_action(&action),
1727 err
1728 );
1729 continue;
1730 }
1731
1732 if let Some(edit) = action.lsp_action.edit().cloned() {
1733 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1734 // but filters out and logs warnings for code actions that require unreasonably
1735 // difficult handling on our part, such as:
1736 // - applying edits that call commands
1737 // which can result in arbitrary workspace edits being sent from the server that
1738 // have no way of being tied back to the command that initiated them (i.e. we
1739 // can't know which edits are part of the format request, or if the server is done sending
1740 // actions in response to the command)
1741 // - actions that create/delete/modify/rename files other than the one we are formatting
1742 // as we then would need to handle such changes correctly in the local history as well
1743 // as the remote history through the ProjectTransaction
1744 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1745 // Supporting these actions is not impossible, but not supported as of yet.
1746 if edit.changes.is_none() && edit.document_changes.is_none() {
1747 zlog::trace!(
1748 logger =>
1749 "No changes for code action. Skipping {}",
1750 describe_code_action(&action),
1751 );
1752 continue;
1753 }
1754
1755 let mut operations = Vec::new();
1756 if let Some(document_changes) = edit.document_changes {
1757 match document_changes {
1758 lsp::DocumentChanges::Edits(edits) => operations.extend(
1759 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1760 ),
1761 lsp::DocumentChanges::Operations(ops) => operations = ops,
1762 }
1763 } else if let Some(changes) = edit.changes {
1764 operations.extend(changes.into_iter().map(|(uri, edits)| {
1765 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1766 text_document:
1767 lsp::OptionalVersionedTextDocumentIdentifier {
1768 uri,
1769 version: None,
1770 },
1771 edits: edits.into_iter().map(Edit::Plain).collect(),
1772 })
1773 }));
1774 }
1775
1776 let mut edits = Vec::with_capacity(operations.len());
1777
1778 if operations.is_empty() {
1779 zlog::trace!(
1780 logger =>
1781 "No changes for code action. Skipping {}",
1782 describe_code_action(&action),
1783 );
1784 continue;
1785 }
1786 for operation in operations {
1787 let op = match operation {
1788 lsp::DocumentChangeOperation::Edit(op) => op,
1789 lsp::DocumentChangeOperation::Op(_) => {
1790 zlog::warn!(
1791 logger =>
1792 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1793 describe_code_action(&action),
1794 );
1795 continue 'actions;
1796 }
1797 };
1798 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1799 zlog::warn!(
1800 logger =>
1801 "Failed to convert URI '{:?}' to file path. Skipping {}",
1802 &op.text_document.uri,
1803 describe_code_action(&action),
1804 );
1805 continue 'actions;
1806 };
1807 if &file_path != buffer_path_abs {
1808 zlog::warn!(
1809 logger =>
1810 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1811 file_path,
1812 buffer_path_abs,
1813 describe_code_action(&action),
1814 );
1815 continue 'actions;
1816 }
1817
1818 let mut lsp_edits = Vec::new();
1819 for edit in op.edits {
1820 match edit {
1821 Edit::Plain(edit) => {
1822 if !lsp_edits.contains(&edit) {
1823 lsp_edits.push(edit);
1824 }
1825 }
1826 Edit::Annotated(edit) => {
1827 if !lsp_edits.contains(&edit.text_edit) {
1828 lsp_edits.push(edit.text_edit);
1829 }
1830 }
1831 Edit::Snippet(_) => {
1832 zlog::warn!(
1833 logger =>
1834 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1835 describe_code_action(&action),
1836 );
1837 continue 'actions;
1838 }
1839 }
1840 }
1841 let edits_result = lsp_store
1842 .update(cx, |lsp_store, cx| {
1843 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1844 &buffer.handle,
1845 lsp_edits,
1846 server.server_id(),
1847 op.text_document.version,
1848 cx,
1849 )
1850 })?
1851 .await;
1852 let Ok(resolved_edits) = edits_result else {
1853 zlog::warn!(
1854 logger =>
1855 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1856 buffer_path_abs.as_path(),
1857 describe_code_action(&action),
1858 );
1859 continue 'actions;
1860 };
1861 edits.extend(resolved_edits);
1862 }
1863
1864 if edits.is_empty() {
1865 zlog::warn!(logger => "No edits resolved from LSP");
1866 continue;
1867 }
1868
1869 extend_formatting_transaction(
1870 buffer,
1871 formatting_transaction_id,
1872 cx,
1873 |buffer, cx| {
1874 zlog::info!(
1875 "Applying edits {edits:?}. Content: {:?}",
1876 buffer.text()
1877 );
1878 buffer.edit(edits, None, cx);
1879 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1880 },
1881 )?;
1882 }
1883
1884 if let Some(command) = action.lsp_action.command() {
1885 zlog::warn!(
1886 logger =>
1887 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1888 &command.command,
1889 );
1890
1891 // bail early if command is invalid
1892 let server_capabilities = server.capabilities();
1893 let available_commands = server_capabilities
1894 .execute_command_provider
1895 .as_ref()
1896 .map(|options| options.commands.as_slice())
1897 .unwrap_or_default();
1898 if !available_commands.contains(&command.command) {
1899 zlog::warn!(
1900 logger =>
1901 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1902 command.command,
1903 server.name(),
1904 );
1905 continue;
1906 }
1907
1908 // noop so we just ensure buffer hasn't been edited since resolving code actions
1909 extend_formatting_transaction(
1910 buffer,
1911 formatting_transaction_id,
1912 cx,
1913 |_, _| {},
1914 )?;
1915 zlog::info!(logger => "Executing command {}", &command.command);
1916
1917 lsp_store.update(cx, |this, _| {
1918 this.as_local_mut()
1919 .unwrap()
1920 .last_workspace_edits_by_language_server
1921 .remove(&server.server_id());
1922 })?;
1923
1924 let execute_command_result = server
1925 .request::<lsp::request::ExecuteCommand>(
1926 lsp::ExecuteCommandParams {
1927 command: command.command.clone(),
1928 arguments: command.arguments.clone().unwrap_or_default(),
1929 ..Default::default()
1930 },
1931 )
1932 .await
1933 .into_response();
1934
1935 if execute_command_result.is_err() {
1936 zlog::error!(
1937 logger =>
1938 "Failed to execute command '{}' as part of {}",
1939 &command.command,
1940 describe_code_action(&action),
1941 );
1942 continue 'actions;
1943 }
1944
1945 let mut project_transaction_command =
1946 lsp_store.update(cx, |this, _| {
1947 this.as_local_mut()
1948 .unwrap()
1949 .last_workspace_edits_by_language_server
1950 .remove(&server.server_id())
1951 .unwrap_or_default()
1952 })?;
1953
1954 if let Some(transaction) =
1955 project_transaction_command.0.remove(&buffer.handle)
1956 {
1957 zlog::trace!(
1958 logger =>
1959 "Successfully captured {} edits that resulted from command {}",
1960 transaction.edit_ids.len(),
1961 &command.command,
1962 );
1963 let transaction_id_project_transaction = transaction.id;
1964 buffer.handle.update(cx, |buffer, _| {
1965 // it may have been removed from history if push_to_history was
1966 // false in deserialize_workspace_edit. If so push it so we
1967 // can merge it with the format transaction
1968 // and pop the combined transaction off the history stack
1969 // later if push_to_history is false
1970 if buffer.get_transaction(transaction.id).is_none() {
1971 buffer.push_transaction(transaction, Instant::now());
1972 }
1973 buffer.merge_transactions(
1974 transaction_id_project_transaction,
1975 formatting_transaction_id,
1976 );
1977 })?;
1978 }
1979
1980 if !project_transaction_command.0.is_empty() {
1981 let mut extra_buffers = String::new();
1982 for buffer in project_transaction_command.0.keys() {
1983 buffer
1984 .read_with(cx, |b, cx| {
1985 if let Some(path) = b.project_path(cx) {
1986 if !extra_buffers.is_empty() {
1987 extra_buffers.push_str(", ");
1988 }
1989 extra_buffers.push_str(path.path.as_unix_str());
1990 }
1991 })
1992 .ok();
1993 }
1994 zlog::warn!(
1995 logger =>
1996 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1997 &command.command,
1998 extra_buffers,
1999 );
2000 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2001 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2002 // add it so it's included, and merge it into the format transaction when its created later
2003 }
2004 }
2005 }
2006 }
2007 }
2008 }
2009
2010 Ok(())
2011 }
2012
2013 pub async fn format_ranges_via_lsp(
2014 this: &WeakEntity<LspStore>,
2015 buffer_handle: &Entity<Buffer>,
2016 ranges: &[Range<Anchor>],
2017 abs_path: &Path,
2018 language_server: &Arc<LanguageServer>,
2019 settings: &LanguageSettings,
2020 cx: &mut AsyncApp,
2021 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2022 let capabilities = &language_server.capabilities();
2023 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2024 if range_formatting_provider == Some(&OneOf::Left(false)) {
2025 anyhow::bail!(
2026 "{} language server does not support range formatting",
2027 language_server.name()
2028 );
2029 }
2030
2031 let uri = file_path_to_lsp_url(abs_path)?;
2032 let text_document = lsp::TextDocumentIdentifier::new(uri);
2033
2034 let lsp_edits = {
2035 let mut lsp_ranges = Vec::new();
2036 this.update(cx, |_this, cx| {
2037 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2038 // not have been sent to the language server. This seems like a fairly systemic
2039 // issue, though, the resolution probably is not specific to formatting.
2040 //
2041 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2042 // LSP.
2043 let snapshot = buffer_handle.read(cx).snapshot();
2044 for range in ranges {
2045 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2046 }
2047 anyhow::Ok(())
2048 })??;
2049
2050 let mut edits = None;
2051 for range in lsp_ranges {
2052 if let Some(mut edit) = language_server
2053 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2054 text_document: text_document.clone(),
2055 range,
2056 options: lsp_command::lsp_formatting_options(settings),
2057 work_done_progress_params: Default::default(),
2058 })
2059 .await
2060 .into_response()?
2061 {
2062 edits.get_or_insert_with(Vec::new).append(&mut edit);
2063 }
2064 }
2065 edits
2066 };
2067
2068 if let Some(lsp_edits) = lsp_edits {
2069 this.update(cx, |this, cx| {
2070 this.as_local_mut().unwrap().edits_from_lsp(
2071 buffer_handle,
2072 lsp_edits,
2073 language_server.server_id(),
2074 None,
2075 cx,
2076 )
2077 })?
2078 .await
2079 } else {
2080 Ok(Vec::with_capacity(0))
2081 }
2082 }
2083
2084 async fn format_via_lsp(
2085 this: &WeakEntity<LspStore>,
2086 buffer: &Entity<Buffer>,
2087 abs_path: &Path,
2088 language_server: &Arc<LanguageServer>,
2089 settings: &LanguageSettings,
2090 cx: &mut AsyncApp,
2091 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2092 let logger = zlog::scoped!("lsp_format");
2093 zlog::debug!(logger => "Formatting via LSP");
2094
2095 let uri = file_path_to_lsp_url(abs_path)?;
2096 let text_document = lsp::TextDocumentIdentifier::new(uri);
2097 let capabilities = &language_server.capabilities();
2098
2099 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2100 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2101
2102 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2103 let _timer = zlog::time!(logger => "format-full");
2104 language_server
2105 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2106 text_document,
2107 options: lsp_command::lsp_formatting_options(settings),
2108 work_done_progress_params: Default::default(),
2109 })
2110 .await
2111 .into_response()?
2112 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2113 let _timer = zlog::time!(logger => "format-range");
2114 let buffer_start = lsp::Position::new(0, 0);
2115 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2116 language_server
2117 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2118 text_document: text_document.clone(),
2119 range: lsp::Range::new(buffer_start, buffer_end),
2120 options: lsp_command::lsp_formatting_options(settings),
2121 work_done_progress_params: Default::default(),
2122 })
2123 .await
2124 .into_response()?
2125 } else {
2126 None
2127 };
2128
2129 if let Some(lsp_edits) = lsp_edits {
2130 this.update(cx, |this, cx| {
2131 this.as_local_mut().unwrap().edits_from_lsp(
2132 buffer,
2133 lsp_edits,
2134 language_server.server_id(),
2135 None,
2136 cx,
2137 )
2138 })?
2139 .await
2140 } else {
2141 Ok(Vec::with_capacity(0))
2142 }
2143 }
2144
2145 async fn format_via_external_command(
2146 buffer: &FormattableBuffer,
2147 command: &str,
2148 arguments: Option<&[String]>,
2149 cx: &mut AsyncApp,
2150 ) -> Result<Option<Diff>> {
2151 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2152 let file = File::from_dyn(buffer.file())?;
2153 let worktree = file.worktree.read(cx);
2154 let mut worktree_path = worktree.abs_path().to_path_buf();
2155 if worktree.root_entry()?.is_file() {
2156 worktree_path.pop();
2157 }
2158 Some(worktree_path)
2159 })?;
2160
2161 let mut child = util::command::new_smol_command(command);
2162
2163 if let Some(buffer_env) = buffer.env.as_ref() {
2164 child.envs(buffer_env);
2165 }
2166
2167 if let Some(working_dir_path) = working_dir_path {
2168 child.current_dir(working_dir_path);
2169 }
2170
2171 if let Some(arguments) = arguments {
2172 child.args(arguments.iter().map(|arg| {
2173 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2174 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2175 } else {
2176 arg.replace("{buffer_path}", "Untitled")
2177 }
2178 }));
2179 }
2180
2181 let mut child = child
2182 .stdin(smol::process::Stdio::piped())
2183 .stdout(smol::process::Stdio::piped())
2184 .stderr(smol::process::Stdio::piped())
2185 .spawn()?;
2186
2187 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2188 let text = buffer
2189 .handle
2190 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2191 for chunk in text.chunks() {
2192 stdin.write_all(chunk.as_bytes()).await?;
2193 }
2194 stdin.flush().await?;
2195
2196 let output = child.output().await?;
2197 anyhow::ensure!(
2198 output.status.success(),
2199 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2200 output.status.code(),
2201 String::from_utf8_lossy(&output.stdout),
2202 String::from_utf8_lossy(&output.stderr),
2203 );
2204
2205 let stdout = String::from_utf8(output.stdout)?;
2206 Ok(Some(
2207 buffer
2208 .handle
2209 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2210 .await,
2211 ))
2212 }
2213
2214 async fn try_resolve_code_action(
2215 lang_server: &LanguageServer,
2216 action: &mut CodeAction,
2217 ) -> anyhow::Result<()> {
2218 match &mut action.lsp_action {
2219 LspAction::Action(lsp_action) => {
2220 if !action.resolved
2221 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2222 && lsp_action.data.is_some()
2223 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2224 {
2225 *lsp_action = Box::new(
2226 lang_server
2227 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2228 .await
2229 .into_response()?,
2230 );
2231 }
2232 }
2233 LspAction::CodeLens(lens) => {
2234 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2235 *lens = lang_server
2236 .request::<lsp::request::CodeLensResolve>(lens.clone())
2237 .await
2238 .into_response()?;
2239 }
2240 }
2241 LspAction::Command(_) => {}
2242 }
2243
2244 action.resolved = true;
2245 anyhow::Ok(())
2246 }
2247
2248 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2249 let buffer = buffer_handle.read(cx);
2250
2251 let file = buffer.file().cloned();
2252
2253 let Some(file) = File::from_dyn(file.as_ref()) else {
2254 return;
2255 };
2256 if !file.is_local() {
2257 return;
2258 }
2259 let path = ProjectPath::from_file(file, cx);
2260 let worktree_id = file.worktree_id(cx);
2261 let language = buffer.language().cloned();
2262
2263 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2264 for (server_id, diagnostics) in
2265 diagnostics.get(file.path()).cloned().unwrap_or_default()
2266 {
2267 self.update_buffer_diagnostics(
2268 buffer_handle,
2269 server_id,
2270 None,
2271 None,
2272 None,
2273 Vec::new(),
2274 diagnostics,
2275 cx,
2276 )
2277 .log_err();
2278 }
2279 }
2280 let Some(language) = language else {
2281 return;
2282 };
2283 let Some(snapshot) = self
2284 .worktree_store
2285 .read(cx)
2286 .worktree_for_id(worktree_id, cx)
2287 .map(|worktree| worktree.read(cx).snapshot())
2288 else {
2289 return;
2290 };
2291 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2292
2293 for server_id in
2294 self.lsp_tree
2295 .get(path, language.name(), language.manifest(), &delegate, cx)
2296 {
2297 let server = self
2298 .language_servers
2299 .get(&server_id)
2300 .and_then(|server_state| {
2301 if let LanguageServerState::Running { server, .. } = server_state {
2302 Some(server.clone())
2303 } else {
2304 None
2305 }
2306 });
2307 let server = match server {
2308 Some(server) => server,
2309 None => continue,
2310 };
2311
2312 buffer_handle.update(cx, |buffer, cx| {
2313 buffer.set_completion_triggers(
2314 server.server_id(),
2315 server
2316 .capabilities()
2317 .completion_provider
2318 .as_ref()
2319 .and_then(|provider| {
2320 provider
2321 .trigger_characters
2322 .as_ref()
2323 .map(|characters| characters.iter().cloned().collect())
2324 })
2325 .unwrap_or_default(),
2326 cx,
2327 );
2328 });
2329 }
2330 }
2331
2332 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2333 buffer.update(cx, |buffer, cx| {
2334 let Some(language) = buffer.language() else {
2335 return;
2336 };
2337 let path = ProjectPath {
2338 worktree_id: old_file.worktree_id(cx),
2339 path: old_file.path.clone(),
2340 };
2341 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2342 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2343 buffer.set_completion_triggers(server_id, Default::default(), cx);
2344 }
2345 });
2346 }
2347
2348 fn update_buffer_diagnostics(
2349 &mut self,
2350 buffer: &Entity<Buffer>,
2351 server_id: LanguageServerId,
2352 registration_id: Option<Option<SharedString>>,
2353 result_id: Option<SharedString>,
2354 version: Option<i32>,
2355 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2356 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2357 cx: &mut Context<LspStore>,
2358 ) -> Result<()> {
2359 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2360 Ordering::Equal
2361 .then_with(|| b.is_primary.cmp(&a.is_primary))
2362 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2363 .then_with(|| a.severity.cmp(&b.severity))
2364 .then_with(|| a.message.cmp(&b.message))
2365 }
2366
2367 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2368 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2369 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2370
2371 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2372 Ordering::Equal
2373 .then_with(|| a.range.start.cmp(&b.range.start))
2374 .then_with(|| b.range.end.cmp(&a.range.end))
2375 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2376 });
2377
2378 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2379
2380 let edits_since_save = std::cell::LazyCell::new(|| {
2381 let saved_version = buffer.read(cx).saved_version();
2382 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2383 });
2384
2385 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2386
2387 for (new_diagnostic, entry) in diagnostics {
2388 let start;
2389 let end;
2390 if new_diagnostic && entry.diagnostic.is_disk_based {
2391 // Some diagnostics are based on files on disk instead of buffers'
2392 // current contents. Adjust these diagnostics' ranges to reflect
2393 // any unsaved edits.
2394 // Do not alter the reused ones though, as their coordinates were stored as anchors
2395 // and were properly adjusted on reuse.
2396 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2397 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2398 } else {
2399 start = entry.range.start;
2400 end = entry.range.end;
2401 }
2402
2403 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2404 ..snapshot.clip_point_utf16(end, Bias::Right);
2405
2406 // Expand empty ranges by one codepoint
2407 if range.start == range.end {
2408 // This will be go to the next boundary when being clipped
2409 range.end.column += 1;
2410 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2411 if range.start == range.end && range.end.column > 0 {
2412 range.start.column -= 1;
2413 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2414 }
2415 }
2416
2417 sanitized_diagnostics.push(DiagnosticEntry {
2418 range,
2419 diagnostic: entry.diagnostic,
2420 });
2421 }
2422 drop(edits_since_save);
2423
2424 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2425 buffer.update(cx, |buffer, cx| {
2426 if let Some(registration_id) = registration_id {
2427 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2428 self.buffer_pull_diagnostics_result_ids
2429 .entry(server_id)
2430 .or_default()
2431 .entry(registration_id)
2432 .or_default()
2433 .insert(abs_path, result_id);
2434 }
2435 }
2436
2437 buffer.update_diagnostics(server_id, set, cx)
2438 });
2439
2440 Ok(())
2441 }
2442
2443 fn register_language_server_for_invisible_worktree(
2444 &mut self,
2445 worktree: &Entity<Worktree>,
2446 language_server_id: LanguageServerId,
2447 cx: &mut App,
2448 ) {
2449 let worktree = worktree.read(cx);
2450 let worktree_id = worktree.id();
2451 debug_assert!(!worktree.is_visible());
2452 let Some(mut origin_seed) = self
2453 .language_server_ids
2454 .iter()
2455 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2456 else {
2457 return;
2458 };
2459 origin_seed.worktree_id = worktree_id;
2460 self.language_server_ids
2461 .entry(origin_seed)
2462 .or_insert_with(|| UnifiedLanguageServer {
2463 id: language_server_id,
2464 project_roots: Default::default(),
2465 });
2466 }
2467
2468 fn register_buffer_with_language_servers(
2469 &mut self,
2470 buffer_handle: &Entity<Buffer>,
2471 only_register_servers: HashSet<LanguageServerSelector>,
2472 cx: &mut Context<LspStore>,
2473 ) {
2474 let buffer = buffer_handle.read(cx);
2475 let buffer_id = buffer.remote_id();
2476
2477 let Some(file) = File::from_dyn(buffer.file()) else {
2478 return;
2479 };
2480 if !file.is_local() {
2481 return;
2482 }
2483
2484 let abs_path = file.abs_path(cx);
2485 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2486 return;
2487 };
2488 let initial_snapshot = buffer.text_snapshot();
2489 let worktree_id = file.worktree_id(cx);
2490
2491 let Some(language) = buffer.language().cloned() else {
2492 return;
2493 };
2494 let path: Arc<RelPath> = file
2495 .path()
2496 .parent()
2497 .map(Arc::from)
2498 .unwrap_or_else(|| file.path().clone());
2499 let Some(worktree) = self
2500 .worktree_store
2501 .read(cx)
2502 .worktree_for_id(worktree_id, cx)
2503 else {
2504 return;
2505 };
2506 let language_name = language.name();
2507 let (reused, delegate, servers) = self
2508 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2509 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2510 .unwrap_or_else(|| {
2511 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2512 let delegate: Arc<dyn ManifestDelegate> =
2513 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2514
2515 let servers = self
2516 .lsp_tree
2517 .walk(
2518 ProjectPath { worktree_id, path },
2519 language.name(),
2520 language.manifest(),
2521 &delegate,
2522 cx,
2523 )
2524 .collect::<Vec<_>>();
2525 (false, lsp_delegate, servers)
2526 });
2527 let servers_and_adapters = servers
2528 .into_iter()
2529 .filter_map(|server_node| {
2530 if reused && server_node.server_id().is_none() {
2531 return None;
2532 }
2533 if !only_register_servers.is_empty() {
2534 if let Some(server_id) = server_node.server_id()
2535 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2536 {
2537 return None;
2538 }
2539 if let Some(name) = server_node.name()
2540 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2541 {
2542 return None;
2543 }
2544 }
2545
2546 let server_id = server_node.server_id_or_init(|disposition| {
2547 let path = &disposition.path;
2548
2549 {
2550 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2551
2552 let server_id = self.get_or_insert_language_server(
2553 &worktree,
2554 delegate.clone(),
2555 disposition,
2556 &language_name,
2557 cx,
2558 );
2559
2560 if let Some(state) = self.language_servers.get(&server_id)
2561 && let Ok(uri) = uri
2562 {
2563 state.add_workspace_folder(uri);
2564 };
2565 server_id
2566 }
2567 })?;
2568 let server_state = self.language_servers.get(&server_id)?;
2569 if let LanguageServerState::Running {
2570 server, adapter, ..
2571 } = server_state
2572 {
2573 Some((server.clone(), adapter.clone()))
2574 } else {
2575 None
2576 }
2577 })
2578 .collect::<Vec<_>>();
2579 for (server, adapter) in servers_and_adapters {
2580 buffer_handle.update(cx, |buffer, cx| {
2581 buffer.set_completion_triggers(
2582 server.server_id(),
2583 server
2584 .capabilities()
2585 .completion_provider
2586 .as_ref()
2587 .and_then(|provider| {
2588 provider
2589 .trigger_characters
2590 .as_ref()
2591 .map(|characters| characters.iter().cloned().collect())
2592 })
2593 .unwrap_or_default(),
2594 cx,
2595 );
2596 });
2597
2598 let snapshot = LspBufferSnapshot {
2599 version: 0,
2600 snapshot: initial_snapshot.clone(),
2601 };
2602
2603 let mut registered = false;
2604 self.buffer_snapshots
2605 .entry(buffer_id)
2606 .or_default()
2607 .entry(server.server_id())
2608 .or_insert_with(|| {
2609 registered = true;
2610 server.register_buffer(
2611 uri.clone(),
2612 adapter.language_id(&language.name()),
2613 0,
2614 initial_snapshot.text(),
2615 );
2616
2617 vec![snapshot]
2618 });
2619
2620 self.buffers_opened_in_servers
2621 .entry(buffer_id)
2622 .or_default()
2623 .insert(server.server_id());
2624 if registered {
2625 cx.emit(LspStoreEvent::LanguageServerUpdate {
2626 language_server_id: server.server_id(),
2627 name: None,
2628 message: proto::update_language_server::Variant::RegisteredForBuffer(
2629 proto::RegisteredForBuffer {
2630 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2631 buffer_id: buffer_id.to_proto(),
2632 },
2633 ),
2634 });
2635 }
2636 }
2637 }
2638
2639 fn reuse_existing_language_server<'lang_name>(
2640 &self,
2641 server_tree: &LanguageServerTree,
2642 worktree: &Entity<Worktree>,
2643 language_name: &'lang_name LanguageName,
2644 cx: &mut App,
2645 ) -> Option<(
2646 Arc<LocalLspAdapterDelegate>,
2647 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2648 )> {
2649 if worktree.read(cx).is_visible() {
2650 return None;
2651 }
2652
2653 let worktree_store = self.worktree_store.read(cx);
2654 let servers = server_tree
2655 .instances
2656 .iter()
2657 .filter(|(worktree_id, _)| {
2658 worktree_store
2659 .worktree_for_id(**worktree_id, cx)
2660 .is_some_and(|worktree| worktree.read(cx).is_visible())
2661 })
2662 .flat_map(|(worktree_id, servers)| {
2663 servers
2664 .roots
2665 .iter()
2666 .flat_map(|(_, language_servers)| language_servers)
2667 .map(move |(_, (server_node, server_languages))| {
2668 (worktree_id, server_node, server_languages)
2669 })
2670 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2671 .map(|(worktree_id, server_node, _)| {
2672 (
2673 *worktree_id,
2674 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2675 )
2676 })
2677 })
2678 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2679 acc.entry(worktree_id)
2680 .or_insert_with(Vec::new)
2681 .push(server_node);
2682 acc
2683 })
2684 .into_values()
2685 .max_by_key(|servers| servers.len())?;
2686
2687 let worktree_id = worktree.read(cx).id();
2688 let apply = move |tree: &mut LanguageServerTree| {
2689 for server_node in &servers {
2690 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2691 }
2692 servers
2693 };
2694
2695 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2696 Some((delegate, apply))
2697 }
2698
2699 pub(crate) fn unregister_old_buffer_from_language_servers(
2700 &mut self,
2701 buffer: &Entity<Buffer>,
2702 old_file: &File,
2703 cx: &mut App,
2704 ) {
2705 let old_path = match old_file.as_local() {
2706 Some(local) => local.abs_path(cx),
2707 None => return,
2708 };
2709
2710 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2711 debug_panic!("{old_path:?} is not parseable as an URI");
2712 return;
2713 };
2714 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2715 }
2716
2717 pub(crate) fn unregister_buffer_from_language_servers(
2718 &mut self,
2719 buffer: &Entity<Buffer>,
2720 file_url: &lsp::Uri,
2721 cx: &mut App,
2722 ) {
2723 buffer.update(cx, |buffer, cx| {
2724 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2725
2726 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2727 if snapshots
2728 .as_mut()
2729 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2730 {
2731 language_server.unregister_buffer(file_url.clone());
2732 }
2733 }
2734 });
2735 }
2736
2737 fn buffer_snapshot_for_lsp_version(
2738 &mut self,
2739 buffer: &Entity<Buffer>,
2740 server_id: LanguageServerId,
2741 version: Option<i32>,
2742 cx: &App,
2743 ) -> Result<TextBufferSnapshot> {
2744 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2745
2746 if let Some(version) = version {
2747 let buffer_id = buffer.read(cx).remote_id();
2748 let snapshots = if let Some(snapshots) = self
2749 .buffer_snapshots
2750 .get_mut(&buffer_id)
2751 .and_then(|m| m.get_mut(&server_id))
2752 {
2753 snapshots
2754 } else if version == 0 {
2755 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2756 // We detect this case and treat it as if the version was `None`.
2757 return Ok(buffer.read(cx).text_snapshot());
2758 } else {
2759 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2760 };
2761
2762 let found_snapshot = snapshots
2763 .binary_search_by_key(&version, |e| e.version)
2764 .map(|ix| snapshots[ix].snapshot.clone())
2765 .map_err(|_| {
2766 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2767 })?;
2768
2769 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2770 Ok(found_snapshot)
2771 } else {
2772 Ok((buffer.read(cx)).text_snapshot())
2773 }
2774 }
2775
2776 async fn get_server_code_actions_from_action_kinds(
2777 lsp_store: &WeakEntity<LspStore>,
2778 language_server_id: LanguageServerId,
2779 code_action_kinds: Vec<lsp::CodeActionKind>,
2780 buffer: &Entity<Buffer>,
2781 cx: &mut AsyncApp,
2782 ) -> Result<Vec<CodeAction>> {
2783 let actions = lsp_store
2784 .update(cx, move |this, cx| {
2785 let request = GetCodeActions {
2786 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2787 kinds: Some(code_action_kinds),
2788 };
2789 let server = LanguageServerToQuery::Other(language_server_id);
2790 this.request_lsp(buffer.clone(), server, request, cx)
2791 })?
2792 .await?;
2793 Ok(actions)
2794 }
2795
2796 pub async fn execute_code_actions_on_server(
2797 lsp_store: &WeakEntity<LspStore>,
2798 language_server: &Arc<LanguageServer>,
2799
2800 actions: Vec<CodeAction>,
2801 push_to_history: bool,
2802 project_transaction: &mut ProjectTransaction,
2803 cx: &mut AsyncApp,
2804 ) -> anyhow::Result<()> {
2805 for mut action in actions {
2806 Self::try_resolve_code_action(language_server, &mut action)
2807 .await
2808 .context("resolving a formatting code action")?;
2809
2810 if let Some(edit) = action.lsp_action.edit() {
2811 if edit.changes.is_none() && edit.document_changes.is_none() {
2812 continue;
2813 }
2814
2815 let new = Self::deserialize_workspace_edit(
2816 lsp_store.upgrade().context("project dropped")?,
2817 edit.clone(),
2818 push_to_history,
2819 language_server.clone(),
2820 cx,
2821 )
2822 .await?;
2823 project_transaction.0.extend(new.0);
2824 }
2825
2826 if let Some(command) = action.lsp_action.command() {
2827 let server_capabilities = language_server.capabilities();
2828 let available_commands = server_capabilities
2829 .execute_command_provider
2830 .as_ref()
2831 .map(|options| options.commands.as_slice())
2832 .unwrap_or_default();
2833 if available_commands.contains(&command.command) {
2834 lsp_store.update(cx, |lsp_store, _| {
2835 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2836 mode.last_workspace_edits_by_language_server
2837 .remove(&language_server.server_id());
2838 }
2839 })?;
2840
2841 language_server
2842 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2843 command: command.command.clone(),
2844 arguments: command.arguments.clone().unwrap_or_default(),
2845 ..Default::default()
2846 })
2847 .await
2848 .into_response()
2849 .context("execute command")?;
2850
2851 lsp_store.update(cx, |this, _| {
2852 if let LspStoreMode::Local(mode) = &mut this.mode {
2853 project_transaction.0.extend(
2854 mode.last_workspace_edits_by_language_server
2855 .remove(&language_server.server_id())
2856 .unwrap_or_default()
2857 .0,
2858 )
2859 }
2860 })?;
2861 } else {
2862 log::warn!(
2863 "Cannot execute a command {} not listed in the language server capabilities",
2864 command.command
2865 )
2866 }
2867 }
2868 }
2869 Ok(())
2870 }
2871
2872 pub async fn deserialize_text_edits(
2873 this: Entity<LspStore>,
2874 buffer_to_edit: Entity<Buffer>,
2875 edits: Vec<lsp::TextEdit>,
2876 push_to_history: bool,
2877 _: Arc<CachedLspAdapter>,
2878 language_server: Arc<LanguageServer>,
2879 cx: &mut AsyncApp,
2880 ) -> Result<Option<Transaction>> {
2881 let edits = this
2882 .update(cx, |this, cx| {
2883 this.as_local_mut().unwrap().edits_from_lsp(
2884 &buffer_to_edit,
2885 edits,
2886 language_server.server_id(),
2887 None,
2888 cx,
2889 )
2890 })?
2891 .await?;
2892
2893 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2894 buffer.finalize_last_transaction();
2895 buffer.start_transaction();
2896 for (range, text) in edits {
2897 buffer.edit([(range, text)], None, cx);
2898 }
2899
2900 if buffer.end_transaction(cx).is_some() {
2901 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2902 if !push_to_history {
2903 buffer.forget_transaction(transaction.id);
2904 }
2905 Some(transaction)
2906 } else {
2907 None
2908 }
2909 })?;
2910
2911 Ok(transaction)
2912 }
2913
2914 #[allow(clippy::type_complexity)]
2915 pub(crate) fn edits_from_lsp(
2916 &mut self,
2917 buffer: &Entity<Buffer>,
2918 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2919 server_id: LanguageServerId,
2920 version: Option<i32>,
2921 cx: &mut Context<LspStore>,
2922 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2923 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2924 cx.background_spawn(async move {
2925 let snapshot = snapshot?;
2926 let mut lsp_edits = lsp_edits
2927 .into_iter()
2928 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2929 .collect::<Vec<_>>();
2930
2931 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2932
2933 let mut lsp_edits = lsp_edits.into_iter().peekable();
2934 let mut edits = Vec::new();
2935 while let Some((range, mut new_text)) = lsp_edits.next() {
2936 // Clip invalid ranges provided by the language server.
2937 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2938 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2939
2940 // Combine any LSP edits that are adjacent.
2941 //
2942 // Also, combine LSP edits that are separated from each other by only
2943 // a newline. This is important because for some code actions,
2944 // Rust-analyzer rewrites the entire buffer via a series of edits that
2945 // are separated by unchanged newline characters.
2946 //
2947 // In order for the diffing logic below to work properly, any edits that
2948 // cancel each other out must be combined into one.
2949 while let Some((next_range, next_text)) = lsp_edits.peek() {
2950 if next_range.start.0 > range.end {
2951 if next_range.start.0.row > range.end.row + 1
2952 || next_range.start.0.column > 0
2953 || snapshot.clip_point_utf16(
2954 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2955 Bias::Left,
2956 ) > range.end
2957 {
2958 break;
2959 }
2960 new_text.push('\n');
2961 }
2962 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2963 new_text.push_str(next_text);
2964 lsp_edits.next();
2965 }
2966
2967 // For multiline edits, perform a diff of the old and new text so that
2968 // we can identify the changes more precisely, preserving the locations
2969 // of any anchors positioned in the unchanged regions.
2970 if range.end.row > range.start.row {
2971 let offset = range.start.to_offset(&snapshot);
2972 let old_text = snapshot.text_for_range(range).collect::<String>();
2973 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2974 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2975 (
2976 snapshot.anchor_after(offset + range.start)
2977 ..snapshot.anchor_before(offset + range.end),
2978 replacement,
2979 )
2980 }));
2981 } else if range.end == range.start {
2982 let anchor = snapshot.anchor_after(range.start);
2983 edits.push((anchor..anchor, new_text.into()));
2984 } else {
2985 let edit_start = snapshot.anchor_after(range.start);
2986 let edit_end = snapshot.anchor_before(range.end);
2987 edits.push((edit_start..edit_end, new_text.into()));
2988 }
2989 }
2990
2991 Ok(edits)
2992 })
2993 }
2994
2995 pub(crate) async fn deserialize_workspace_edit(
2996 this: Entity<LspStore>,
2997 edit: lsp::WorkspaceEdit,
2998 push_to_history: bool,
2999 language_server: Arc<LanguageServer>,
3000 cx: &mut AsyncApp,
3001 ) -> Result<ProjectTransaction> {
3002 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3003
3004 let mut operations = Vec::new();
3005 if let Some(document_changes) = edit.document_changes {
3006 match document_changes {
3007 lsp::DocumentChanges::Edits(edits) => {
3008 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3009 }
3010 lsp::DocumentChanges::Operations(ops) => operations = ops,
3011 }
3012 } else if let Some(changes) = edit.changes {
3013 operations.extend(changes.into_iter().map(|(uri, edits)| {
3014 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3015 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3016 uri,
3017 version: None,
3018 },
3019 edits: edits.into_iter().map(Edit::Plain).collect(),
3020 })
3021 }));
3022 }
3023
3024 let mut project_transaction = ProjectTransaction::default();
3025 for operation in operations {
3026 match operation {
3027 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3028 let abs_path = op
3029 .uri
3030 .to_file_path()
3031 .map_err(|()| anyhow!("can't convert URI to path"))?;
3032
3033 if let Some(parent_path) = abs_path.parent() {
3034 fs.create_dir(parent_path).await?;
3035 }
3036 if abs_path.ends_with("/") {
3037 fs.create_dir(&abs_path).await?;
3038 } else {
3039 fs.create_file(
3040 &abs_path,
3041 op.options
3042 .map(|options| fs::CreateOptions {
3043 overwrite: options.overwrite.unwrap_or(false),
3044 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3045 })
3046 .unwrap_or_default(),
3047 )
3048 .await?;
3049 }
3050 }
3051
3052 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3053 let source_abs_path = op
3054 .old_uri
3055 .to_file_path()
3056 .map_err(|()| anyhow!("can't convert URI to path"))?;
3057 let target_abs_path = op
3058 .new_uri
3059 .to_file_path()
3060 .map_err(|()| anyhow!("can't convert URI to path"))?;
3061
3062 let options = fs::RenameOptions {
3063 overwrite: op
3064 .options
3065 .as_ref()
3066 .and_then(|options| options.overwrite)
3067 .unwrap_or(false),
3068 ignore_if_exists: op
3069 .options
3070 .as_ref()
3071 .and_then(|options| options.ignore_if_exists)
3072 .unwrap_or(false),
3073 create_parents: true,
3074 };
3075
3076 fs.rename(&source_abs_path, &target_abs_path, options)
3077 .await?;
3078 }
3079
3080 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3081 let abs_path = op
3082 .uri
3083 .to_file_path()
3084 .map_err(|()| anyhow!("can't convert URI to path"))?;
3085 let options = op
3086 .options
3087 .map(|options| fs::RemoveOptions {
3088 recursive: options.recursive.unwrap_or(false),
3089 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3090 })
3091 .unwrap_or_default();
3092 if abs_path.ends_with("/") {
3093 fs.remove_dir(&abs_path, options).await?;
3094 } else {
3095 fs.remove_file(&abs_path, options).await?;
3096 }
3097 }
3098
3099 lsp::DocumentChangeOperation::Edit(op) => {
3100 let buffer_to_edit = this
3101 .update(cx, |this, cx| {
3102 this.open_local_buffer_via_lsp(
3103 op.text_document.uri.clone(),
3104 language_server.server_id(),
3105 cx,
3106 )
3107 })?
3108 .await?;
3109
3110 let edits = this
3111 .update(cx, |this, cx| {
3112 let path = buffer_to_edit.read(cx).project_path(cx);
3113 let active_entry = this.active_entry;
3114 let is_active_entry = path.is_some_and(|project_path| {
3115 this.worktree_store
3116 .read(cx)
3117 .entry_for_path(&project_path, cx)
3118 .is_some_and(|entry| Some(entry.id) == active_entry)
3119 });
3120 let local = this.as_local_mut().unwrap();
3121
3122 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3123 for edit in op.edits {
3124 match edit {
3125 Edit::Plain(edit) => {
3126 if !edits.contains(&edit) {
3127 edits.push(edit)
3128 }
3129 }
3130 Edit::Annotated(edit) => {
3131 if !edits.contains(&edit.text_edit) {
3132 edits.push(edit.text_edit)
3133 }
3134 }
3135 Edit::Snippet(edit) => {
3136 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3137 else {
3138 continue;
3139 };
3140
3141 if is_active_entry {
3142 snippet_edits.push((edit.range, snippet));
3143 } else {
3144 // Since this buffer is not focused, apply a normal edit.
3145 let new_edit = TextEdit {
3146 range: edit.range,
3147 new_text: snippet.text,
3148 };
3149 if !edits.contains(&new_edit) {
3150 edits.push(new_edit);
3151 }
3152 }
3153 }
3154 }
3155 }
3156 if !snippet_edits.is_empty() {
3157 let buffer_id = buffer_to_edit.read(cx).remote_id();
3158 let version = if let Some(buffer_version) = op.text_document.version
3159 {
3160 local
3161 .buffer_snapshot_for_lsp_version(
3162 &buffer_to_edit,
3163 language_server.server_id(),
3164 Some(buffer_version),
3165 cx,
3166 )
3167 .ok()
3168 .map(|snapshot| snapshot.version)
3169 } else {
3170 Some(buffer_to_edit.read(cx).saved_version().clone())
3171 };
3172
3173 let most_recent_edit =
3174 version.and_then(|version| version.most_recent());
3175 // Check if the edit that triggered that edit has been made by this participant.
3176
3177 if let Some(most_recent_edit) = most_recent_edit {
3178 cx.emit(LspStoreEvent::SnippetEdit {
3179 buffer_id,
3180 edits: snippet_edits,
3181 most_recent_edit,
3182 });
3183 }
3184 }
3185
3186 local.edits_from_lsp(
3187 &buffer_to_edit,
3188 edits,
3189 language_server.server_id(),
3190 op.text_document.version,
3191 cx,
3192 )
3193 })?
3194 .await?;
3195
3196 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3197 buffer.finalize_last_transaction();
3198 buffer.start_transaction();
3199 for (range, text) in edits {
3200 buffer.edit([(range, text)], None, cx);
3201 }
3202
3203 buffer.end_transaction(cx).and_then(|transaction_id| {
3204 if push_to_history {
3205 buffer.finalize_last_transaction();
3206 buffer.get_transaction(transaction_id).cloned()
3207 } else {
3208 buffer.forget_transaction(transaction_id)
3209 }
3210 })
3211 })?;
3212 if let Some(transaction) = transaction {
3213 project_transaction.0.insert(buffer_to_edit, transaction);
3214 }
3215 }
3216 }
3217 }
3218
3219 Ok(project_transaction)
3220 }
3221
3222 async fn on_lsp_workspace_edit(
3223 this: WeakEntity<LspStore>,
3224 params: lsp::ApplyWorkspaceEditParams,
3225 server_id: LanguageServerId,
3226 cx: &mut AsyncApp,
3227 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3228 let this = this.upgrade().context("project project closed")?;
3229 let language_server = this
3230 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3231 .context("language server not found")?;
3232 let transaction = Self::deserialize_workspace_edit(
3233 this.clone(),
3234 params.edit,
3235 true,
3236 language_server.clone(),
3237 cx,
3238 )
3239 .await
3240 .log_err();
3241 this.update(cx, |this, _| {
3242 if let Some(transaction) = transaction {
3243 this.as_local_mut()
3244 .unwrap()
3245 .last_workspace_edits_by_language_server
3246 .insert(server_id, transaction);
3247 }
3248 })?;
3249 Ok(lsp::ApplyWorkspaceEditResponse {
3250 applied: true,
3251 failed_change: None,
3252 failure_reason: None,
3253 })
3254 }
3255
3256 fn remove_worktree(
3257 &mut self,
3258 id_to_remove: WorktreeId,
3259 cx: &mut Context<LspStore>,
3260 ) -> Vec<LanguageServerId> {
3261 self.diagnostics.remove(&id_to_remove);
3262 self.prettier_store.update(cx, |prettier_store, cx| {
3263 prettier_store.remove_worktree(id_to_remove, cx);
3264 });
3265
3266 let mut servers_to_remove = BTreeSet::default();
3267 let mut servers_to_preserve = HashSet::default();
3268 for (seed, state) in &self.language_server_ids {
3269 if seed.worktree_id == id_to_remove {
3270 servers_to_remove.insert(state.id);
3271 } else {
3272 servers_to_preserve.insert(state.id);
3273 }
3274 }
3275 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3276 self.language_server_ids
3277 .retain(|_, state| !servers_to_remove.contains(&state.id));
3278 for server_id_to_remove in &servers_to_remove {
3279 self.language_server_watched_paths
3280 .remove(server_id_to_remove);
3281 self.language_server_paths_watched_for_rename
3282 .remove(server_id_to_remove);
3283 self.last_workspace_edits_by_language_server
3284 .remove(server_id_to_remove);
3285 self.language_servers.remove(server_id_to_remove);
3286 self.buffer_pull_diagnostics_result_ids
3287 .remove(server_id_to_remove);
3288 self.workspace_pull_diagnostics_result_ids
3289 .remove(server_id_to_remove);
3290 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3291 buffer_servers.remove(server_id_to_remove);
3292 }
3293 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3294 }
3295 servers_to_remove.into_iter().collect()
3296 }
3297
3298 fn rebuild_watched_paths_inner<'a>(
3299 &'a self,
3300 language_server_id: LanguageServerId,
3301 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3302 cx: &mut Context<LspStore>,
3303 ) -> LanguageServerWatchedPathsBuilder {
3304 let worktrees = self
3305 .worktree_store
3306 .read(cx)
3307 .worktrees()
3308 .filter_map(|worktree| {
3309 self.language_servers_for_worktree(worktree.read(cx).id())
3310 .find(|server| server.server_id() == language_server_id)
3311 .map(|_| worktree)
3312 })
3313 .collect::<Vec<_>>();
3314
3315 let mut worktree_globs = HashMap::default();
3316 let mut abs_globs = HashMap::default();
3317 log::trace!(
3318 "Processing new watcher paths for language server with id {}",
3319 language_server_id
3320 );
3321
3322 for watcher in watchers {
3323 if let Some((worktree, literal_prefix, pattern)) =
3324 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3325 {
3326 worktree.update(cx, |worktree, _| {
3327 if let Some((tree, glob)) =
3328 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3329 {
3330 tree.add_path_prefix_to_scan(literal_prefix);
3331 worktree_globs
3332 .entry(tree.id())
3333 .or_insert_with(GlobSetBuilder::new)
3334 .add(glob);
3335 }
3336 });
3337 } else {
3338 let (path, pattern) = match &watcher.glob_pattern {
3339 lsp::GlobPattern::String(s) => {
3340 let watcher_path = SanitizedPath::new(s);
3341 let path = glob_literal_prefix(watcher_path.as_path());
3342 let pattern = watcher_path
3343 .as_path()
3344 .strip_prefix(&path)
3345 .map(|p| p.to_string_lossy().into_owned())
3346 .unwrap_or_else(|e| {
3347 debug_panic!(
3348 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3349 s,
3350 path.display(),
3351 e
3352 );
3353 watcher_path.as_path().to_string_lossy().into_owned()
3354 });
3355 (path, pattern)
3356 }
3357 lsp::GlobPattern::Relative(rp) => {
3358 let Ok(mut base_uri) = match &rp.base_uri {
3359 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3360 lsp::OneOf::Right(base_uri) => base_uri,
3361 }
3362 .to_file_path() else {
3363 continue;
3364 };
3365
3366 let path = glob_literal_prefix(Path::new(&rp.pattern));
3367 let pattern = Path::new(&rp.pattern)
3368 .strip_prefix(&path)
3369 .map(|p| p.to_string_lossy().into_owned())
3370 .unwrap_or_else(|e| {
3371 debug_panic!(
3372 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3373 rp.pattern,
3374 path.display(),
3375 e
3376 );
3377 rp.pattern.clone()
3378 });
3379 base_uri.push(path);
3380 (base_uri, pattern)
3381 }
3382 };
3383
3384 if let Some(glob) = Glob::new(&pattern).log_err() {
3385 if !path
3386 .components()
3387 .any(|c| matches!(c, path::Component::Normal(_)))
3388 {
3389 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3390 // rather than adding a new watcher for `/`.
3391 for worktree in &worktrees {
3392 worktree_globs
3393 .entry(worktree.read(cx).id())
3394 .or_insert_with(GlobSetBuilder::new)
3395 .add(glob.clone());
3396 }
3397 } else {
3398 abs_globs
3399 .entry(path.into())
3400 .or_insert_with(GlobSetBuilder::new)
3401 .add(glob);
3402 }
3403 }
3404 }
3405 }
3406
3407 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3408 for (worktree_id, builder) in worktree_globs {
3409 if let Ok(globset) = builder.build() {
3410 watch_builder.watch_worktree(worktree_id, globset);
3411 }
3412 }
3413 for (abs_path, builder) in abs_globs {
3414 if let Ok(globset) = builder.build() {
3415 watch_builder.watch_abs_path(abs_path, globset);
3416 }
3417 }
3418 watch_builder
3419 }
3420
3421 fn worktree_and_path_for_file_watcher(
3422 worktrees: &[Entity<Worktree>],
3423 watcher: &FileSystemWatcher,
3424 cx: &App,
3425 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3426 worktrees.iter().find_map(|worktree| {
3427 let tree = worktree.read(cx);
3428 let worktree_root_path = tree.abs_path();
3429 let path_style = tree.path_style();
3430 match &watcher.glob_pattern {
3431 lsp::GlobPattern::String(s) => {
3432 let watcher_path = SanitizedPath::new(s);
3433 let relative = watcher_path
3434 .as_path()
3435 .strip_prefix(&worktree_root_path)
3436 .ok()?;
3437 let literal_prefix = glob_literal_prefix(relative);
3438 Some((
3439 worktree.clone(),
3440 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3441 relative.to_string_lossy().into_owned(),
3442 ))
3443 }
3444 lsp::GlobPattern::Relative(rp) => {
3445 let base_uri = match &rp.base_uri {
3446 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3447 lsp::OneOf::Right(base_uri) => base_uri,
3448 }
3449 .to_file_path()
3450 .ok()?;
3451 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3452 let mut literal_prefix = relative.to_owned();
3453 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3454 Some((
3455 worktree.clone(),
3456 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3457 rp.pattern.clone(),
3458 ))
3459 }
3460 }
3461 })
3462 }
3463
3464 fn rebuild_watched_paths(
3465 &mut self,
3466 language_server_id: LanguageServerId,
3467 cx: &mut Context<LspStore>,
3468 ) {
3469 let Some(registrations) = self
3470 .language_server_dynamic_registrations
3471 .get(&language_server_id)
3472 else {
3473 return;
3474 };
3475
3476 let watch_builder = self.rebuild_watched_paths_inner(
3477 language_server_id,
3478 registrations.did_change_watched_files.values().flatten(),
3479 cx,
3480 );
3481 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3482 self.language_server_watched_paths
3483 .insert(language_server_id, watcher);
3484
3485 cx.notify();
3486 }
3487
3488 fn on_lsp_did_change_watched_files(
3489 &mut self,
3490 language_server_id: LanguageServerId,
3491 registration_id: &str,
3492 params: DidChangeWatchedFilesRegistrationOptions,
3493 cx: &mut Context<LspStore>,
3494 ) {
3495 let registrations = self
3496 .language_server_dynamic_registrations
3497 .entry(language_server_id)
3498 .or_default();
3499
3500 registrations
3501 .did_change_watched_files
3502 .insert(registration_id.to_string(), params.watchers);
3503
3504 self.rebuild_watched_paths(language_server_id, cx);
3505 }
3506
3507 fn on_lsp_unregister_did_change_watched_files(
3508 &mut self,
3509 language_server_id: LanguageServerId,
3510 registration_id: &str,
3511 cx: &mut Context<LspStore>,
3512 ) {
3513 let registrations = self
3514 .language_server_dynamic_registrations
3515 .entry(language_server_id)
3516 .or_default();
3517
3518 if registrations
3519 .did_change_watched_files
3520 .remove(registration_id)
3521 .is_some()
3522 {
3523 log::info!(
3524 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3525 language_server_id,
3526 registration_id
3527 );
3528 } else {
3529 log::warn!(
3530 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3531 language_server_id,
3532 registration_id
3533 );
3534 }
3535
3536 self.rebuild_watched_paths(language_server_id, cx);
3537 }
3538
3539 async fn initialization_options_for_adapter(
3540 adapter: Arc<dyn LspAdapter>,
3541 delegate: &Arc<dyn LspAdapterDelegate>,
3542 ) -> Result<Option<serde_json::Value>> {
3543 let Some(mut initialization_config) =
3544 adapter.clone().initialization_options(delegate).await?
3545 else {
3546 return Ok(None);
3547 };
3548
3549 for other_adapter in delegate.registered_lsp_adapters() {
3550 if other_adapter.name() == adapter.name() {
3551 continue;
3552 }
3553 if let Ok(Some(target_config)) = other_adapter
3554 .clone()
3555 .additional_initialization_options(adapter.name(), delegate)
3556 .await
3557 {
3558 merge_json_value_into(target_config.clone(), &mut initialization_config);
3559 }
3560 }
3561
3562 Ok(Some(initialization_config))
3563 }
3564
3565 async fn workspace_configuration_for_adapter(
3566 adapter: Arc<dyn LspAdapter>,
3567 delegate: &Arc<dyn LspAdapterDelegate>,
3568 toolchain: Option<Toolchain>,
3569 requested_uri: Option<Uri>,
3570 cx: &mut AsyncApp,
3571 ) -> Result<serde_json::Value> {
3572 let mut workspace_config = adapter
3573 .clone()
3574 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3575 .await?;
3576
3577 for other_adapter in delegate.registered_lsp_adapters() {
3578 if other_adapter.name() == adapter.name() {
3579 continue;
3580 }
3581 if let Ok(Some(target_config)) = other_adapter
3582 .clone()
3583 .additional_workspace_configuration(adapter.name(), delegate, cx)
3584 .await
3585 {
3586 merge_json_value_into(target_config.clone(), &mut workspace_config);
3587 }
3588 }
3589
3590 Ok(workspace_config)
3591 }
3592
3593 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3594 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3595 Some(server.clone())
3596 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3597 Some(Arc::clone(server))
3598 } else {
3599 None
3600 }
3601 }
3602}
3603
3604fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3605 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3606 cx.emit(LspStoreEvent::LanguageServerUpdate {
3607 language_server_id: server.server_id(),
3608 name: Some(server.name()),
3609 message: proto::update_language_server::Variant::MetadataUpdated(
3610 proto::ServerMetadataUpdated {
3611 capabilities: Some(capabilities),
3612 binary: Some(proto::LanguageServerBinaryInfo {
3613 path: server.binary().path.to_string_lossy().into_owned(),
3614 arguments: server
3615 .binary()
3616 .arguments
3617 .iter()
3618 .map(|arg| arg.to_string_lossy().into_owned())
3619 .collect(),
3620 }),
3621 configuration: serde_json::to_string(server.configuration()).ok(),
3622 workspace_folders: server
3623 .workspace_folders()
3624 .iter()
3625 .map(|uri| uri.to_string())
3626 .collect(),
3627 },
3628 ),
3629 });
3630 }
3631}
3632
3633#[derive(Debug)]
3634pub struct FormattableBuffer {
3635 handle: Entity<Buffer>,
3636 abs_path: Option<PathBuf>,
3637 env: Option<HashMap<String, String>>,
3638 ranges: Option<Vec<Range<Anchor>>>,
3639}
3640
3641pub struct RemoteLspStore {
3642 upstream_client: Option<AnyProtoClient>,
3643 upstream_project_id: u64,
3644}
3645
3646pub(crate) enum LspStoreMode {
3647 Local(LocalLspStore), // ssh host and collab host
3648 Remote(RemoteLspStore), // collab guest
3649}
3650
3651impl LspStoreMode {
3652 fn is_local(&self) -> bool {
3653 matches!(self, LspStoreMode::Local(_))
3654 }
3655}
3656
3657pub struct LspStore {
3658 mode: LspStoreMode,
3659 last_formatting_failure: Option<String>,
3660 downstream_client: Option<(AnyProtoClient, u64)>,
3661 nonce: u128,
3662 buffer_store: Entity<BufferStore>,
3663 worktree_store: Entity<WorktreeStore>,
3664 pub languages: Arc<LanguageRegistry>,
3665 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3666 active_entry: Option<ProjectEntryId>,
3667 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3668 _maintain_buffer_languages: Task<()>,
3669 diagnostic_summaries:
3670 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3671 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3672 lsp_data: HashMap<BufferId, BufferLspData>,
3673 next_hint_id: Arc<AtomicUsize>,
3674}
3675
3676#[derive(Debug)]
3677pub struct BufferLspData {
3678 buffer_version: Global,
3679 document_colors: Option<DocumentColorData>,
3680 code_lens: Option<CodeLensData>,
3681 inlay_hints: BufferInlayHints,
3682 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3683 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3684}
3685
3686#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3687struct LspKey {
3688 request_type: TypeId,
3689 server_queried: Option<LanguageServerId>,
3690}
3691
3692impl BufferLspData {
3693 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3694 Self {
3695 buffer_version: buffer.read(cx).version(),
3696 document_colors: None,
3697 code_lens: None,
3698 inlay_hints: BufferInlayHints::new(buffer, cx),
3699 lsp_requests: HashMap::default(),
3700 chunk_lsp_requests: HashMap::default(),
3701 }
3702 }
3703
3704 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3705 if let Some(document_colors) = &mut self.document_colors {
3706 document_colors.colors.remove(&for_server);
3707 document_colors.cache_version += 1;
3708 }
3709
3710 if let Some(code_lens) = &mut self.code_lens {
3711 code_lens.lens.remove(&for_server);
3712 }
3713
3714 self.inlay_hints.remove_server_data(for_server);
3715 }
3716
3717 #[cfg(any(test, feature = "test-support"))]
3718 pub fn inlay_hints(&self) -> &BufferInlayHints {
3719 &self.inlay_hints
3720 }
3721}
3722
3723#[derive(Debug, Default, Clone)]
3724pub struct DocumentColors {
3725 pub colors: HashSet<DocumentColor>,
3726 pub cache_version: Option<usize>,
3727}
3728
3729type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3730type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3731
3732#[derive(Debug, Default)]
3733struct DocumentColorData {
3734 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3735 cache_version: usize,
3736 colors_update: Option<(Global, DocumentColorTask)>,
3737}
3738
3739#[derive(Debug, Default)]
3740struct CodeLensData {
3741 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3742 update: Option<(Global, CodeLensTask)>,
3743}
3744
3745#[derive(Debug)]
3746pub enum LspStoreEvent {
3747 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3748 LanguageServerRemoved(LanguageServerId),
3749 LanguageServerUpdate {
3750 language_server_id: LanguageServerId,
3751 name: Option<LanguageServerName>,
3752 message: proto::update_language_server::Variant,
3753 },
3754 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3755 LanguageServerPrompt(LanguageServerPromptRequest),
3756 LanguageDetected {
3757 buffer: Entity<Buffer>,
3758 new_language: Option<Arc<Language>>,
3759 },
3760 Notification(String),
3761 RefreshInlayHints {
3762 server_id: LanguageServerId,
3763 request_id: Option<usize>,
3764 },
3765 RefreshCodeLens,
3766 DiagnosticsUpdated {
3767 server_id: LanguageServerId,
3768 paths: Vec<ProjectPath>,
3769 },
3770 DiskBasedDiagnosticsStarted {
3771 language_server_id: LanguageServerId,
3772 },
3773 DiskBasedDiagnosticsFinished {
3774 language_server_id: LanguageServerId,
3775 },
3776 SnippetEdit {
3777 buffer_id: BufferId,
3778 edits: Vec<(lsp::Range, Snippet)>,
3779 most_recent_edit: clock::Lamport,
3780 },
3781}
3782
3783#[derive(Clone, Debug, Serialize)]
3784pub struct LanguageServerStatus {
3785 pub name: LanguageServerName,
3786 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3787 pub has_pending_diagnostic_updates: bool,
3788 pub progress_tokens: HashSet<ProgressToken>,
3789 pub worktree: Option<WorktreeId>,
3790 pub binary: Option<LanguageServerBinary>,
3791 pub configuration: Option<Value>,
3792 pub workspace_folders: BTreeSet<Uri>,
3793}
3794
3795#[derive(Clone, Debug)]
3796struct CoreSymbol {
3797 pub language_server_name: LanguageServerName,
3798 pub source_worktree_id: WorktreeId,
3799 pub source_language_server_id: LanguageServerId,
3800 pub path: SymbolLocation,
3801 pub name: String,
3802 pub kind: lsp::SymbolKind,
3803 pub range: Range<Unclipped<PointUtf16>>,
3804}
3805
3806#[derive(Clone, Debug, PartialEq, Eq)]
3807pub enum SymbolLocation {
3808 InProject(ProjectPath),
3809 OutsideProject {
3810 abs_path: Arc<Path>,
3811 signature: [u8; 32],
3812 },
3813}
3814
3815impl SymbolLocation {
3816 fn file_name(&self) -> Option<&str> {
3817 match self {
3818 Self::InProject(path) => path.path.file_name(),
3819 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3820 }
3821 }
3822}
3823
3824impl LspStore {
3825 pub fn init(client: &AnyProtoClient) {
3826 client.add_entity_request_handler(Self::handle_lsp_query);
3827 client.add_entity_message_handler(Self::handle_lsp_query_response);
3828 client.add_entity_request_handler(Self::handle_restart_language_servers);
3829 client.add_entity_request_handler(Self::handle_stop_language_servers);
3830 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3831 client.add_entity_message_handler(Self::handle_start_language_server);
3832 client.add_entity_message_handler(Self::handle_update_language_server);
3833 client.add_entity_message_handler(Self::handle_language_server_log);
3834 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3835 client.add_entity_request_handler(Self::handle_format_buffers);
3836 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3837 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3838 client.add_entity_request_handler(Self::handle_apply_code_action);
3839 client.add_entity_request_handler(Self::handle_get_project_symbols);
3840 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3841 client.add_entity_request_handler(Self::handle_get_color_presentation);
3842 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3843 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3844 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3845 client.add_entity_request_handler(Self::handle_on_type_formatting);
3846 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3847 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3848 client.add_entity_request_handler(Self::handle_rename_project_entry);
3849 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3850 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3851 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3852 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3853 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3854 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3855 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3856
3857 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3858 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3859 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3860 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3861 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3862 client.add_entity_request_handler(
3863 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3864 );
3865 client.add_entity_request_handler(
3866 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3867 );
3868 client.add_entity_request_handler(
3869 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3870 );
3871 }
3872
3873 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3874 match &self.mode {
3875 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3876 _ => None,
3877 }
3878 }
3879
3880 pub fn as_local(&self) -> Option<&LocalLspStore> {
3881 match &self.mode {
3882 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3883 _ => None,
3884 }
3885 }
3886
3887 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3888 match &mut self.mode {
3889 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3890 _ => None,
3891 }
3892 }
3893
3894 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3895 match &self.mode {
3896 LspStoreMode::Remote(RemoteLspStore {
3897 upstream_client: Some(upstream_client),
3898 upstream_project_id,
3899 ..
3900 }) => Some((upstream_client.clone(), *upstream_project_id)),
3901
3902 LspStoreMode::Remote(RemoteLspStore {
3903 upstream_client: None,
3904 ..
3905 }) => None,
3906 LspStoreMode::Local(_) => None,
3907 }
3908 }
3909
3910 pub fn new_local(
3911 buffer_store: Entity<BufferStore>,
3912 worktree_store: Entity<WorktreeStore>,
3913 prettier_store: Entity<PrettierStore>,
3914 toolchain_store: Entity<LocalToolchainStore>,
3915 environment: Entity<ProjectEnvironment>,
3916 manifest_tree: Entity<ManifestTree>,
3917 languages: Arc<LanguageRegistry>,
3918 http_client: Arc<dyn HttpClient>,
3919 fs: Arc<dyn Fs>,
3920 cx: &mut Context<Self>,
3921 ) -> Self {
3922 let yarn = YarnPathStore::new(fs.clone(), cx);
3923 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3924 .detach();
3925 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3926 .detach();
3927 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3928 .detach();
3929 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3930 .detach();
3931 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3932 .detach();
3933 subscribe_to_binary_statuses(&languages, cx).detach();
3934
3935 let _maintain_workspace_config = {
3936 let (sender, receiver) = watch::channel();
3937 (Self::maintain_workspace_config(receiver, cx), sender)
3938 };
3939
3940 Self {
3941 mode: LspStoreMode::Local(LocalLspStore {
3942 weak: cx.weak_entity(),
3943 worktree_store: worktree_store.clone(),
3944
3945 supplementary_language_servers: Default::default(),
3946 languages: languages.clone(),
3947 language_server_ids: Default::default(),
3948 language_servers: Default::default(),
3949 last_workspace_edits_by_language_server: Default::default(),
3950 language_server_watched_paths: Default::default(),
3951 language_server_paths_watched_for_rename: Default::default(),
3952 language_server_dynamic_registrations: Default::default(),
3953 buffers_being_formatted: Default::default(),
3954 buffer_snapshots: Default::default(),
3955 prettier_store,
3956 environment,
3957 http_client,
3958 fs,
3959 yarn,
3960 next_diagnostic_group_id: Default::default(),
3961 diagnostics: Default::default(),
3962 _subscription: cx.on_app_quit(|this, cx| {
3963 this.as_local_mut()
3964 .unwrap()
3965 .shutdown_language_servers_on_quit(cx)
3966 }),
3967 lsp_tree: LanguageServerTree::new(
3968 manifest_tree,
3969 languages.clone(),
3970 toolchain_store.clone(),
3971 ),
3972 toolchain_store,
3973 registered_buffers: HashMap::default(),
3974 buffers_opened_in_servers: HashMap::default(),
3975 buffer_pull_diagnostics_result_ids: HashMap::default(),
3976 workspace_pull_diagnostics_result_ids: HashMap::default(),
3977 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3978 .manifest_file_names(),
3979 }),
3980 last_formatting_failure: None,
3981 downstream_client: None,
3982 buffer_store,
3983 worktree_store,
3984 languages: languages.clone(),
3985 language_server_statuses: Default::default(),
3986 nonce: StdRng::from_os_rng().random(),
3987 diagnostic_summaries: HashMap::default(),
3988 lsp_server_capabilities: HashMap::default(),
3989 lsp_data: HashMap::default(),
3990 next_hint_id: Arc::default(),
3991 active_entry: None,
3992 _maintain_workspace_config,
3993 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3994 }
3995 }
3996
3997 fn send_lsp_proto_request<R: LspCommand>(
3998 &self,
3999 buffer: Entity<Buffer>,
4000 client: AnyProtoClient,
4001 upstream_project_id: u64,
4002 request: R,
4003 cx: &mut Context<LspStore>,
4004 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4005 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4006 return Task::ready(Ok(R::Response::default()));
4007 }
4008 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4009 cx.spawn(async move |this, cx| {
4010 let response = client.request(message).await?;
4011 let this = this.upgrade().context("project dropped")?;
4012 request
4013 .response_from_proto(response, this, buffer, cx.clone())
4014 .await
4015 })
4016 }
4017
4018 pub(super) fn new_remote(
4019 buffer_store: Entity<BufferStore>,
4020 worktree_store: Entity<WorktreeStore>,
4021 languages: Arc<LanguageRegistry>,
4022 upstream_client: AnyProtoClient,
4023 project_id: u64,
4024 cx: &mut Context<Self>,
4025 ) -> Self {
4026 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4027 .detach();
4028 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4029 .detach();
4030 subscribe_to_binary_statuses(&languages, cx).detach();
4031 let _maintain_workspace_config = {
4032 let (sender, receiver) = watch::channel();
4033 (Self::maintain_workspace_config(receiver, cx), sender)
4034 };
4035 Self {
4036 mode: LspStoreMode::Remote(RemoteLspStore {
4037 upstream_client: Some(upstream_client),
4038 upstream_project_id: project_id,
4039 }),
4040 downstream_client: None,
4041 last_formatting_failure: None,
4042 buffer_store,
4043 worktree_store,
4044 languages: languages.clone(),
4045 language_server_statuses: Default::default(),
4046 nonce: StdRng::from_os_rng().random(),
4047 diagnostic_summaries: HashMap::default(),
4048 lsp_server_capabilities: HashMap::default(),
4049 next_hint_id: Arc::default(),
4050 lsp_data: HashMap::default(),
4051 active_entry: None,
4052
4053 _maintain_workspace_config,
4054 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4055 }
4056 }
4057
4058 fn on_buffer_store_event(
4059 &mut self,
4060 _: Entity<BufferStore>,
4061 event: &BufferStoreEvent,
4062 cx: &mut Context<Self>,
4063 ) {
4064 match event {
4065 BufferStoreEvent::BufferAdded(buffer) => {
4066 self.on_buffer_added(buffer, cx).log_err();
4067 }
4068 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4069 let buffer_id = buffer.read(cx).remote_id();
4070 if let Some(local) = self.as_local_mut()
4071 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4072 {
4073 local.reset_buffer(buffer, old_file, cx);
4074
4075 if local.registered_buffers.contains_key(&buffer_id) {
4076 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4077 }
4078 }
4079
4080 self.detect_language_for_buffer(buffer, cx);
4081 if let Some(local) = self.as_local_mut() {
4082 local.initialize_buffer(buffer, cx);
4083 if local.registered_buffers.contains_key(&buffer_id) {
4084 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4085 }
4086 }
4087 }
4088 _ => {}
4089 }
4090 }
4091
4092 fn on_worktree_store_event(
4093 &mut self,
4094 _: Entity<WorktreeStore>,
4095 event: &WorktreeStoreEvent,
4096 cx: &mut Context<Self>,
4097 ) {
4098 match event {
4099 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4100 if !worktree.read(cx).is_local() {
4101 return;
4102 }
4103 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4104 worktree::Event::UpdatedEntries(changes) => {
4105 this.update_local_worktree_language_servers(&worktree, changes, cx);
4106 }
4107 worktree::Event::UpdatedGitRepositories(_)
4108 | worktree::Event::DeletedEntry(_) => {}
4109 })
4110 .detach()
4111 }
4112 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4113 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4114 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4115 }
4116 WorktreeStoreEvent::WorktreeReleased(..)
4117 | WorktreeStoreEvent::WorktreeOrderChanged
4118 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4119 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4120 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4121 }
4122 }
4123
4124 fn on_prettier_store_event(
4125 &mut self,
4126 _: Entity<PrettierStore>,
4127 event: &PrettierStoreEvent,
4128 cx: &mut Context<Self>,
4129 ) {
4130 match event {
4131 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4132 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4133 }
4134 PrettierStoreEvent::LanguageServerAdded {
4135 new_server_id,
4136 name,
4137 prettier_server,
4138 } => {
4139 self.register_supplementary_language_server(
4140 *new_server_id,
4141 name.clone(),
4142 prettier_server.clone(),
4143 cx,
4144 );
4145 }
4146 }
4147 }
4148
4149 fn on_toolchain_store_event(
4150 &mut self,
4151 _: Entity<LocalToolchainStore>,
4152 event: &ToolchainStoreEvent,
4153 _: &mut Context<Self>,
4154 ) {
4155 if let ToolchainStoreEvent::ToolchainActivated = event {
4156 self.request_workspace_config_refresh()
4157 }
4158 }
4159
4160 fn request_workspace_config_refresh(&mut self) {
4161 *self._maintain_workspace_config.1.borrow_mut() = ();
4162 }
4163
4164 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4165 self.as_local().map(|local| local.prettier_store.clone())
4166 }
4167
4168 fn on_buffer_event(
4169 &mut self,
4170 buffer: Entity<Buffer>,
4171 event: &language::BufferEvent,
4172 cx: &mut Context<Self>,
4173 ) {
4174 match event {
4175 language::BufferEvent::Edited => {
4176 self.on_buffer_edited(buffer, cx);
4177 }
4178
4179 language::BufferEvent::Saved => {
4180 self.on_buffer_saved(buffer, cx);
4181 }
4182
4183 _ => {}
4184 }
4185 }
4186
4187 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4188 buffer
4189 .read(cx)
4190 .set_language_registry(self.languages.clone());
4191
4192 cx.subscribe(buffer, |this, buffer, event, cx| {
4193 this.on_buffer_event(buffer, event, cx);
4194 })
4195 .detach();
4196
4197 self.detect_language_for_buffer(buffer, cx);
4198 if let Some(local) = self.as_local_mut() {
4199 local.initialize_buffer(buffer, cx);
4200 }
4201
4202 Ok(())
4203 }
4204
4205 pub(crate) fn register_buffer_with_language_servers(
4206 &mut self,
4207 buffer: &Entity<Buffer>,
4208 only_register_servers: HashSet<LanguageServerSelector>,
4209 ignore_refcounts: bool,
4210 cx: &mut Context<Self>,
4211 ) -> OpenLspBufferHandle {
4212 let buffer_id = buffer.read(cx).remote_id();
4213 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4214 if let Some(local) = self.as_local_mut() {
4215 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4216 if !ignore_refcounts {
4217 *refcount += 1;
4218 }
4219
4220 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4221 // 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
4222 // 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
4223 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4224 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4225 return handle;
4226 };
4227 if !file.is_local() {
4228 return handle;
4229 }
4230
4231 if ignore_refcounts || *refcount == 1 {
4232 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4233 }
4234 if !ignore_refcounts {
4235 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4236 let refcount = {
4237 let local = lsp_store.as_local_mut().unwrap();
4238 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4239 debug_panic!("bad refcounting");
4240 return;
4241 };
4242
4243 *refcount -= 1;
4244 *refcount
4245 };
4246 if refcount == 0 {
4247 lsp_store.lsp_data.remove(&buffer_id);
4248 let local = lsp_store.as_local_mut().unwrap();
4249 local.registered_buffers.remove(&buffer_id);
4250
4251 local.buffers_opened_in_servers.remove(&buffer_id);
4252 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4253 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4254
4255 let buffer_abs_path = file.abs_path(cx);
4256 for (_, buffer_pull_diagnostics_result_ids) in
4257 &mut local.buffer_pull_diagnostics_result_ids
4258 {
4259 buffer_pull_diagnostics_result_ids.retain(
4260 |_, buffer_result_ids| {
4261 buffer_result_ids.remove(&buffer_abs_path);
4262 !buffer_result_ids.is_empty()
4263 },
4264 );
4265 }
4266
4267 let diagnostic_updates = local
4268 .language_servers
4269 .keys()
4270 .cloned()
4271 .map(|server_id| DocumentDiagnosticsUpdate {
4272 diagnostics: DocumentDiagnostics {
4273 document_abs_path: buffer_abs_path.clone(),
4274 version: None,
4275 diagnostics: Vec::new(),
4276 },
4277 result_id: None,
4278 registration_id: None,
4279 server_id: server_id,
4280 disk_based_sources: Cow::Borrowed(&[]),
4281 })
4282 .collect::<Vec<_>>();
4283
4284 lsp_store
4285 .merge_diagnostic_entries(
4286 diagnostic_updates,
4287 |_, diagnostic, _| {
4288 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4289 },
4290 cx,
4291 )
4292 .context("Clearing diagnostics for the closed buffer")
4293 .log_err();
4294 }
4295 }
4296 })
4297 .detach();
4298 }
4299 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4300 let buffer_id = buffer.read(cx).remote_id().to_proto();
4301 cx.background_spawn(async move {
4302 upstream_client
4303 .request(proto::RegisterBufferWithLanguageServers {
4304 project_id: upstream_project_id,
4305 buffer_id,
4306 only_servers: only_register_servers
4307 .into_iter()
4308 .map(|selector| {
4309 let selector = match selector {
4310 LanguageServerSelector::Id(language_server_id) => {
4311 proto::language_server_selector::Selector::ServerId(
4312 language_server_id.to_proto(),
4313 )
4314 }
4315 LanguageServerSelector::Name(language_server_name) => {
4316 proto::language_server_selector::Selector::Name(
4317 language_server_name.to_string(),
4318 )
4319 }
4320 };
4321 proto::LanguageServerSelector {
4322 selector: Some(selector),
4323 }
4324 })
4325 .collect(),
4326 })
4327 .await
4328 })
4329 .detach();
4330 } else {
4331 // Our remote connection got closed
4332 }
4333 handle
4334 }
4335
4336 fn maintain_buffer_languages(
4337 languages: Arc<LanguageRegistry>,
4338 cx: &mut Context<Self>,
4339 ) -> Task<()> {
4340 let mut subscription = languages.subscribe();
4341 let mut prev_reload_count = languages.reload_count();
4342 cx.spawn(async move |this, cx| {
4343 while let Some(()) = subscription.next().await {
4344 if let Some(this) = this.upgrade() {
4345 // If the language registry has been reloaded, then remove and
4346 // re-assign the languages on all open buffers.
4347 let reload_count = languages.reload_count();
4348 if reload_count > prev_reload_count {
4349 prev_reload_count = reload_count;
4350 this.update(cx, |this, cx| {
4351 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4352 for buffer in buffer_store.buffers() {
4353 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4354 {
4355 buffer.update(cx, |buffer, cx| {
4356 buffer.set_language_async(None, cx)
4357 });
4358 if let Some(local) = this.as_local_mut() {
4359 local.reset_buffer(&buffer, &f, cx);
4360
4361 if local
4362 .registered_buffers
4363 .contains_key(&buffer.read(cx).remote_id())
4364 && let Some(file_url) =
4365 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4366 {
4367 local.unregister_buffer_from_language_servers(
4368 &buffer, &file_url, cx,
4369 );
4370 }
4371 }
4372 }
4373 }
4374 });
4375 })
4376 .ok();
4377 }
4378
4379 this.update(cx, |this, cx| {
4380 let mut plain_text_buffers = Vec::new();
4381 let mut buffers_with_unknown_injections = Vec::new();
4382 for handle in this.buffer_store.read(cx).buffers() {
4383 let buffer = handle.read(cx);
4384 if buffer.language().is_none()
4385 || buffer.language() == Some(&*language::PLAIN_TEXT)
4386 {
4387 plain_text_buffers.push(handle);
4388 } else if buffer.contains_unknown_injections() {
4389 buffers_with_unknown_injections.push(handle);
4390 }
4391 }
4392
4393 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4394 // and reused later in the invisible worktrees.
4395 plain_text_buffers.sort_by_key(|buffer| {
4396 Reverse(
4397 File::from_dyn(buffer.read(cx).file())
4398 .map(|file| file.worktree.read(cx).is_visible()),
4399 )
4400 });
4401
4402 for buffer in plain_text_buffers {
4403 this.detect_language_for_buffer(&buffer, cx);
4404 if let Some(local) = this.as_local_mut() {
4405 local.initialize_buffer(&buffer, cx);
4406 if local
4407 .registered_buffers
4408 .contains_key(&buffer.read(cx).remote_id())
4409 {
4410 local.register_buffer_with_language_servers(
4411 &buffer,
4412 HashSet::default(),
4413 cx,
4414 );
4415 }
4416 }
4417 }
4418
4419 for buffer in buffers_with_unknown_injections {
4420 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4421 }
4422 })
4423 .ok();
4424 }
4425 }
4426 })
4427 }
4428
4429 fn detect_language_for_buffer(
4430 &mut self,
4431 buffer_handle: &Entity<Buffer>,
4432 cx: &mut Context<Self>,
4433 ) -> Option<language::AvailableLanguage> {
4434 // If the buffer has a language, set it and start the language server if we haven't already.
4435 let buffer = buffer_handle.read(cx);
4436 let file = buffer.file()?;
4437
4438 let content = buffer.as_rope();
4439 let available_language = self.languages.language_for_file(file, Some(content), cx);
4440 if let Some(available_language) = &available_language {
4441 if let Some(Ok(Ok(new_language))) = self
4442 .languages
4443 .load_language(available_language)
4444 .now_or_never()
4445 {
4446 self.set_language_for_buffer(buffer_handle, new_language, cx);
4447 }
4448 } else {
4449 cx.emit(LspStoreEvent::LanguageDetected {
4450 buffer: buffer_handle.clone(),
4451 new_language: None,
4452 });
4453 }
4454
4455 available_language
4456 }
4457
4458 pub(crate) fn set_language_for_buffer(
4459 &mut self,
4460 buffer_entity: &Entity<Buffer>,
4461 new_language: Arc<Language>,
4462 cx: &mut Context<Self>,
4463 ) {
4464 let buffer = buffer_entity.read(cx);
4465 let buffer_file = buffer.file().cloned();
4466 let buffer_id = buffer.remote_id();
4467 if let Some(local_store) = self.as_local_mut()
4468 && local_store.registered_buffers.contains_key(&buffer_id)
4469 && let Some(abs_path) =
4470 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4471 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4472 {
4473 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4474 }
4475 buffer_entity.update(cx, |buffer, cx| {
4476 if buffer
4477 .language()
4478 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4479 {
4480 buffer.set_language_async(Some(new_language.clone()), cx);
4481 }
4482 });
4483
4484 let settings =
4485 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4486 let buffer_file = File::from_dyn(buffer_file.as_ref());
4487
4488 let worktree_id = if let Some(file) = buffer_file {
4489 let worktree = file.worktree.clone();
4490
4491 if let Some(local) = self.as_local_mut()
4492 && local.registered_buffers.contains_key(&buffer_id)
4493 {
4494 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4495 }
4496 Some(worktree.read(cx).id())
4497 } else {
4498 None
4499 };
4500
4501 if settings.prettier.allowed
4502 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4503 {
4504 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4505 if let Some(prettier_store) = prettier_store {
4506 prettier_store.update(cx, |prettier_store, cx| {
4507 prettier_store.install_default_prettier(
4508 worktree_id,
4509 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4510 cx,
4511 )
4512 })
4513 }
4514 }
4515
4516 cx.emit(LspStoreEvent::LanguageDetected {
4517 buffer: buffer_entity.clone(),
4518 new_language: Some(new_language),
4519 })
4520 }
4521
4522 pub fn buffer_store(&self) -> Entity<BufferStore> {
4523 self.buffer_store.clone()
4524 }
4525
4526 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4527 self.active_entry = active_entry;
4528 }
4529
4530 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4531 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4532 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4533 {
4534 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4535 summaries
4536 .iter()
4537 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4538 });
4539 if let Some(summary) = summaries.next() {
4540 client
4541 .send(proto::UpdateDiagnosticSummary {
4542 project_id: downstream_project_id,
4543 worktree_id: worktree.id().to_proto(),
4544 summary: Some(summary),
4545 more_summaries: summaries.collect(),
4546 })
4547 .log_err();
4548 }
4549 }
4550 }
4551
4552 fn is_capable_for_proto_request<R>(
4553 &self,
4554 buffer: &Entity<Buffer>,
4555 request: &R,
4556 cx: &App,
4557 ) -> bool
4558 where
4559 R: LspCommand,
4560 {
4561 self.check_if_capable_for_proto_request(
4562 buffer,
4563 |capabilities| {
4564 request.check_capabilities(AdapterServerCapabilities {
4565 server_capabilities: capabilities.clone(),
4566 code_action_kinds: None,
4567 })
4568 },
4569 cx,
4570 )
4571 }
4572
4573 fn check_if_capable_for_proto_request<F>(
4574 &self,
4575 buffer: &Entity<Buffer>,
4576 check: F,
4577 cx: &App,
4578 ) -> bool
4579 where
4580 F: FnMut(&lsp::ServerCapabilities) -> bool,
4581 {
4582 let Some(language) = buffer.read(cx).language().cloned() else {
4583 return false;
4584 };
4585 let relevant_language_servers = self
4586 .languages
4587 .lsp_adapters(&language.name())
4588 .into_iter()
4589 .map(|lsp_adapter| lsp_adapter.name())
4590 .collect::<HashSet<_>>();
4591 self.language_server_statuses
4592 .iter()
4593 .filter_map(|(server_id, server_status)| {
4594 relevant_language_servers
4595 .contains(&server_status.name)
4596 .then_some(server_id)
4597 })
4598 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4599 .any(check)
4600 }
4601
4602 fn all_capable_for_proto_request<F>(
4603 &self,
4604 buffer: &Entity<Buffer>,
4605 mut check: F,
4606 cx: &App,
4607 ) -> Vec<lsp::LanguageServerId>
4608 where
4609 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4610 {
4611 let Some(language) = buffer.read(cx).language().cloned() else {
4612 return Vec::default();
4613 };
4614 let relevant_language_servers = self
4615 .languages
4616 .lsp_adapters(&language.name())
4617 .into_iter()
4618 .map(|lsp_adapter| lsp_adapter.name())
4619 .collect::<HashSet<_>>();
4620 self.language_server_statuses
4621 .iter()
4622 .filter_map(|(server_id, server_status)| {
4623 relevant_language_servers
4624 .contains(&server_status.name)
4625 .then_some((server_id, &server_status.name))
4626 })
4627 .filter_map(|(server_id, server_name)| {
4628 self.lsp_server_capabilities
4629 .get(server_id)
4630 .map(|c| (server_id, server_name, c))
4631 })
4632 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4633 .map(|(server_id, _, _)| *server_id)
4634 .collect()
4635 }
4636
4637 pub fn request_lsp<R>(
4638 &mut self,
4639 buffer: Entity<Buffer>,
4640 server: LanguageServerToQuery,
4641 request: R,
4642 cx: &mut Context<Self>,
4643 ) -> Task<Result<R::Response>>
4644 where
4645 R: LspCommand,
4646 <R::LspRequest as lsp::request::Request>::Result: Send,
4647 <R::LspRequest as lsp::request::Request>::Params: Send,
4648 {
4649 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4650 return self.send_lsp_proto_request(
4651 buffer,
4652 upstream_client,
4653 upstream_project_id,
4654 request,
4655 cx,
4656 );
4657 }
4658
4659 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4660 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4661 local
4662 .language_servers_for_buffer(buffer, cx)
4663 .find(|(_, server)| {
4664 request.check_capabilities(server.adapter_server_capabilities())
4665 })
4666 .map(|(_, server)| server.clone())
4667 }),
4668 LanguageServerToQuery::Other(id) => self
4669 .language_server_for_local_buffer(buffer, id, cx)
4670 .and_then(|(_, server)| {
4671 request
4672 .check_capabilities(server.adapter_server_capabilities())
4673 .then(|| Arc::clone(server))
4674 }),
4675 }) else {
4676 return Task::ready(Ok(Default::default()));
4677 };
4678
4679 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4680
4681 let Some(file) = file else {
4682 return Task::ready(Ok(Default::default()));
4683 };
4684
4685 let lsp_params = match request.to_lsp_params_or_response(
4686 &file.abs_path(cx),
4687 buffer.read(cx),
4688 &language_server,
4689 cx,
4690 ) {
4691 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4692 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4693 Err(err) => {
4694 let message = format!(
4695 "{} via {} failed: {}",
4696 request.display_name(),
4697 language_server.name(),
4698 err
4699 );
4700 // rust-analyzer likes to error with this when its still loading up
4701 if !message.ends_with("content modified") {
4702 log::warn!("{message}");
4703 }
4704 return Task::ready(Err(anyhow!(message)));
4705 }
4706 };
4707
4708 let status = request.status();
4709 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4710 return Task::ready(Ok(Default::default()));
4711 }
4712 cx.spawn(async move |this, cx| {
4713 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4714
4715 let id = lsp_request.id();
4716 let _cleanup = if status.is_some() {
4717 cx.update(|cx| {
4718 this.update(cx, |this, cx| {
4719 this.on_lsp_work_start(
4720 language_server.server_id(),
4721 ProgressToken::Number(id),
4722 LanguageServerProgress {
4723 is_disk_based_diagnostics_progress: false,
4724 is_cancellable: false,
4725 title: None,
4726 message: status.clone(),
4727 percentage: None,
4728 last_update_at: cx.background_executor().now(),
4729 },
4730 cx,
4731 );
4732 })
4733 })
4734 .log_err();
4735
4736 Some(defer(|| {
4737 cx.update(|cx| {
4738 this.update(cx, |this, cx| {
4739 this.on_lsp_work_end(
4740 language_server.server_id(),
4741 ProgressToken::Number(id),
4742 cx,
4743 );
4744 })
4745 })
4746 .log_err();
4747 }))
4748 } else {
4749 None
4750 };
4751
4752 let result = lsp_request.await.into_response();
4753
4754 let response = result.map_err(|err| {
4755 let message = format!(
4756 "{} via {} failed: {}",
4757 request.display_name(),
4758 language_server.name(),
4759 err
4760 );
4761 // rust-analyzer likes to error with this when its still loading up
4762 if !message.ends_with("content modified") {
4763 log::warn!("{message}");
4764 }
4765 anyhow::anyhow!(message)
4766 })?;
4767
4768 request
4769 .response_from_lsp(
4770 response,
4771 this.upgrade().context("no app context")?,
4772 buffer,
4773 language_server.server_id(),
4774 cx.clone(),
4775 )
4776 .await
4777 })
4778 }
4779
4780 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4781 let mut language_formatters_to_check = Vec::new();
4782 for buffer in self.buffer_store.read(cx).buffers() {
4783 let buffer = buffer.read(cx);
4784 let buffer_file = File::from_dyn(buffer.file());
4785 let buffer_language = buffer.language();
4786 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4787 if buffer_language.is_some() {
4788 language_formatters_to_check.push((
4789 buffer_file.map(|f| f.worktree_id(cx)),
4790 settings.into_owned(),
4791 ));
4792 }
4793 }
4794
4795 self.request_workspace_config_refresh();
4796
4797 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4798 prettier_store.update(cx, |prettier_store, cx| {
4799 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4800 })
4801 }
4802
4803 cx.notify();
4804 }
4805
4806 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4807 let buffer_store = self.buffer_store.clone();
4808 let Some(local) = self.as_local_mut() else {
4809 return;
4810 };
4811 let mut adapters = BTreeMap::default();
4812 let get_adapter = {
4813 let languages = local.languages.clone();
4814 let environment = local.environment.clone();
4815 let weak = local.weak.clone();
4816 let worktree_store = local.worktree_store.clone();
4817 let http_client = local.http_client.clone();
4818 let fs = local.fs.clone();
4819 move |worktree_id, cx: &mut App| {
4820 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4821 Some(LocalLspAdapterDelegate::new(
4822 languages.clone(),
4823 &environment,
4824 weak.clone(),
4825 &worktree,
4826 http_client.clone(),
4827 fs.clone(),
4828 cx,
4829 ))
4830 }
4831 };
4832
4833 let mut messages_to_report = Vec::new();
4834 let (new_tree, to_stop) = {
4835 let mut rebase = local.lsp_tree.rebase();
4836 let buffers = buffer_store
4837 .read(cx)
4838 .buffers()
4839 .filter_map(|buffer| {
4840 let raw_buffer = buffer.read(cx);
4841 if !local
4842 .registered_buffers
4843 .contains_key(&raw_buffer.remote_id())
4844 {
4845 return None;
4846 }
4847 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4848 let language = raw_buffer.language().cloned()?;
4849 Some((file, language, raw_buffer.remote_id()))
4850 })
4851 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4852 for (file, language, buffer_id) in buffers {
4853 let worktree_id = file.worktree_id(cx);
4854 let Some(worktree) = local
4855 .worktree_store
4856 .read(cx)
4857 .worktree_for_id(worktree_id, cx)
4858 else {
4859 continue;
4860 };
4861
4862 if let Some((_, apply)) = local.reuse_existing_language_server(
4863 rebase.server_tree(),
4864 &worktree,
4865 &language.name(),
4866 cx,
4867 ) {
4868 (apply)(rebase.server_tree());
4869 } else if let Some(lsp_delegate) = adapters
4870 .entry(worktree_id)
4871 .or_insert_with(|| get_adapter(worktree_id, cx))
4872 .clone()
4873 {
4874 let delegate =
4875 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4876 let path = file
4877 .path()
4878 .parent()
4879 .map(Arc::from)
4880 .unwrap_or_else(|| file.path().clone());
4881 let worktree_path = ProjectPath { worktree_id, path };
4882 let abs_path = file.abs_path(cx);
4883 let nodes = rebase
4884 .walk(
4885 worktree_path,
4886 language.name(),
4887 language.manifest(),
4888 delegate.clone(),
4889 cx,
4890 )
4891 .collect::<Vec<_>>();
4892 for node in nodes {
4893 let server_id = node.server_id_or_init(|disposition| {
4894 let path = &disposition.path;
4895 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4896 let key = LanguageServerSeed {
4897 worktree_id,
4898 name: disposition.server_name.clone(),
4899 settings: disposition.settings.clone(),
4900 toolchain: local.toolchain_store.read(cx).active_toolchain(
4901 path.worktree_id,
4902 &path.path,
4903 language.name(),
4904 ),
4905 };
4906 local.language_server_ids.remove(&key);
4907
4908 let server_id = local.get_or_insert_language_server(
4909 &worktree,
4910 lsp_delegate.clone(),
4911 disposition,
4912 &language.name(),
4913 cx,
4914 );
4915 if let Some(state) = local.language_servers.get(&server_id)
4916 && let Ok(uri) = uri
4917 {
4918 state.add_workspace_folder(uri);
4919 };
4920 server_id
4921 });
4922
4923 if let Some(language_server_id) = server_id {
4924 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4925 language_server_id,
4926 name: node.name(),
4927 message:
4928 proto::update_language_server::Variant::RegisteredForBuffer(
4929 proto::RegisteredForBuffer {
4930 buffer_abs_path: abs_path
4931 .to_string_lossy()
4932 .into_owned(),
4933 buffer_id: buffer_id.to_proto(),
4934 },
4935 ),
4936 });
4937 }
4938 }
4939 } else {
4940 continue;
4941 }
4942 }
4943 rebase.finish()
4944 };
4945 for message in messages_to_report {
4946 cx.emit(message);
4947 }
4948 local.lsp_tree = new_tree;
4949 for (id, _) in to_stop {
4950 self.stop_local_language_server(id, cx).detach();
4951 }
4952 }
4953
4954 pub fn apply_code_action(
4955 &self,
4956 buffer_handle: Entity<Buffer>,
4957 mut action: CodeAction,
4958 push_to_history: bool,
4959 cx: &mut Context<Self>,
4960 ) -> Task<Result<ProjectTransaction>> {
4961 if let Some((upstream_client, project_id)) = self.upstream_client() {
4962 let request = proto::ApplyCodeAction {
4963 project_id,
4964 buffer_id: buffer_handle.read(cx).remote_id().into(),
4965 action: Some(Self::serialize_code_action(&action)),
4966 };
4967 let buffer_store = self.buffer_store();
4968 cx.spawn(async move |_, cx| {
4969 let response = upstream_client
4970 .request(request)
4971 .await?
4972 .transaction
4973 .context("missing transaction")?;
4974
4975 buffer_store
4976 .update(cx, |buffer_store, cx| {
4977 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4978 })?
4979 .await
4980 })
4981 } else if self.mode.is_local() {
4982 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4983 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4984 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4985 }) else {
4986 return Task::ready(Ok(ProjectTransaction::default()));
4987 };
4988 cx.spawn(async move |this, cx| {
4989 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4990 .await
4991 .context("resolving a code action")?;
4992 if let Some(edit) = action.lsp_action.edit()
4993 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4994 return LocalLspStore::deserialize_workspace_edit(
4995 this.upgrade().context("no app present")?,
4996 edit.clone(),
4997 push_to_history,
4998
4999 lang_server.clone(),
5000 cx,
5001 )
5002 .await;
5003 }
5004
5005 if let Some(command) = action.lsp_action.command() {
5006 let server_capabilities = lang_server.capabilities();
5007 let available_commands = server_capabilities
5008 .execute_command_provider
5009 .as_ref()
5010 .map(|options| options.commands.as_slice())
5011 .unwrap_or_default();
5012 if available_commands.contains(&command.command) {
5013 this.update(cx, |this, _| {
5014 this.as_local_mut()
5015 .unwrap()
5016 .last_workspace_edits_by_language_server
5017 .remove(&lang_server.server_id());
5018 })?;
5019
5020 let _result = lang_server
5021 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5022 command: command.command.clone(),
5023 arguments: command.arguments.clone().unwrap_or_default(),
5024 ..lsp::ExecuteCommandParams::default()
5025 })
5026 .await.into_response()
5027 .context("execute command")?;
5028
5029 return this.update(cx, |this, _| {
5030 this.as_local_mut()
5031 .unwrap()
5032 .last_workspace_edits_by_language_server
5033 .remove(&lang_server.server_id())
5034 .unwrap_or_default()
5035 });
5036 } else {
5037 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5038 }
5039 }
5040
5041 Ok(ProjectTransaction::default())
5042 })
5043 } else {
5044 Task::ready(Err(anyhow!("no upstream client and not local")))
5045 }
5046 }
5047
5048 pub fn apply_code_action_kind(
5049 &mut self,
5050 buffers: HashSet<Entity<Buffer>>,
5051 kind: CodeActionKind,
5052 push_to_history: bool,
5053 cx: &mut Context<Self>,
5054 ) -> Task<anyhow::Result<ProjectTransaction>> {
5055 if self.as_local().is_some() {
5056 cx.spawn(async move |lsp_store, cx| {
5057 let buffers = buffers.into_iter().collect::<Vec<_>>();
5058 let result = LocalLspStore::execute_code_action_kind_locally(
5059 lsp_store.clone(),
5060 buffers,
5061 kind,
5062 push_to_history,
5063 cx,
5064 )
5065 .await;
5066 lsp_store.update(cx, |lsp_store, _| {
5067 lsp_store.update_last_formatting_failure(&result);
5068 })?;
5069 result
5070 })
5071 } else if let Some((client, project_id)) = self.upstream_client() {
5072 let buffer_store = self.buffer_store();
5073 cx.spawn(async move |lsp_store, cx| {
5074 let result = client
5075 .request(proto::ApplyCodeActionKind {
5076 project_id,
5077 kind: kind.as_str().to_owned(),
5078 buffer_ids: buffers
5079 .iter()
5080 .map(|buffer| {
5081 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5082 })
5083 .collect::<Result<_>>()?,
5084 })
5085 .await
5086 .and_then(|result| result.transaction.context("missing transaction"));
5087 lsp_store.update(cx, |lsp_store, _| {
5088 lsp_store.update_last_formatting_failure(&result);
5089 })?;
5090
5091 let transaction_response = result?;
5092 buffer_store
5093 .update(cx, |buffer_store, cx| {
5094 buffer_store.deserialize_project_transaction(
5095 transaction_response,
5096 push_to_history,
5097 cx,
5098 )
5099 })?
5100 .await
5101 })
5102 } else {
5103 Task::ready(Ok(ProjectTransaction::default()))
5104 }
5105 }
5106
5107 pub fn resolved_hint(
5108 &mut self,
5109 buffer_id: BufferId,
5110 id: InlayId,
5111 cx: &mut Context<Self>,
5112 ) -> Option<ResolvedHint> {
5113 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5114
5115 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5116 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5117 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5118 let (server_id, resolve_data) = match &hint.resolve_state {
5119 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5120 ResolveState::Resolving => {
5121 return Some(ResolvedHint::Resolving(
5122 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5123 ));
5124 }
5125 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5126 };
5127
5128 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5129 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5130 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5131 id,
5132 cx.spawn(async move |lsp_store, cx| {
5133 let resolved_hint = resolve_task.await;
5134 lsp_store
5135 .update(cx, |lsp_store, _| {
5136 if let Some(old_inlay_hint) = lsp_store
5137 .lsp_data
5138 .get_mut(&buffer_id)
5139 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5140 {
5141 match resolved_hint {
5142 Ok(resolved_hint) => {
5143 *old_inlay_hint = resolved_hint;
5144 }
5145 Err(e) => {
5146 old_inlay_hint.resolve_state =
5147 ResolveState::CanResolve(server_id, resolve_data);
5148 log::error!("Inlay hint resolve failed: {e:#}");
5149 }
5150 }
5151 }
5152 })
5153 .ok();
5154 })
5155 .shared(),
5156 );
5157 debug_assert!(
5158 previous_task.is_none(),
5159 "Did not change hint's resolve state after spawning its resolve"
5160 );
5161 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5162 None
5163 }
5164
5165 fn resolve_inlay_hint(
5166 &self,
5167 mut hint: InlayHint,
5168 buffer: Entity<Buffer>,
5169 server_id: LanguageServerId,
5170 cx: &mut Context<Self>,
5171 ) -> Task<anyhow::Result<InlayHint>> {
5172 if let Some((upstream_client, project_id)) = self.upstream_client() {
5173 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5174 {
5175 hint.resolve_state = ResolveState::Resolved;
5176 return Task::ready(Ok(hint));
5177 }
5178 let request = proto::ResolveInlayHint {
5179 project_id,
5180 buffer_id: buffer.read(cx).remote_id().into(),
5181 language_server_id: server_id.0 as u64,
5182 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5183 };
5184 cx.background_spawn(async move {
5185 let response = upstream_client
5186 .request(request)
5187 .await
5188 .context("inlay hints proto request")?;
5189 match response.hint {
5190 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5191 .context("inlay hints proto resolve response conversion"),
5192 None => Ok(hint),
5193 }
5194 })
5195 } else {
5196 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5197 self.language_server_for_local_buffer(buffer, server_id, cx)
5198 .map(|(_, server)| server.clone())
5199 }) else {
5200 return Task::ready(Ok(hint));
5201 };
5202 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5203 return Task::ready(Ok(hint));
5204 }
5205 let buffer_snapshot = buffer.read(cx).snapshot();
5206 cx.spawn(async move |_, cx| {
5207 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5208 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5209 );
5210 let resolved_hint = resolve_task
5211 .await
5212 .into_response()
5213 .context("inlay hint resolve LSP request")?;
5214 let resolved_hint = InlayHints::lsp_to_project_hint(
5215 resolved_hint,
5216 &buffer,
5217 server_id,
5218 ResolveState::Resolved,
5219 false,
5220 cx,
5221 )
5222 .await?;
5223 Ok(resolved_hint)
5224 })
5225 }
5226 }
5227
5228 pub fn resolve_color_presentation(
5229 &mut self,
5230 mut color: DocumentColor,
5231 buffer: Entity<Buffer>,
5232 server_id: LanguageServerId,
5233 cx: &mut Context<Self>,
5234 ) -> Task<Result<DocumentColor>> {
5235 if color.resolved {
5236 return Task::ready(Ok(color));
5237 }
5238
5239 if let Some((upstream_client, project_id)) = self.upstream_client() {
5240 let start = color.lsp_range.start;
5241 let end = color.lsp_range.end;
5242 let request = proto::GetColorPresentation {
5243 project_id,
5244 server_id: server_id.to_proto(),
5245 buffer_id: buffer.read(cx).remote_id().into(),
5246 color: Some(proto::ColorInformation {
5247 red: color.color.red,
5248 green: color.color.green,
5249 blue: color.color.blue,
5250 alpha: color.color.alpha,
5251 lsp_range_start: Some(proto::PointUtf16 {
5252 row: start.line,
5253 column: start.character,
5254 }),
5255 lsp_range_end: Some(proto::PointUtf16 {
5256 row: end.line,
5257 column: end.character,
5258 }),
5259 }),
5260 };
5261 cx.background_spawn(async move {
5262 let response = upstream_client
5263 .request(request)
5264 .await
5265 .context("color presentation proto request")?;
5266 color.resolved = true;
5267 color.color_presentations = response
5268 .presentations
5269 .into_iter()
5270 .map(|presentation| ColorPresentation {
5271 label: SharedString::from(presentation.label),
5272 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5273 additional_text_edits: presentation
5274 .additional_text_edits
5275 .into_iter()
5276 .filter_map(deserialize_lsp_edit)
5277 .collect(),
5278 })
5279 .collect();
5280 Ok(color)
5281 })
5282 } else {
5283 let path = match buffer
5284 .update(cx, |buffer, cx| {
5285 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5286 })
5287 .context("buffer with the missing path")
5288 {
5289 Ok(path) => path,
5290 Err(e) => return Task::ready(Err(e)),
5291 };
5292 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5293 self.language_server_for_local_buffer(buffer, server_id, cx)
5294 .map(|(_, server)| server.clone())
5295 }) else {
5296 return Task::ready(Ok(color));
5297 };
5298 cx.background_spawn(async move {
5299 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5300 lsp::ColorPresentationParams {
5301 text_document: make_text_document_identifier(&path)?,
5302 color: color.color,
5303 range: color.lsp_range,
5304 work_done_progress_params: Default::default(),
5305 partial_result_params: Default::default(),
5306 },
5307 );
5308 color.color_presentations = resolve_task
5309 .await
5310 .into_response()
5311 .context("color presentation resolve LSP request")?
5312 .into_iter()
5313 .map(|presentation| ColorPresentation {
5314 label: SharedString::from(presentation.label),
5315 text_edit: presentation.text_edit,
5316 additional_text_edits: presentation
5317 .additional_text_edits
5318 .unwrap_or_default(),
5319 })
5320 .collect();
5321 color.resolved = true;
5322 Ok(color)
5323 })
5324 }
5325 }
5326
5327 pub(crate) fn linked_edits(
5328 &mut self,
5329 buffer: &Entity<Buffer>,
5330 position: Anchor,
5331 cx: &mut Context<Self>,
5332 ) -> Task<Result<Vec<Range<Anchor>>>> {
5333 let snapshot = buffer.read(cx).snapshot();
5334 let scope = snapshot.language_scope_at(position);
5335 let Some(server_id) = self
5336 .as_local()
5337 .and_then(|local| {
5338 buffer.update(cx, |buffer, cx| {
5339 local
5340 .language_servers_for_buffer(buffer, cx)
5341 .filter(|(_, server)| {
5342 LinkedEditingRange::check_server_capabilities(server.capabilities())
5343 })
5344 .filter(|(adapter, _)| {
5345 scope
5346 .as_ref()
5347 .map(|scope| scope.language_allowed(&adapter.name))
5348 .unwrap_or(true)
5349 })
5350 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5351 .next()
5352 })
5353 })
5354 .or_else(|| {
5355 self.upstream_client()
5356 .is_some()
5357 .then_some(LanguageServerToQuery::FirstCapable)
5358 })
5359 .filter(|_| {
5360 maybe!({
5361 let language = buffer.read(cx).language_at(position)?;
5362 Some(
5363 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5364 .linked_edits,
5365 )
5366 }) == Some(true)
5367 })
5368 else {
5369 return Task::ready(Ok(Vec::new()));
5370 };
5371
5372 self.request_lsp(
5373 buffer.clone(),
5374 server_id,
5375 LinkedEditingRange { position },
5376 cx,
5377 )
5378 }
5379
5380 fn apply_on_type_formatting(
5381 &mut self,
5382 buffer: Entity<Buffer>,
5383 position: Anchor,
5384 trigger: String,
5385 cx: &mut Context<Self>,
5386 ) -> Task<Result<Option<Transaction>>> {
5387 if let Some((client, project_id)) = self.upstream_client() {
5388 if !self.check_if_capable_for_proto_request(
5389 &buffer,
5390 |capabilities| {
5391 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5392 },
5393 cx,
5394 ) {
5395 return Task::ready(Ok(None));
5396 }
5397 let request = proto::OnTypeFormatting {
5398 project_id,
5399 buffer_id: buffer.read(cx).remote_id().into(),
5400 position: Some(serialize_anchor(&position)),
5401 trigger,
5402 version: serialize_version(&buffer.read(cx).version()),
5403 };
5404 cx.background_spawn(async move {
5405 client
5406 .request(request)
5407 .await?
5408 .transaction
5409 .map(language::proto::deserialize_transaction)
5410 .transpose()
5411 })
5412 } else if let Some(local) = self.as_local_mut() {
5413 let buffer_id = buffer.read(cx).remote_id();
5414 local.buffers_being_formatted.insert(buffer_id);
5415 cx.spawn(async move |this, cx| {
5416 let _cleanup = defer({
5417 let this = this.clone();
5418 let mut cx = cx.clone();
5419 move || {
5420 this.update(&mut cx, |this, _| {
5421 if let Some(local) = this.as_local_mut() {
5422 local.buffers_being_formatted.remove(&buffer_id);
5423 }
5424 })
5425 .ok();
5426 }
5427 });
5428
5429 buffer
5430 .update(cx, |buffer, _| {
5431 buffer.wait_for_edits(Some(position.timestamp))
5432 })?
5433 .await?;
5434 this.update(cx, |this, cx| {
5435 let position = position.to_point_utf16(buffer.read(cx));
5436 this.on_type_format(buffer, position, trigger, false, cx)
5437 })?
5438 .await
5439 })
5440 } else {
5441 Task::ready(Err(anyhow!("No upstream client or local language server")))
5442 }
5443 }
5444
5445 pub fn on_type_format<T: ToPointUtf16>(
5446 &mut self,
5447 buffer: Entity<Buffer>,
5448 position: T,
5449 trigger: String,
5450 push_to_history: bool,
5451 cx: &mut Context<Self>,
5452 ) -> Task<Result<Option<Transaction>>> {
5453 let position = position.to_point_utf16(buffer.read(cx));
5454 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5455 }
5456
5457 fn on_type_format_impl(
5458 &mut self,
5459 buffer: Entity<Buffer>,
5460 position: PointUtf16,
5461 trigger: String,
5462 push_to_history: bool,
5463 cx: &mut Context<Self>,
5464 ) -> Task<Result<Option<Transaction>>> {
5465 let options = buffer.update(cx, |buffer, cx| {
5466 lsp_command::lsp_formatting_options(
5467 language_settings(
5468 buffer.language_at(position).map(|l| l.name()),
5469 buffer.file(),
5470 cx,
5471 )
5472 .as_ref(),
5473 )
5474 });
5475
5476 cx.spawn(async move |this, cx| {
5477 if let Some(waiter) =
5478 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5479 {
5480 waiter.await?;
5481 }
5482 cx.update(|cx| {
5483 this.update(cx, |this, cx| {
5484 this.request_lsp(
5485 buffer.clone(),
5486 LanguageServerToQuery::FirstCapable,
5487 OnTypeFormatting {
5488 position,
5489 trigger,
5490 options,
5491 push_to_history,
5492 },
5493 cx,
5494 )
5495 })
5496 })??
5497 .await
5498 })
5499 }
5500
5501 pub fn definitions(
5502 &mut self,
5503 buffer: &Entity<Buffer>,
5504 position: PointUtf16,
5505 cx: &mut Context<Self>,
5506 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5507 if let Some((upstream_client, project_id)) = self.upstream_client() {
5508 let request = GetDefinitions { position };
5509 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5510 return Task::ready(Ok(None));
5511 }
5512 let request_task = upstream_client.request_lsp(
5513 project_id,
5514 None,
5515 LSP_REQUEST_TIMEOUT,
5516 cx.background_executor().clone(),
5517 request.to_proto(project_id, buffer.read(cx)),
5518 );
5519 let buffer = buffer.clone();
5520 cx.spawn(async move |weak_lsp_store, cx| {
5521 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5522 return Ok(None);
5523 };
5524 let Some(responses) = request_task.await? else {
5525 return Ok(None);
5526 };
5527 let actions = join_all(responses.payload.into_iter().map(|response| {
5528 GetDefinitions { position }.response_from_proto(
5529 response.response,
5530 lsp_store.clone(),
5531 buffer.clone(),
5532 cx.clone(),
5533 )
5534 }))
5535 .await;
5536
5537 Ok(Some(
5538 actions
5539 .into_iter()
5540 .collect::<Result<Vec<Vec<_>>>>()?
5541 .into_iter()
5542 .flatten()
5543 .dedup()
5544 .collect(),
5545 ))
5546 })
5547 } else {
5548 let definitions_task = self.request_multiple_lsp_locally(
5549 buffer,
5550 Some(position),
5551 GetDefinitions { position },
5552 cx,
5553 );
5554 cx.background_spawn(async move {
5555 Ok(Some(
5556 definitions_task
5557 .await
5558 .into_iter()
5559 .flat_map(|(_, definitions)| definitions)
5560 .dedup()
5561 .collect(),
5562 ))
5563 })
5564 }
5565 }
5566
5567 pub fn declarations(
5568 &mut self,
5569 buffer: &Entity<Buffer>,
5570 position: PointUtf16,
5571 cx: &mut Context<Self>,
5572 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5573 if let Some((upstream_client, project_id)) = self.upstream_client() {
5574 let request = GetDeclarations { position };
5575 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5576 return Task::ready(Ok(None));
5577 }
5578 let request_task = upstream_client.request_lsp(
5579 project_id,
5580 None,
5581 LSP_REQUEST_TIMEOUT,
5582 cx.background_executor().clone(),
5583 request.to_proto(project_id, buffer.read(cx)),
5584 );
5585 let buffer = buffer.clone();
5586 cx.spawn(async move |weak_lsp_store, cx| {
5587 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5588 return Ok(None);
5589 };
5590 let Some(responses) = request_task.await? else {
5591 return Ok(None);
5592 };
5593 let actions = join_all(responses.payload.into_iter().map(|response| {
5594 GetDeclarations { position }.response_from_proto(
5595 response.response,
5596 lsp_store.clone(),
5597 buffer.clone(),
5598 cx.clone(),
5599 )
5600 }))
5601 .await;
5602
5603 Ok(Some(
5604 actions
5605 .into_iter()
5606 .collect::<Result<Vec<Vec<_>>>>()?
5607 .into_iter()
5608 .flatten()
5609 .dedup()
5610 .collect(),
5611 ))
5612 })
5613 } else {
5614 let declarations_task = self.request_multiple_lsp_locally(
5615 buffer,
5616 Some(position),
5617 GetDeclarations { position },
5618 cx,
5619 );
5620 cx.background_spawn(async move {
5621 Ok(Some(
5622 declarations_task
5623 .await
5624 .into_iter()
5625 .flat_map(|(_, declarations)| declarations)
5626 .dedup()
5627 .collect(),
5628 ))
5629 })
5630 }
5631 }
5632
5633 pub fn type_definitions(
5634 &mut self,
5635 buffer: &Entity<Buffer>,
5636 position: PointUtf16,
5637 cx: &mut Context<Self>,
5638 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5639 if let Some((upstream_client, project_id)) = self.upstream_client() {
5640 let request = GetTypeDefinitions { position };
5641 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5642 return Task::ready(Ok(None));
5643 }
5644 let request_task = upstream_client.request_lsp(
5645 project_id,
5646 None,
5647 LSP_REQUEST_TIMEOUT,
5648 cx.background_executor().clone(),
5649 request.to_proto(project_id, buffer.read(cx)),
5650 );
5651 let buffer = buffer.clone();
5652 cx.spawn(async move |weak_lsp_store, cx| {
5653 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5654 return Ok(None);
5655 };
5656 let Some(responses) = request_task.await? else {
5657 return Ok(None);
5658 };
5659 let actions = join_all(responses.payload.into_iter().map(|response| {
5660 GetTypeDefinitions { position }.response_from_proto(
5661 response.response,
5662 lsp_store.clone(),
5663 buffer.clone(),
5664 cx.clone(),
5665 )
5666 }))
5667 .await;
5668
5669 Ok(Some(
5670 actions
5671 .into_iter()
5672 .collect::<Result<Vec<Vec<_>>>>()?
5673 .into_iter()
5674 .flatten()
5675 .dedup()
5676 .collect(),
5677 ))
5678 })
5679 } else {
5680 let type_definitions_task = self.request_multiple_lsp_locally(
5681 buffer,
5682 Some(position),
5683 GetTypeDefinitions { position },
5684 cx,
5685 );
5686 cx.background_spawn(async move {
5687 Ok(Some(
5688 type_definitions_task
5689 .await
5690 .into_iter()
5691 .flat_map(|(_, type_definitions)| type_definitions)
5692 .dedup()
5693 .collect(),
5694 ))
5695 })
5696 }
5697 }
5698
5699 pub fn implementations(
5700 &mut self,
5701 buffer: &Entity<Buffer>,
5702 position: PointUtf16,
5703 cx: &mut Context<Self>,
5704 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5705 if let Some((upstream_client, project_id)) = self.upstream_client() {
5706 let request = GetImplementations { position };
5707 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5708 return Task::ready(Ok(None));
5709 }
5710 let request_task = upstream_client.request_lsp(
5711 project_id,
5712 None,
5713 LSP_REQUEST_TIMEOUT,
5714 cx.background_executor().clone(),
5715 request.to_proto(project_id, buffer.read(cx)),
5716 );
5717 let buffer = buffer.clone();
5718 cx.spawn(async move |weak_lsp_store, cx| {
5719 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5720 return Ok(None);
5721 };
5722 let Some(responses) = request_task.await? else {
5723 return Ok(None);
5724 };
5725 let actions = join_all(responses.payload.into_iter().map(|response| {
5726 GetImplementations { position }.response_from_proto(
5727 response.response,
5728 lsp_store.clone(),
5729 buffer.clone(),
5730 cx.clone(),
5731 )
5732 }))
5733 .await;
5734
5735 Ok(Some(
5736 actions
5737 .into_iter()
5738 .collect::<Result<Vec<Vec<_>>>>()?
5739 .into_iter()
5740 .flatten()
5741 .dedup()
5742 .collect(),
5743 ))
5744 })
5745 } else {
5746 let implementations_task = self.request_multiple_lsp_locally(
5747 buffer,
5748 Some(position),
5749 GetImplementations { position },
5750 cx,
5751 );
5752 cx.background_spawn(async move {
5753 Ok(Some(
5754 implementations_task
5755 .await
5756 .into_iter()
5757 .flat_map(|(_, implementations)| implementations)
5758 .dedup()
5759 .collect(),
5760 ))
5761 })
5762 }
5763 }
5764
5765 pub fn references(
5766 &mut self,
5767 buffer: &Entity<Buffer>,
5768 position: PointUtf16,
5769 cx: &mut Context<Self>,
5770 ) -> Task<Result<Option<Vec<Location>>>> {
5771 if let Some((upstream_client, project_id)) = self.upstream_client() {
5772 let request = GetReferences { position };
5773 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5774 return Task::ready(Ok(None));
5775 }
5776
5777 let request_task = upstream_client.request_lsp(
5778 project_id,
5779 None,
5780 LSP_REQUEST_TIMEOUT,
5781 cx.background_executor().clone(),
5782 request.to_proto(project_id, buffer.read(cx)),
5783 );
5784 let buffer = buffer.clone();
5785 cx.spawn(async move |weak_lsp_store, cx| {
5786 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5787 return Ok(None);
5788 };
5789 let Some(responses) = request_task.await? else {
5790 return Ok(None);
5791 };
5792
5793 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5794 GetReferences { position }.response_from_proto(
5795 lsp_response.response,
5796 lsp_store.clone(),
5797 buffer.clone(),
5798 cx.clone(),
5799 )
5800 }))
5801 .await
5802 .into_iter()
5803 .collect::<Result<Vec<Vec<_>>>>()?
5804 .into_iter()
5805 .flatten()
5806 .dedup()
5807 .collect();
5808 Ok(Some(locations))
5809 })
5810 } else {
5811 let references_task = self.request_multiple_lsp_locally(
5812 buffer,
5813 Some(position),
5814 GetReferences { position },
5815 cx,
5816 );
5817 cx.background_spawn(async move {
5818 Ok(Some(
5819 references_task
5820 .await
5821 .into_iter()
5822 .flat_map(|(_, references)| references)
5823 .dedup()
5824 .collect(),
5825 ))
5826 })
5827 }
5828 }
5829
5830 pub fn code_actions(
5831 &mut self,
5832 buffer: &Entity<Buffer>,
5833 range: Range<Anchor>,
5834 kinds: Option<Vec<CodeActionKind>>,
5835 cx: &mut Context<Self>,
5836 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5837 if let Some((upstream_client, project_id)) = self.upstream_client() {
5838 let request = GetCodeActions {
5839 range: range.clone(),
5840 kinds: kinds.clone(),
5841 };
5842 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5843 return Task::ready(Ok(None));
5844 }
5845 let request_task = upstream_client.request_lsp(
5846 project_id,
5847 None,
5848 LSP_REQUEST_TIMEOUT,
5849 cx.background_executor().clone(),
5850 request.to_proto(project_id, buffer.read(cx)),
5851 );
5852 let buffer = buffer.clone();
5853 cx.spawn(async move |weak_lsp_store, cx| {
5854 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5855 return Ok(None);
5856 };
5857 let Some(responses) = request_task.await? else {
5858 return Ok(None);
5859 };
5860 let actions = join_all(responses.payload.into_iter().map(|response| {
5861 GetCodeActions {
5862 range: range.clone(),
5863 kinds: kinds.clone(),
5864 }
5865 .response_from_proto(
5866 response.response,
5867 lsp_store.clone(),
5868 buffer.clone(),
5869 cx.clone(),
5870 )
5871 }))
5872 .await;
5873
5874 Ok(Some(
5875 actions
5876 .into_iter()
5877 .collect::<Result<Vec<Vec<_>>>>()?
5878 .into_iter()
5879 .flatten()
5880 .collect(),
5881 ))
5882 })
5883 } else {
5884 let all_actions_task = self.request_multiple_lsp_locally(
5885 buffer,
5886 Some(range.start),
5887 GetCodeActions { range, kinds },
5888 cx,
5889 );
5890 cx.background_spawn(async move {
5891 Ok(Some(
5892 all_actions_task
5893 .await
5894 .into_iter()
5895 .flat_map(|(_, actions)| actions)
5896 .collect(),
5897 ))
5898 })
5899 }
5900 }
5901
5902 pub fn code_lens_actions(
5903 &mut self,
5904 buffer: &Entity<Buffer>,
5905 cx: &mut Context<Self>,
5906 ) -> CodeLensTask {
5907 let version_queried_for = buffer.read(cx).version();
5908 let buffer_id = buffer.read(cx).remote_id();
5909 let existing_servers = self.as_local().map(|local| {
5910 local
5911 .buffers_opened_in_servers
5912 .get(&buffer_id)
5913 .cloned()
5914 .unwrap_or_default()
5915 });
5916
5917 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5918 if let Some(cached_lens) = &lsp_data.code_lens {
5919 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5920 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5921 existing_servers != cached_lens.lens.keys().copied().collect()
5922 });
5923 if !has_different_servers {
5924 return Task::ready(Ok(Some(
5925 cached_lens.lens.values().flatten().cloned().collect(),
5926 )))
5927 .shared();
5928 }
5929 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5930 if !version_queried_for.changed_since(updating_for) {
5931 return running_update.clone();
5932 }
5933 }
5934 }
5935 }
5936
5937 let lens_lsp_data = self
5938 .latest_lsp_data(buffer, cx)
5939 .code_lens
5940 .get_or_insert_default();
5941 let buffer = buffer.clone();
5942 let query_version_queried_for = version_queried_for.clone();
5943 let new_task = cx
5944 .spawn(async move |lsp_store, cx| {
5945 cx.background_executor()
5946 .timer(Duration::from_millis(30))
5947 .await;
5948 let fetched_lens = lsp_store
5949 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5950 .map_err(Arc::new)?
5951 .await
5952 .context("fetching code lens")
5953 .map_err(Arc::new);
5954 let fetched_lens = match fetched_lens {
5955 Ok(fetched_lens) => fetched_lens,
5956 Err(e) => {
5957 lsp_store
5958 .update(cx, |lsp_store, _| {
5959 if let Some(lens_lsp_data) = lsp_store
5960 .lsp_data
5961 .get_mut(&buffer_id)
5962 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5963 {
5964 lens_lsp_data.update = None;
5965 }
5966 })
5967 .ok();
5968 return Err(e);
5969 }
5970 };
5971
5972 lsp_store
5973 .update(cx, |lsp_store, _| {
5974 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5975 let code_lens = lsp_data.code_lens.as_mut()?;
5976 if let Some(fetched_lens) = fetched_lens {
5977 if lsp_data.buffer_version == query_version_queried_for {
5978 code_lens.lens.extend(fetched_lens);
5979 } else if !lsp_data
5980 .buffer_version
5981 .changed_since(&query_version_queried_for)
5982 {
5983 lsp_data.buffer_version = query_version_queried_for;
5984 code_lens.lens = fetched_lens;
5985 }
5986 }
5987 code_lens.update = None;
5988 Some(code_lens.lens.values().flatten().cloned().collect())
5989 })
5990 .map_err(Arc::new)
5991 })
5992 .shared();
5993 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5994 new_task
5995 }
5996
5997 fn fetch_code_lens(
5998 &mut self,
5999 buffer: &Entity<Buffer>,
6000 cx: &mut Context<Self>,
6001 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6002 if let Some((upstream_client, project_id)) = self.upstream_client() {
6003 let request = GetCodeLens;
6004 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6005 return Task::ready(Ok(None));
6006 }
6007 let request_task = upstream_client.request_lsp(
6008 project_id,
6009 None,
6010 LSP_REQUEST_TIMEOUT,
6011 cx.background_executor().clone(),
6012 request.to_proto(project_id, buffer.read(cx)),
6013 );
6014 let buffer = buffer.clone();
6015 cx.spawn(async move |weak_lsp_store, cx| {
6016 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6017 return Ok(None);
6018 };
6019 let Some(responses) = request_task.await? else {
6020 return Ok(None);
6021 };
6022
6023 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6024 let lsp_store = lsp_store.clone();
6025 let buffer = buffer.clone();
6026 let cx = cx.clone();
6027 async move {
6028 (
6029 LanguageServerId::from_proto(response.server_id),
6030 GetCodeLens
6031 .response_from_proto(response.response, lsp_store, buffer, cx)
6032 .await,
6033 )
6034 }
6035 }))
6036 .await;
6037
6038 let mut has_errors = false;
6039 let code_lens_actions = code_lens_actions
6040 .into_iter()
6041 .filter_map(|(server_id, code_lens)| match code_lens {
6042 Ok(code_lens) => Some((server_id, code_lens)),
6043 Err(e) => {
6044 has_errors = true;
6045 log::error!("{e:#}");
6046 None
6047 }
6048 })
6049 .collect::<HashMap<_, _>>();
6050 anyhow::ensure!(
6051 !has_errors || !code_lens_actions.is_empty(),
6052 "Failed to fetch code lens"
6053 );
6054 Ok(Some(code_lens_actions))
6055 })
6056 } else {
6057 let code_lens_actions_task =
6058 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6059 cx.background_spawn(async move {
6060 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6061 })
6062 }
6063 }
6064
6065 #[inline(never)]
6066 pub fn completions(
6067 &self,
6068 buffer: &Entity<Buffer>,
6069 position: PointUtf16,
6070 context: CompletionContext,
6071 cx: &mut Context<Self>,
6072 ) -> Task<Result<Vec<CompletionResponse>>> {
6073 let language_registry = self.languages.clone();
6074
6075 if let Some((upstream_client, project_id)) = self.upstream_client() {
6076 let snapshot = buffer.read(cx).snapshot();
6077 let offset = position.to_offset(&snapshot);
6078 let scope = snapshot.language_scope_at(offset);
6079 let capable_lsps = self.all_capable_for_proto_request(
6080 buffer,
6081 |server_name, capabilities| {
6082 capabilities.completion_provider.is_some()
6083 && scope
6084 .as_ref()
6085 .map(|scope| scope.language_allowed(server_name))
6086 .unwrap_or(true)
6087 },
6088 cx,
6089 );
6090 if capable_lsps.is_empty() {
6091 return Task::ready(Ok(Vec::new()));
6092 }
6093
6094 let language = buffer.read(cx).language().cloned();
6095
6096 // In the future, we should provide project guests with the names of LSP adapters,
6097 // so that they can use the correct LSP adapter when computing labels. For now,
6098 // guests just use the first LSP adapter associated with the buffer's language.
6099 let lsp_adapter = language.as_ref().and_then(|language| {
6100 language_registry
6101 .lsp_adapters(&language.name())
6102 .first()
6103 .cloned()
6104 });
6105
6106 let buffer = buffer.clone();
6107
6108 cx.spawn(async move |this, cx| {
6109 let requests = join_all(
6110 capable_lsps
6111 .into_iter()
6112 .map(|id| {
6113 let request = GetCompletions {
6114 position,
6115 context: context.clone(),
6116 server_id: Some(id),
6117 };
6118 let buffer = buffer.clone();
6119 let language = language.clone();
6120 let lsp_adapter = lsp_adapter.clone();
6121 let upstream_client = upstream_client.clone();
6122 let response = this
6123 .update(cx, |this, cx| {
6124 this.send_lsp_proto_request(
6125 buffer,
6126 upstream_client,
6127 project_id,
6128 request,
6129 cx,
6130 )
6131 })
6132 .log_err();
6133 async move {
6134 let response = response?.await.log_err()?;
6135
6136 let completions = populate_labels_for_completions(
6137 response.completions,
6138 language,
6139 lsp_adapter,
6140 )
6141 .await;
6142
6143 Some(CompletionResponse {
6144 completions,
6145 display_options: CompletionDisplayOptions::default(),
6146 is_incomplete: response.is_incomplete,
6147 })
6148 }
6149 })
6150 .collect::<Vec<_>>(),
6151 );
6152 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6153 })
6154 } else if let Some(local) = self.as_local() {
6155 let snapshot = buffer.read(cx).snapshot();
6156 let offset = position.to_offset(&snapshot);
6157 let scope = snapshot.language_scope_at(offset);
6158 let language = snapshot.language().cloned();
6159 let completion_settings = language_settings(
6160 language.as_ref().map(|language| language.name()),
6161 buffer.read(cx).file(),
6162 cx,
6163 )
6164 .completions
6165 .clone();
6166 if !completion_settings.lsp {
6167 return Task::ready(Ok(Vec::new()));
6168 }
6169
6170 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6171 local
6172 .language_servers_for_buffer(buffer, cx)
6173 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6174 .filter(|(adapter, _)| {
6175 scope
6176 .as_ref()
6177 .map(|scope| scope.language_allowed(&adapter.name))
6178 .unwrap_or(true)
6179 })
6180 .map(|(_, server)| server.server_id())
6181 .collect()
6182 });
6183
6184 let buffer = buffer.clone();
6185 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6186 let lsp_timeout = if lsp_timeout > 0 {
6187 Some(Duration::from_millis(lsp_timeout))
6188 } else {
6189 None
6190 };
6191 cx.spawn(async move |this, cx| {
6192 let mut tasks = Vec::with_capacity(server_ids.len());
6193 this.update(cx, |lsp_store, cx| {
6194 for server_id in server_ids {
6195 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6196 let lsp_timeout = lsp_timeout
6197 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6198 let mut timeout = cx.background_spawn(async move {
6199 match lsp_timeout {
6200 Some(lsp_timeout) => {
6201 lsp_timeout.await;
6202 true
6203 },
6204 None => false,
6205 }
6206 }).fuse();
6207 let mut lsp_request = lsp_store.request_lsp(
6208 buffer.clone(),
6209 LanguageServerToQuery::Other(server_id),
6210 GetCompletions {
6211 position,
6212 context: context.clone(),
6213 server_id: Some(server_id),
6214 },
6215 cx,
6216 ).fuse();
6217 let new_task = cx.background_spawn(async move {
6218 select_biased! {
6219 response = lsp_request => anyhow::Ok(Some(response?)),
6220 timeout_happened = timeout => {
6221 if timeout_happened {
6222 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6223 Ok(None)
6224 } else {
6225 let completions = lsp_request.await?;
6226 Ok(Some(completions))
6227 }
6228 },
6229 }
6230 });
6231 tasks.push((lsp_adapter, new_task));
6232 }
6233 })?;
6234
6235 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6236 let completion_response = task.await.ok()??;
6237 let completions = populate_labels_for_completions(
6238 completion_response.completions,
6239 language.clone(),
6240 lsp_adapter,
6241 )
6242 .await;
6243 Some(CompletionResponse {
6244 completions,
6245 display_options: CompletionDisplayOptions::default(),
6246 is_incomplete: completion_response.is_incomplete,
6247 })
6248 });
6249
6250 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6251
6252 Ok(responses.into_iter().flatten().collect())
6253 })
6254 } else {
6255 Task::ready(Err(anyhow!("No upstream client or local language server")))
6256 }
6257 }
6258
6259 pub fn resolve_completions(
6260 &self,
6261 buffer: Entity<Buffer>,
6262 completion_indices: Vec<usize>,
6263 completions: Rc<RefCell<Box<[Completion]>>>,
6264 cx: &mut Context<Self>,
6265 ) -> Task<Result<bool>> {
6266 let client = self.upstream_client();
6267 let buffer_id = buffer.read(cx).remote_id();
6268 let buffer_snapshot = buffer.read(cx).snapshot();
6269
6270 if !self.check_if_capable_for_proto_request(
6271 &buffer,
6272 GetCompletions::can_resolve_completions,
6273 cx,
6274 ) {
6275 return Task::ready(Ok(false));
6276 }
6277 cx.spawn(async move |lsp_store, cx| {
6278 let mut did_resolve = false;
6279 if let Some((client, project_id)) = client {
6280 for completion_index in completion_indices {
6281 let server_id = {
6282 let completion = &completions.borrow()[completion_index];
6283 completion.source.server_id()
6284 };
6285 if let Some(server_id) = server_id {
6286 if Self::resolve_completion_remote(
6287 project_id,
6288 server_id,
6289 buffer_id,
6290 completions.clone(),
6291 completion_index,
6292 client.clone(),
6293 )
6294 .await
6295 .log_err()
6296 .is_some()
6297 {
6298 did_resolve = true;
6299 }
6300 } else {
6301 resolve_word_completion(
6302 &buffer_snapshot,
6303 &mut completions.borrow_mut()[completion_index],
6304 );
6305 }
6306 }
6307 } else {
6308 for completion_index in completion_indices {
6309 let server_id = {
6310 let completion = &completions.borrow()[completion_index];
6311 completion.source.server_id()
6312 };
6313 if let Some(server_id) = server_id {
6314 let server_and_adapter = lsp_store
6315 .read_with(cx, |lsp_store, _| {
6316 let server = lsp_store.language_server_for_id(server_id)?;
6317 let adapter =
6318 lsp_store.language_server_adapter_for_id(server.server_id())?;
6319 Some((server, adapter))
6320 })
6321 .ok()
6322 .flatten();
6323 let Some((server, adapter)) = server_and_adapter else {
6324 continue;
6325 };
6326
6327 let resolved = Self::resolve_completion_local(
6328 server,
6329 completions.clone(),
6330 completion_index,
6331 )
6332 .await
6333 .log_err()
6334 .is_some();
6335 if resolved {
6336 Self::regenerate_completion_labels(
6337 adapter,
6338 &buffer_snapshot,
6339 completions.clone(),
6340 completion_index,
6341 )
6342 .await
6343 .log_err();
6344 did_resolve = true;
6345 }
6346 } else {
6347 resolve_word_completion(
6348 &buffer_snapshot,
6349 &mut completions.borrow_mut()[completion_index],
6350 );
6351 }
6352 }
6353 }
6354
6355 Ok(did_resolve)
6356 })
6357 }
6358
6359 async fn resolve_completion_local(
6360 server: Arc<lsp::LanguageServer>,
6361 completions: Rc<RefCell<Box<[Completion]>>>,
6362 completion_index: usize,
6363 ) -> Result<()> {
6364 let server_id = server.server_id();
6365 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6366 return Ok(());
6367 }
6368
6369 let request = {
6370 let completion = &completions.borrow()[completion_index];
6371 match &completion.source {
6372 CompletionSource::Lsp {
6373 lsp_completion,
6374 resolved,
6375 server_id: completion_server_id,
6376 ..
6377 } => {
6378 if *resolved {
6379 return Ok(());
6380 }
6381 anyhow::ensure!(
6382 server_id == *completion_server_id,
6383 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6384 );
6385 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6386 }
6387 CompletionSource::BufferWord { .. }
6388 | CompletionSource::Dap { .. }
6389 | CompletionSource::Custom => {
6390 return Ok(());
6391 }
6392 }
6393 };
6394 let resolved_completion = request
6395 .await
6396 .into_response()
6397 .context("resolve completion")?;
6398
6399 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6400 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6401
6402 let mut completions = completions.borrow_mut();
6403 let completion = &mut completions[completion_index];
6404 if let CompletionSource::Lsp {
6405 lsp_completion,
6406 resolved,
6407 server_id: completion_server_id,
6408 ..
6409 } = &mut completion.source
6410 {
6411 if *resolved {
6412 return Ok(());
6413 }
6414 anyhow::ensure!(
6415 server_id == *completion_server_id,
6416 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6417 );
6418 *lsp_completion = Box::new(resolved_completion);
6419 *resolved = true;
6420 }
6421 Ok(())
6422 }
6423
6424 async fn regenerate_completion_labels(
6425 adapter: Arc<CachedLspAdapter>,
6426 snapshot: &BufferSnapshot,
6427 completions: Rc<RefCell<Box<[Completion]>>>,
6428 completion_index: usize,
6429 ) -> Result<()> {
6430 let completion_item = completions.borrow()[completion_index]
6431 .source
6432 .lsp_completion(true)
6433 .map(Cow::into_owned);
6434 if let Some(lsp_documentation) = completion_item
6435 .as_ref()
6436 .and_then(|completion_item| completion_item.documentation.clone())
6437 {
6438 let mut completions = completions.borrow_mut();
6439 let completion = &mut completions[completion_index];
6440 completion.documentation = Some(lsp_documentation.into());
6441 } else {
6442 let mut completions = completions.borrow_mut();
6443 let completion = &mut completions[completion_index];
6444 completion.documentation = Some(CompletionDocumentation::Undocumented);
6445 }
6446
6447 let mut new_label = match completion_item {
6448 Some(completion_item) => {
6449 // 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
6450 // So we have to update the label here anyway...
6451 let language = snapshot.language();
6452 match language {
6453 Some(language) => {
6454 adapter
6455 .labels_for_completions(
6456 std::slice::from_ref(&completion_item),
6457 language,
6458 )
6459 .await?
6460 }
6461 None => Vec::new(),
6462 }
6463 .pop()
6464 .flatten()
6465 .unwrap_or_else(|| {
6466 CodeLabel::fallback_for_completion(
6467 &completion_item,
6468 language.map(|language| language.as_ref()),
6469 )
6470 })
6471 }
6472 None => CodeLabel::plain(
6473 completions.borrow()[completion_index].new_text.clone(),
6474 None,
6475 ),
6476 };
6477 ensure_uniform_list_compatible_label(&mut new_label);
6478
6479 let mut completions = completions.borrow_mut();
6480 let completion = &mut completions[completion_index];
6481 if completion.label.filter_text() == new_label.filter_text() {
6482 completion.label = new_label;
6483 } else {
6484 log::error!(
6485 "Resolved completion changed display label from {} to {}. \
6486 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6487 completion.label.text(),
6488 new_label.text(),
6489 completion.label.filter_text(),
6490 new_label.filter_text()
6491 );
6492 }
6493
6494 Ok(())
6495 }
6496
6497 async fn resolve_completion_remote(
6498 project_id: u64,
6499 server_id: LanguageServerId,
6500 buffer_id: BufferId,
6501 completions: Rc<RefCell<Box<[Completion]>>>,
6502 completion_index: usize,
6503 client: AnyProtoClient,
6504 ) -> Result<()> {
6505 let lsp_completion = {
6506 let completion = &completions.borrow()[completion_index];
6507 match &completion.source {
6508 CompletionSource::Lsp {
6509 lsp_completion,
6510 resolved,
6511 server_id: completion_server_id,
6512 ..
6513 } => {
6514 anyhow::ensure!(
6515 server_id == *completion_server_id,
6516 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6517 );
6518 if *resolved {
6519 return Ok(());
6520 }
6521 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6522 }
6523 CompletionSource::Custom
6524 | CompletionSource::Dap { .. }
6525 | CompletionSource::BufferWord { .. } => {
6526 return Ok(());
6527 }
6528 }
6529 };
6530 let request = proto::ResolveCompletionDocumentation {
6531 project_id,
6532 language_server_id: server_id.0 as u64,
6533 lsp_completion,
6534 buffer_id: buffer_id.into(),
6535 };
6536
6537 let response = client
6538 .request(request)
6539 .await
6540 .context("completion documentation resolve proto request")?;
6541 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6542
6543 let documentation = if response.documentation.is_empty() {
6544 CompletionDocumentation::Undocumented
6545 } else if response.documentation_is_markdown {
6546 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6547 } else if response.documentation.lines().count() <= 1 {
6548 CompletionDocumentation::SingleLine(response.documentation.into())
6549 } else {
6550 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6551 };
6552
6553 let mut completions = completions.borrow_mut();
6554 let completion = &mut completions[completion_index];
6555 completion.documentation = Some(documentation);
6556 if let CompletionSource::Lsp {
6557 insert_range,
6558 lsp_completion,
6559 resolved,
6560 server_id: completion_server_id,
6561 lsp_defaults: _,
6562 } = &mut completion.source
6563 {
6564 let completion_insert_range = response
6565 .old_insert_start
6566 .and_then(deserialize_anchor)
6567 .zip(response.old_insert_end.and_then(deserialize_anchor));
6568 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6569
6570 if *resolved {
6571 return Ok(());
6572 }
6573 anyhow::ensure!(
6574 server_id == *completion_server_id,
6575 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6576 );
6577 *lsp_completion = Box::new(resolved_lsp_completion);
6578 *resolved = true;
6579 }
6580
6581 let replace_range = response
6582 .old_replace_start
6583 .and_then(deserialize_anchor)
6584 .zip(response.old_replace_end.and_then(deserialize_anchor));
6585 if let Some((old_replace_start, old_replace_end)) = replace_range
6586 && !response.new_text.is_empty()
6587 {
6588 completion.new_text = response.new_text;
6589 completion.replace_range = old_replace_start..old_replace_end;
6590 }
6591
6592 Ok(())
6593 }
6594
6595 pub fn apply_additional_edits_for_completion(
6596 &self,
6597 buffer_handle: Entity<Buffer>,
6598 completions: Rc<RefCell<Box<[Completion]>>>,
6599 completion_index: usize,
6600 push_to_history: bool,
6601 cx: &mut Context<Self>,
6602 ) -> Task<Result<Option<Transaction>>> {
6603 if let Some((client, project_id)) = self.upstream_client() {
6604 let buffer = buffer_handle.read(cx);
6605 let buffer_id = buffer.remote_id();
6606 cx.spawn(async move |_, cx| {
6607 let request = {
6608 let completion = completions.borrow()[completion_index].clone();
6609 proto::ApplyCompletionAdditionalEdits {
6610 project_id,
6611 buffer_id: buffer_id.into(),
6612 completion: Some(Self::serialize_completion(&CoreCompletion {
6613 replace_range: completion.replace_range,
6614 new_text: completion.new_text,
6615 source: completion.source,
6616 })),
6617 }
6618 };
6619
6620 if let Some(transaction) = client.request(request).await?.transaction {
6621 let transaction = language::proto::deserialize_transaction(transaction)?;
6622 buffer_handle
6623 .update(cx, |buffer, _| {
6624 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6625 })?
6626 .await?;
6627 if push_to_history {
6628 buffer_handle.update(cx, |buffer, _| {
6629 buffer.push_transaction(transaction.clone(), Instant::now());
6630 buffer.finalize_last_transaction();
6631 })?;
6632 }
6633 Ok(Some(transaction))
6634 } else {
6635 Ok(None)
6636 }
6637 })
6638 } else {
6639 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6640 let completion = &completions.borrow()[completion_index];
6641 let server_id = completion.source.server_id()?;
6642 Some(
6643 self.language_server_for_local_buffer(buffer, server_id, cx)?
6644 .1
6645 .clone(),
6646 )
6647 }) else {
6648 return Task::ready(Ok(None));
6649 };
6650
6651 cx.spawn(async move |this, cx| {
6652 Self::resolve_completion_local(
6653 server.clone(),
6654 completions.clone(),
6655 completion_index,
6656 )
6657 .await
6658 .context("resolving completion")?;
6659 let completion = completions.borrow()[completion_index].clone();
6660 let additional_text_edits = completion
6661 .source
6662 .lsp_completion(true)
6663 .as_ref()
6664 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6665 if let Some(edits) = additional_text_edits {
6666 let edits = this
6667 .update(cx, |this, cx| {
6668 this.as_local_mut().unwrap().edits_from_lsp(
6669 &buffer_handle,
6670 edits,
6671 server.server_id(),
6672 None,
6673 cx,
6674 )
6675 })?
6676 .await?;
6677
6678 buffer_handle.update(cx, |buffer, cx| {
6679 buffer.finalize_last_transaction();
6680 buffer.start_transaction();
6681
6682 for (range, text) in edits {
6683 let primary = &completion.replace_range;
6684
6685 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6686 // and the primary completion is just an insertion (empty range), then this is likely
6687 // an auto-import scenario and should not be considered overlapping
6688 // https://github.com/zed-industries/zed/issues/26136
6689 let is_file_start_auto_import = {
6690 let snapshot = buffer.snapshot();
6691 let primary_start_point = primary.start.to_point(&snapshot);
6692 let range_start_point = range.start.to_point(&snapshot);
6693
6694 let result = primary_start_point.row == 0
6695 && primary_start_point.column == 0
6696 && range_start_point.row == 0
6697 && range_start_point.column == 0;
6698
6699 result
6700 };
6701
6702 let has_overlap = if is_file_start_auto_import {
6703 false
6704 } else {
6705 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6706 && primary.end.cmp(&range.start, buffer).is_ge();
6707 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6708 && range.end.cmp(&primary.end, buffer).is_ge();
6709 let result = start_within || end_within;
6710 result
6711 };
6712
6713 //Skip additional edits which overlap with the primary completion edit
6714 //https://github.com/zed-industries/zed/pull/1871
6715 if !has_overlap {
6716 buffer.edit([(range, text)], None, cx);
6717 }
6718 }
6719
6720 let transaction = if buffer.end_transaction(cx).is_some() {
6721 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6722 if !push_to_history {
6723 buffer.forget_transaction(transaction.id);
6724 }
6725 Some(transaction)
6726 } else {
6727 None
6728 };
6729 Ok(transaction)
6730 })?
6731 } else {
6732 Ok(None)
6733 }
6734 })
6735 }
6736 }
6737
6738 pub fn pull_diagnostics(
6739 &mut self,
6740 buffer: Entity<Buffer>,
6741 cx: &mut Context<Self>,
6742 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6743 let buffer_id = buffer.read(cx).remote_id();
6744
6745 if let Some((client, upstream_project_id)) = self.upstream_client() {
6746 let mut suitable_capabilities = None;
6747 // Are we capable for proto request?
6748 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6749 &buffer,
6750 |capabilities| {
6751 if let Some(caps) = &capabilities.diagnostic_provider {
6752 suitable_capabilities = Some(caps.clone());
6753 true
6754 } else {
6755 false
6756 }
6757 },
6758 cx,
6759 );
6760 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6761 let Some(dynamic_caps) = suitable_capabilities else {
6762 return Task::ready(Ok(None));
6763 };
6764 assert!(any_server_has_diagnostics_provider);
6765
6766 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6767 let request = GetDocumentDiagnostics {
6768 previous_result_id: None,
6769 identifier,
6770 registration_id: None,
6771 };
6772 let request_task = client.request_lsp(
6773 upstream_project_id,
6774 None,
6775 LSP_REQUEST_TIMEOUT,
6776 cx.background_executor().clone(),
6777 request.to_proto(upstream_project_id, buffer.read(cx)),
6778 );
6779 cx.background_spawn(async move {
6780 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6781 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6782 // Do not attempt to further process the dummy responses here.
6783 let _response = request_task.await?;
6784 Ok(None)
6785 })
6786 } else {
6787 let servers = buffer.update(cx, |buffer, cx| {
6788 self.running_language_servers_for_local_buffer(buffer, cx)
6789 .map(|(_, server)| server.clone())
6790 .collect::<Vec<_>>()
6791 });
6792
6793 let pull_diagnostics = servers
6794 .into_iter()
6795 .flat_map(|server| {
6796 let result = maybe!({
6797 let local = self.as_local()?;
6798 let server_id = server.server_id();
6799 let providers_with_identifiers = local
6800 .language_server_dynamic_registrations
6801 .get(&server_id)
6802 .into_iter()
6803 .flat_map(|registrations| registrations.diagnostics.clone())
6804 .collect::<Vec<_>>();
6805 Some(
6806 providers_with_identifiers
6807 .into_iter()
6808 .map(|(registration_id, dynamic_caps)| {
6809 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6810 let registration_id = registration_id.map(SharedString::from);
6811 let result_id = self.result_id_for_buffer_pull(
6812 server_id,
6813 buffer_id,
6814 ®istration_id,
6815 cx,
6816 );
6817 self.request_lsp(
6818 buffer.clone(),
6819 LanguageServerToQuery::Other(server_id),
6820 GetDocumentDiagnostics {
6821 previous_result_id: result_id,
6822 registration_id,
6823 identifier,
6824 },
6825 cx,
6826 )
6827 })
6828 .collect::<Vec<_>>(),
6829 )
6830 });
6831
6832 result.unwrap_or_default()
6833 })
6834 .collect::<Vec<_>>();
6835
6836 cx.background_spawn(async move {
6837 let mut responses = Vec::new();
6838 for diagnostics in join_all(pull_diagnostics).await {
6839 responses.extend(diagnostics?);
6840 }
6841 Ok(Some(responses))
6842 })
6843 }
6844 }
6845
6846 pub fn applicable_inlay_chunks(
6847 &mut self,
6848 buffer: &Entity<Buffer>,
6849 ranges: &[Range<text::Anchor>],
6850 cx: &mut Context<Self>,
6851 ) -> Vec<Range<BufferRow>> {
6852 self.latest_lsp_data(buffer, cx)
6853 .inlay_hints
6854 .applicable_chunks(ranges)
6855 .map(|chunk| chunk.row_range())
6856 .collect()
6857 }
6858
6859 pub fn invalidate_inlay_hints<'a>(
6860 &'a mut self,
6861 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6862 ) {
6863 for buffer_id in for_buffers {
6864 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6865 lsp_data.inlay_hints.clear();
6866 }
6867 }
6868 }
6869
6870 pub fn inlay_hints(
6871 &mut self,
6872 invalidate: InvalidationStrategy,
6873 buffer: Entity<Buffer>,
6874 ranges: Vec<Range<text::Anchor>>,
6875 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6876 cx: &mut Context<Self>,
6877 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6878 let next_hint_id = self.next_hint_id.clone();
6879 let lsp_data = self.latest_lsp_data(&buffer, cx);
6880 let query_version = lsp_data.buffer_version.clone();
6881 let mut lsp_refresh_requested = false;
6882 let for_server = if let InvalidationStrategy::RefreshRequested {
6883 server_id,
6884 request_id,
6885 } = invalidate
6886 {
6887 let invalidated = lsp_data
6888 .inlay_hints
6889 .invalidate_for_server_refresh(server_id, request_id);
6890 lsp_refresh_requested = invalidated;
6891 Some(server_id)
6892 } else {
6893 None
6894 };
6895 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6896 let known_chunks = known_chunks
6897 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6898 .map(|(_, known_chunks)| known_chunks)
6899 .unwrap_or_default();
6900
6901 let mut hint_fetch_tasks = Vec::new();
6902 let mut cached_inlay_hints = None;
6903 let mut ranges_to_query = None;
6904 let applicable_chunks = existing_inlay_hints
6905 .applicable_chunks(ranges.as_slice())
6906 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6907 .collect::<Vec<_>>();
6908 if applicable_chunks.is_empty() {
6909 return HashMap::default();
6910 }
6911
6912 for row_chunk in applicable_chunks {
6913 match (
6914 existing_inlay_hints
6915 .cached_hints(&row_chunk)
6916 .filter(|_| !lsp_refresh_requested)
6917 .cloned(),
6918 existing_inlay_hints
6919 .fetched_hints(&row_chunk)
6920 .as_ref()
6921 .filter(|_| !lsp_refresh_requested)
6922 .cloned(),
6923 ) {
6924 (None, None) => {
6925 let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
6926 continue;
6927 };
6928 ranges_to_query
6929 .get_or_insert_with(Vec::new)
6930 .push((row_chunk, chunk_range));
6931 }
6932 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6933 (Some(cached_hints), None) => {
6934 for (server_id, cached_hints) in cached_hints {
6935 if for_server.is_none_or(|for_server| for_server == server_id) {
6936 cached_inlay_hints
6937 .get_or_insert_with(HashMap::default)
6938 .entry(row_chunk.row_range())
6939 .or_insert_with(HashMap::default)
6940 .entry(server_id)
6941 .or_insert_with(Vec::new)
6942 .extend(cached_hints);
6943 }
6944 }
6945 }
6946 (Some(cached_hints), Some(fetched_hints)) => {
6947 hint_fetch_tasks.push((row_chunk, fetched_hints));
6948 for (server_id, cached_hints) in cached_hints {
6949 if for_server.is_none_or(|for_server| for_server == server_id) {
6950 cached_inlay_hints
6951 .get_or_insert_with(HashMap::default)
6952 .entry(row_chunk.row_range())
6953 .or_insert_with(HashMap::default)
6954 .entry(server_id)
6955 .or_insert_with(Vec::new)
6956 .extend(cached_hints);
6957 }
6958 }
6959 }
6960 }
6961 }
6962
6963 if hint_fetch_tasks.is_empty()
6964 && ranges_to_query
6965 .as_ref()
6966 .is_none_or(|ranges| ranges.is_empty())
6967 && let Some(cached_inlay_hints) = cached_inlay_hints
6968 {
6969 cached_inlay_hints
6970 .into_iter()
6971 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6972 .collect()
6973 } else {
6974 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
6975 let next_hint_id = next_hint_id.clone();
6976 let buffer = buffer.clone();
6977 let query_version = query_version.clone();
6978 let new_inlay_hints = cx
6979 .spawn(async move |lsp_store, cx| {
6980 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6981 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6982 })?;
6983 new_fetch_task
6984 .await
6985 .and_then(|new_hints_by_server| {
6986 lsp_store.update(cx, |lsp_store, cx| {
6987 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6988 let update_cache = lsp_data.buffer_version == query_version;
6989 if new_hints_by_server.is_empty() {
6990 if update_cache {
6991 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
6992 }
6993 HashMap::default()
6994 } else {
6995 new_hints_by_server
6996 .into_iter()
6997 .map(|(server_id, new_hints)| {
6998 let new_hints = new_hints
6999 .into_iter()
7000 .map(|new_hint| {
7001 (
7002 InlayId::Hint(next_hint_id.fetch_add(
7003 1,
7004 atomic::Ordering::AcqRel,
7005 )),
7006 new_hint,
7007 )
7008 })
7009 .collect::<Vec<_>>();
7010 if update_cache {
7011 lsp_data.inlay_hints.insert_new_hints(
7012 chunk,
7013 server_id,
7014 new_hints.clone(),
7015 );
7016 }
7017 (server_id, new_hints)
7018 })
7019 .collect()
7020 }
7021 })
7022 })
7023 .map_err(Arc::new)
7024 })
7025 .shared();
7026
7027 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7028 *fetch_task = Some(new_inlay_hints.clone());
7029 hint_fetch_tasks.push((chunk, new_inlay_hints));
7030 }
7031
7032 cached_inlay_hints
7033 .unwrap_or_default()
7034 .into_iter()
7035 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7036 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7037 (
7038 chunk.row_range(),
7039 cx.spawn(async move |_, _| {
7040 hints_fetch.await.map_err(|e| {
7041 if e.error_code() != ErrorCode::Internal {
7042 anyhow!(e.error_code())
7043 } else {
7044 anyhow!("{e:#}")
7045 }
7046 })
7047 }),
7048 )
7049 }))
7050 .collect()
7051 }
7052 }
7053
7054 fn fetch_inlay_hints(
7055 &mut self,
7056 for_server: Option<LanguageServerId>,
7057 buffer: &Entity<Buffer>,
7058 range: Range<Anchor>,
7059 cx: &mut Context<Self>,
7060 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7061 let request = InlayHints {
7062 range: range.clone(),
7063 };
7064 if let Some((upstream_client, project_id)) = self.upstream_client() {
7065 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7066 return Task::ready(Ok(HashMap::default()));
7067 }
7068 let request_task = upstream_client.request_lsp(
7069 project_id,
7070 for_server.map(|id| id.to_proto()),
7071 LSP_REQUEST_TIMEOUT,
7072 cx.background_executor().clone(),
7073 request.to_proto(project_id, buffer.read(cx)),
7074 );
7075 let buffer = buffer.clone();
7076 cx.spawn(async move |weak_lsp_store, cx| {
7077 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7078 return Ok(HashMap::default());
7079 };
7080 let Some(responses) = request_task.await? else {
7081 return Ok(HashMap::default());
7082 };
7083
7084 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7085 let lsp_store = lsp_store.clone();
7086 let buffer = buffer.clone();
7087 let cx = cx.clone();
7088 let request = request.clone();
7089 async move {
7090 (
7091 LanguageServerId::from_proto(response.server_id),
7092 request
7093 .response_from_proto(response.response, lsp_store, buffer, cx)
7094 .await,
7095 )
7096 }
7097 }))
7098 .await;
7099
7100 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7101 let mut has_errors = false;
7102 let inlay_hints = inlay_hints
7103 .into_iter()
7104 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7105 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7106 Err(e) => {
7107 has_errors = true;
7108 log::error!("{e:#}");
7109 None
7110 }
7111 })
7112 .map(|(server_id, mut new_hints)| {
7113 new_hints.retain(|hint| {
7114 hint.position.is_valid(&buffer_snapshot)
7115 && range.start.is_valid(&buffer_snapshot)
7116 && range.end.is_valid(&buffer_snapshot)
7117 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7118 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7119 });
7120 (server_id, new_hints)
7121 })
7122 .collect::<HashMap<_, _>>();
7123 anyhow::ensure!(
7124 !has_errors || !inlay_hints.is_empty(),
7125 "Failed to fetch inlay hints"
7126 );
7127 Ok(inlay_hints)
7128 })
7129 } else {
7130 let inlay_hints_task = match for_server {
7131 Some(server_id) => {
7132 let server_task = self.request_lsp(
7133 buffer.clone(),
7134 LanguageServerToQuery::Other(server_id),
7135 request,
7136 cx,
7137 );
7138 cx.background_spawn(async move {
7139 let mut responses = Vec::new();
7140 match server_task.await {
7141 Ok(response) => responses.push((server_id, response)),
7142 // rust-analyzer likes to error with this when its still loading up
7143 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7144 Err(e) => log::error!(
7145 "Error handling response for inlay hints request: {e:#}"
7146 ),
7147 }
7148 responses
7149 })
7150 }
7151 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7152 };
7153 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7154 cx.background_spawn(async move {
7155 Ok(inlay_hints_task
7156 .await
7157 .into_iter()
7158 .map(|(server_id, mut new_hints)| {
7159 new_hints.retain(|hint| {
7160 hint.position.is_valid(&buffer_snapshot)
7161 && range.start.is_valid(&buffer_snapshot)
7162 && range.end.is_valid(&buffer_snapshot)
7163 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7164 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7165 });
7166 (server_id, new_hints)
7167 })
7168 .collect())
7169 })
7170 }
7171 }
7172
7173 pub fn pull_diagnostics_for_buffer(
7174 &mut self,
7175 buffer: Entity<Buffer>,
7176 cx: &mut Context<Self>,
7177 ) -> Task<anyhow::Result<()>> {
7178 let diagnostics = self.pull_diagnostics(buffer, cx);
7179 cx.spawn(async move |lsp_store, cx| {
7180 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7181 return Ok(());
7182 };
7183 lsp_store.update(cx, |lsp_store, cx| {
7184 if lsp_store.as_local().is_none() {
7185 return;
7186 }
7187
7188 let mut unchanged_buffers = HashMap::default();
7189 let server_diagnostics_updates = diagnostics
7190 .into_iter()
7191 .filter_map(|diagnostics_set| match diagnostics_set {
7192 LspPullDiagnostics::Response {
7193 server_id,
7194 uri,
7195 diagnostics,
7196 registration_id,
7197 } => Some((server_id, uri, diagnostics, registration_id)),
7198 LspPullDiagnostics::Default => None,
7199 })
7200 .fold(
7201 HashMap::default(),
7202 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7203 let (result_id, diagnostics) = match diagnostics {
7204 PulledDiagnostics::Unchanged { result_id } => {
7205 unchanged_buffers
7206 .entry(new_registration_id.clone())
7207 .or_insert_with(HashSet::default)
7208 .insert(uri.clone());
7209 (Some(result_id), Vec::new())
7210 }
7211 PulledDiagnostics::Changed {
7212 result_id,
7213 diagnostics,
7214 } => (result_id, diagnostics),
7215 };
7216 let disk_based_sources = Cow::Owned(
7217 lsp_store
7218 .language_server_adapter_for_id(server_id)
7219 .as_ref()
7220 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7221 .unwrap_or(&[])
7222 .to_vec(),
7223 );
7224 acc.entry(server_id)
7225 .or_insert_with(HashMap::default)
7226 .entry(new_registration_id.clone())
7227 .or_insert_with(Vec::new)
7228 .push(DocumentDiagnosticsUpdate {
7229 server_id,
7230 diagnostics: lsp::PublishDiagnosticsParams {
7231 uri,
7232 diagnostics,
7233 version: None,
7234 },
7235 result_id,
7236 disk_based_sources,
7237 registration_id: new_registration_id,
7238 });
7239 acc
7240 },
7241 );
7242
7243 for diagnostic_updates in server_diagnostics_updates.into_values() {
7244 for (registration_id, diagnostic_updates) in diagnostic_updates {
7245 lsp_store
7246 .merge_lsp_diagnostics(
7247 DiagnosticSourceKind::Pulled,
7248 diagnostic_updates,
7249 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7250 DiagnosticSourceKind::Pulled => {
7251 old_diagnostic.registration_id != registration_id
7252 || unchanged_buffers
7253 .get(&old_diagnostic.registration_id)
7254 .is_some_and(|unchanged_buffers| {
7255 unchanged_buffers.contains(&document_uri)
7256 })
7257 }
7258 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7259 true
7260 }
7261 },
7262 cx,
7263 )
7264 .log_err();
7265 }
7266 }
7267 })
7268 })
7269 }
7270
7271 pub fn document_colors(
7272 &mut self,
7273 known_cache_version: Option<usize>,
7274 buffer: Entity<Buffer>,
7275 cx: &mut Context<Self>,
7276 ) -> Option<DocumentColorTask> {
7277 let version_queried_for = buffer.read(cx).version();
7278 let buffer_id = buffer.read(cx).remote_id();
7279
7280 let current_language_servers = self.as_local().map(|local| {
7281 local
7282 .buffers_opened_in_servers
7283 .get(&buffer_id)
7284 .cloned()
7285 .unwrap_or_default()
7286 });
7287
7288 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7289 if let Some(cached_colors) = &lsp_data.document_colors {
7290 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7291 let has_different_servers =
7292 current_language_servers.is_some_and(|current_language_servers| {
7293 current_language_servers
7294 != cached_colors.colors.keys().copied().collect()
7295 });
7296 if !has_different_servers {
7297 let cache_version = cached_colors.cache_version;
7298 if Some(cache_version) == known_cache_version {
7299 return None;
7300 } else {
7301 return Some(
7302 Task::ready(Ok(DocumentColors {
7303 colors: cached_colors
7304 .colors
7305 .values()
7306 .flatten()
7307 .cloned()
7308 .collect(),
7309 cache_version: Some(cache_version),
7310 }))
7311 .shared(),
7312 );
7313 }
7314 }
7315 }
7316 }
7317 }
7318
7319 let color_lsp_data = self
7320 .latest_lsp_data(&buffer, cx)
7321 .document_colors
7322 .get_or_insert_default();
7323 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7324 && !version_queried_for.changed_since(updating_for)
7325 {
7326 return Some(running_update.clone());
7327 }
7328 let buffer_version_queried_for = version_queried_for.clone();
7329 let new_task = cx
7330 .spawn(async move |lsp_store, cx| {
7331 cx.background_executor()
7332 .timer(Duration::from_millis(30))
7333 .await;
7334 let fetched_colors = lsp_store
7335 .update(cx, |lsp_store, cx| {
7336 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7337 })?
7338 .await
7339 .context("fetching document colors")
7340 .map_err(Arc::new);
7341 let fetched_colors = match fetched_colors {
7342 Ok(fetched_colors) => {
7343 if Some(true)
7344 == buffer
7345 .update(cx, |buffer, _| {
7346 buffer.version() != buffer_version_queried_for
7347 })
7348 .ok()
7349 {
7350 return Ok(DocumentColors::default());
7351 }
7352 fetched_colors
7353 }
7354 Err(e) => {
7355 lsp_store
7356 .update(cx, |lsp_store, _| {
7357 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7358 if let Some(document_colors) = &mut lsp_data.document_colors {
7359 document_colors.colors_update = None;
7360 }
7361 }
7362 })
7363 .ok();
7364 return Err(e);
7365 }
7366 };
7367
7368 lsp_store
7369 .update(cx, |lsp_store, cx| {
7370 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7371 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7372
7373 if let Some(fetched_colors) = fetched_colors {
7374 if lsp_data.buffer_version == buffer_version_queried_for {
7375 lsp_colors.colors.extend(fetched_colors);
7376 lsp_colors.cache_version += 1;
7377 } else if !lsp_data
7378 .buffer_version
7379 .changed_since(&buffer_version_queried_for)
7380 {
7381 lsp_data.buffer_version = buffer_version_queried_for;
7382 lsp_colors.colors = fetched_colors;
7383 lsp_colors.cache_version += 1;
7384 }
7385 }
7386 lsp_colors.colors_update = None;
7387 let colors = lsp_colors
7388 .colors
7389 .values()
7390 .flatten()
7391 .cloned()
7392 .collect::<HashSet<_>>();
7393 DocumentColors {
7394 colors,
7395 cache_version: Some(lsp_colors.cache_version),
7396 }
7397 })
7398 .map_err(Arc::new)
7399 })
7400 .shared();
7401 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7402 Some(new_task)
7403 }
7404
7405 fn fetch_document_colors_for_buffer(
7406 &mut self,
7407 buffer: &Entity<Buffer>,
7408 cx: &mut Context<Self>,
7409 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7410 if let Some((client, project_id)) = self.upstream_client() {
7411 let request = GetDocumentColor {};
7412 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7413 return Task::ready(Ok(None));
7414 }
7415
7416 let request_task = client.request_lsp(
7417 project_id,
7418 None,
7419 LSP_REQUEST_TIMEOUT,
7420 cx.background_executor().clone(),
7421 request.to_proto(project_id, buffer.read(cx)),
7422 );
7423 let buffer = buffer.clone();
7424 cx.spawn(async move |lsp_store, cx| {
7425 let Some(lsp_store) = lsp_store.upgrade() else {
7426 return Ok(None);
7427 };
7428 let colors = join_all(
7429 request_task
7430 .await
7431 .log_err()
7432 .flatten()
7433 .map(|response| response.payload)
7434 .unwrap_or_default()
7435 .into_iter()
7436 .map(|color_response| {
7437 let response = request.response_from_proto(
7438 color_response.response,
7439 lsp_store.clone(),
7440 buffer.clone(),
7441 cx.clone(),
7442 );
7443 async move {
7444 (
7445 LanguageServerId::from_proto(color_response.server_id),
7446 response.await.log_err().unwrap_or_default(),
7447 )
7448 }
7449 }),
7450 )
7451 .await
7452 .into_iter()
7453 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7454 acc.entry(server_id)
7455 .or_insert_with(HashSet::default)
7456 .extend(colors);
7457 acc
7458 });
7459 Ok(Some(colors))
7460 })
7461 } else {
7462 let document_colors_task =
7463 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7464 cx.background_spawn(async move {
7465 Ok(Some(
7466 document_colors_task
7467 .await
7468 .into_iter()
7469 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7470 acc.entry(server_id)
7471 .or_insert_with(HashSet::default)
7472 .extend(colors);
7473 acc
7474 })
7475 .into_iter()
7476 .collect(),
7477 ))
7478 })
7479 }
7480 }
7481
7482 pub fn signature_help<T: ToPointUtf16>(
7483 &mut self,
7484 buffer: &Entity<Buffer>,
7485 position: T,
7486 cx: &mut Context<Self>,
7487 ) -> Task<Option<Vec<SignatureHelp>>> {
7488 let position = position.to_point_utf16(buffer.read(cx));
7489
7490 if let Some((client, upstream_project_id)) = self.upstream_client() {
7491 let request = GetSignatureHelp { position };
7492 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7493 return Task::ready(None);
7494 }
7495 let request_task = client.request_lsp(
7496 upstream_project_id,
7497 None,
7498 LSP_REQUEST_TIMEOUT,
7499 cx.background_executor().clone(),
7500 request.to_proto(upstream_project_id, buffer.read(cx)),
7501 );
7502 let buffer = buffer.clone();
7503 cx.spawn(async move |weak_lsp_store, cx| {
7504 let lsp_store = weak_lsp_store.upgrade()?;
7505 let signatures = join_all(
7506 request_task
7507 .await
7508 .log_err()
7509 .flatten()
7510 .map(|response| response.payload)
7511 .unwrap_or_default()
7512 .into_iter()
7513 .map(|response| {
7514 let response = GetSignatureHelp { position }.response_from_proto(
7515 response.response,
7516 lsp_store.clone(),
7517 buffer.clone(),
7518 cx.clone(),
7519 );
7520 async move { response.await.log_err().flatten() }
7521 }),
7522 )
7523 .await
7524 .into_iter()
7525 .flatten()
7526 .collect();
7527 Some(signatures)
7528 })
7529 } else {
7530 let all_actions_task = self.request_multiple_lsp_locally(
7531 buffer,
7532 Some(position),
7533 GetSignatureHelp { position },
7534 cx,
7535 );
7536 cx.background_spawn(async move {
7537 Some(
7538 all_actions_task
7539 .await
7540 .into_iter()
7541 .flat_map(|(_, actions)| actions)
7542 .collect::<Vec<_>>(),
7543 )
7544 })
7545 }
7546 }
7547
7548 pub fn hover(
7549 &mut self,
7550 buffer: &Entity<Buffer>,
7551 position: PointUtf16,
7552 cx: &mut Context<Self>,
7553 ) -> Task<Option<Vec<Hover>>> {
7554 if let Some((client, upstream_project_id)) = self.upstream_client() {
7555 let request = GetHover { position };
7556 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7557 return Task::ready(None);
7558 }
7559 let request_task = client.request_lsp(
7560 upstream_project_id,
7561 None,
7562 LSP_REQUEST_TIMEOUT,
7563 cx.background_executor().clone(),
7564 request.to_proto(upstream_project_id, buffer.read(cx)),
7565 );
7566 let buffer = buffer.clone();
7567 cx.spawn(async move |weak_lsp_store, cx| {
7568 let lsp_store = weak_lsp_store.upgrade()?;
7569 let hovers = join_all(
7570 request_task
7571 .await
7572 .log_err()
7573 .flatten()
7574 .map(|response| response.payload)
7575 .unwrap_or_default()
7576 .into_iter()
7577 .map(|response| {
7578 let response = GetHover { position }.response_from_proto(
7579 response.response,
7580 lsp_store.clone(),
7581 buffer.clone(),
7582 cx.clone(),
7583 );
7584 async move {
7585 response
7586 .await
7587 .log_err()
7588 .flatten()
7589 .and_then(remove_empty_hover_blocks)
7590 }
7591 }),
7592 )
7593 .await
7594 .into_iter()
7595 .flatten()
7596 .collect();
7597 Some(hovers)
7598 })
7599 } else {
7600 let all_actions_task = self.request_multiple_lsp_locally(
7601 buffer,
7602 Some(position),
7603 GetHover { position },
7604 cx,
7605 );
7606 cx.background_spawn(async move {
7607 Some(
7608 all_actions_task
7609 .await
7610 .into_iter()
7611 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7612 .collect::<Vec<Hover>>(),
7613 )
7614 })
7615 }
7616 }
7617
7618 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7619 let language_registry = self.languages.clone();
7620
7621 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7622 let request = upstream_client.request(proto::GetProjectSymbols {
7623 project_id: *project_id,
7624 query: query.to_string(),
7625 });
7626 cx.foreground_executor().spawn(async move {
7627 let response = request.await?;
7628 let mut symbols = Vec::new();
7629 let core_symbols = response
7630 .symbols
7631 .into_iter()
7632 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7633 .collect::<Vec<_>>();
7634 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7635 .await;
7636 Ok(symbols)
7637 })
7638 } else if let Some(local) = self.as_local() {
7639 struct WorkspaceSymbolsResult {
7640 server_id: LanguageServerId,
7641 lsp_adapter: Arc<CachedLspAdapter>,
7642 worktree: WeakEntity<Worktree>,
7643 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7644 }
7645
7646 let mut requests = Vec::new();
7647 let mut requested_servers = BTreeSet::new();
7648 for (seed, state) in local.language_server_ids.iter() {
7649 let Some(worktree_handle) = self
7650 .worktree_store
7651 .read(cx)
7652 .worktree_for_id(seed.worktree_id, cx)
7653 else {
7654 continue;
7655 };
7656 let worktree = worktree_handle.read(cx);
7657 if !worktree.is_visible() {
7658 continue;
7659 }
7660
7661 if !requested_servers.insert(state.id) {
7662 continue;
7663 }
7664
7665 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7666 Some(LanguageServerState::Running {
7667 adapter, server, ..
7668 }) => (adapter.clone(), server),
7669
7670 _ => continue,
7671 };
7672 let supports_workspace_symbol_request =
7673 match server.capabilities().workspace_symbol_provider {
7674 Some(OneOf::Left(supported)) => supported,
7675 Some(OneOf::Right(_)) => true,
7676 None => false,
7677 };
7678 if !supports_workspace_symbol_request {
7679 continue;
7680 }
7681 let worktree_handle = worktree_handle.clone();
7682 let server_id = server.server_id();
7683 requests.push(
7684 server
7685 .request::<lsp::request::WorkspaceSymbolRequest>(
7686 lsp::WorkspaceSymbolParams {
7687 query: query.to_string(),
7688 ..Default::default()
7689 },
7690 )
7691 .map(move |response| {
7692 let lsp_symbols = response.into_response()
7693 .context("workspace symbols request")
7694 .log_err()
7695 .flatten()
7696 .map(|symbol_response| match symbol_response {
7697 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7698 flat_responses.into_iter().map(|lsp_symbol| {
7699 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7700 }).collect::<Vec<_>>()
7701 }
7702 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7703 nested_responses.into_iter().filter_map(|lsp_symbol| {
7704 let location = match lsp_symbol.location {
7705 OneOf::Left(location) => location,
7706 OneOf::Right(_) => {
7707 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7708 return None
7709 }
7710 };
7711 Some((lsp_symbol.name, lsp_symbol.kind, location))
7712 }).collect::<Vec<_>>()
7713 }
7714 }).unwrap_or_default();
7715
7716 WorkspaceSymbolsResult {
7717 server_id,
7718 lsp_adapter,
7719 worktree: worktree_handle.downgrade(),
7720 lsp_symbols,
7721 }
7722 }),
7723 );
7724 }
7725
7726 cx.spawn(async move |this, cx| {
7727 let responses = futures::future::join_all(requests).await;
7728 let this = match this.upgrade() {
7729 Some(this) => this,
7730 None => return Ok(Vec::new()),
7731 };
7732
7733 let mut symbols = Vec::new();
7734 for result in responses {
7735 let core_symbols = this.update(cx, |this, cx| {
7736 result
7737 .lsp_symbols
7738 .into_iter()
7739 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7740 let abs_path = symbol_location.uri.to_file_path().ok()?;
7741 let source_worktree = result.worktree.upgrade()?;
7742 let source_worktree_id = source_worktree.read(cx).id();
7743
7744 let path = if let Some((tree, rel_path)) =
7745 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7746 {
7747 let worktree_id = tree.read(cx).id();
7748 SymbolLocation::InProject(ProjectPath {
7749 worktree_id,
7750 path: rel_path,
7751 })
7752 } else {
7753 SymbolLocation::OutsideProject {
7754 signature: this.symbol_signature(&abs_path),
7755 abs_path: abs_path.into(),
7756 }
7757 };
7758
7759 Some(CoreSymbol {
7760 source_language_server_id: result.server_id,
7761 language_server_name: result.lsp_adapter.name.clone(),
7762 source_worktree_id,
7763 path,
7764 kind: symbol_kind,
7765 name: symbol_name,
7766 range: range_from_lsp(symbol_location.range),
7767 })
7768 })
7769 .collect()
7770 })?;
7771
7772 populate_labels_for_symbols(
7773 core_symbols,
7774 &language_registry,
7775 Some(result.lsp_adapter),
7776 &mut symbols,
7777 )
7778 .await;
7779 }
7780
7781 Ok(symbols)
7782 })
7783 } else {
7784 Task::ready(Err(anyhow!("No upstream client or local language server")))
7785 }
7786 }
7787
7788 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7789 let mut summary = DiagnosticSummary::default();
7790 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7791 summary.error_count += path_summary.error_count;
7792 summary.warning_count += path_summary.warning_count;
7793 }
7794 summary
7795 }
7796
7797 /// Returns the diagnostic summary for a specific project path.
7798 pub fn diagnostic_summary_for_path(
7799 &self,
7800 project_path: &ProjectPath,
7801 _: &App,
7802 ) -> DiagnosticSummary {
7803 if let Some(summaries) = self
7804 .diagnostic_summaries
7805 .get(&project_path.worktree_id)
7806 .and_then(|map| map.get(&project_path.path))
7807 {
7808 let (error_count, warning_count) = summaries.iter().fold(
7809 (0, 0),
7810 |(error_count, warning_count), (_language_server_id, summary)| {
7811 (
7812 error_count + summary.error_count,
7813 warning_count + summary.warning_count,
7814 )
7815 },
7816 );
7817
7818 DiagnosticSummary {
7819 error_count,
7820 warning_count,
7821 }
7822 } else {
7823 DiagnosticSummary::default()
7824 }
7825 }
7826
7827 pub fn diagnostic_summaries<'a>(
7828 &'a self,
7829 include_ignored: bool,
7830 cx: &'a App,
7831 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7832 self.worktree_store
7833 .read(cx)
7834 .visible_worktrees(cx)
7835 .filter_map(|worktree| {
7836 let worktree = worktree.read(cx);
7837 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7838 })
7839 .flat_map(move |(worktree, summaries)| {
7840 let worktree_id = worktree.id();
7841 summaries
7842 .iter()
7843 .filter(move |(path, _)| {
7844 include_ignored
7845 || worktree
7846 .entry_for_path(path.as_ref())
7847 .is_some_and(|entry| !entry.is_ignored)
7848 })
7849 .flat_map(move |(path, summaries)| {
7850 summaries.iter().map(move |(server_id, summary)| {
7851 (
7852 ProjectPath {
7853 worktree_id,
7854 path: path.clone(),
7855 },
7856 *server_id,
7857 *summary,
7858 )
7859 })
7860 })
7861 })
7862 }
7863
7864 pub fn on_buffer_edited(
7865 &mut self,
7866 buffer: Entity<Buffer>,
7867 cx: &mut Context<Self>,
7868 ) -> Option<()> {
7869 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7870 Some(
7871 self.as_local()?
7872 .language_servers_for_buffer(buffer, cx)
7873 .map(|i| i.1.clone())
7874 .collect(),
7875 )
7876 })?;
7877
7878 let buffer = buffer.read(cx);
7879 let file = File::from_dyn(buffer.file())?;
7880 let abs_path = file.as_local()?.abs_path(cx);
7881 let uri = lsp::Uri::from_file_path(&abs_path)
7882 .ok()
7883 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7884 .log_err()?;
7885 let next_snapshot = buffer.text_snapshot();
7886 for language_server in language_servers {
7887 let language_server = language_server.clone();
7888
7889 let buffer_snapshots = self
7890 .as_local_mut()?
7891 .buffer_snapshots
7892 .get_mut(&buffer.remote_id())
7893 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7894 let previous_snapshot = buffer_snapshots.last()?;
7895
7896 let build_incremental_change = || {
7897 buffer
7898 .edits_since::<Dimensions<PointUtf16, usize>>(
7899 previous_snapshot.snapshot.version(),
7900 )
7901 .map(|edit| {
7902 let edit_start = edit.new.start.0;
7903 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7904 let new_text = next_snapshot
7905 .text_for_range(edit.new.start.1..edit.new.end.1)
7906 .collect();
7907 lsp::TextDocumentContentChangeEvent {
7908 range: Some(lsp::Range::new(
7909 point_to_lsp(edit_start),
7910 point_to_lsp(edit_end),
7911 )),
7912 range_length: None,
7913 text: new_text,
7914 }
7915 })
7916 .collect()
7917 };
7918
7919 let document_sync_kind = language_server
7920 .capabilities()
7921 .text_document_sync
7922 .as_ref()
7923 .and_then(|sync| match sync {
7924 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7925 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7926 });
7927
7928 let content_changes: Vec<_> = match document_sync_kind {
7929 Some(lsp::TextDocumentSyncKind::FULL) => {
7930 vec![lsp::TextDocumentContentChangeEvent {
7931 range: None,
7932 range_length: None,
7933 text: next_snapshot.text(),
7934 }]
7935 }
7936 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7937 _ => {
7938 #[cfg(any(test, feature = "test-support"))]
7939 {
7940 build_incremental_change()
7941 }
7942
7943 #[cfg(not(any(test, feature = "test-support")))]
7944 {
7945 continue;
7946 }
7947 }
7948 };
7949
7950 let next_version = previous_snapshot.version + 1;
7951 buffer_snapshots.push(LspBufferSnapshot {
7952 version: next_version,
7953 snapshot: next_snapshot.clone(),
7954 });
7955
7956 language_server
7957 .notify::<lsp::notification::DidChangeTextDocument>(
7958 lsp::DidChangeTextDocumentParams {
7959 text_document: lsp::VersionedTextDocumentIdentifier::new(
7960 uri.clone(),
7961 next_version,
7962 ),
7963 content_changes,
7964 },
7965 )
7966 .ok();
7967 self.pull_workspace_diagnostics(language_server.server_id());
7968 }
7969
7970 None
7971 }
7972
7973 pub fn on_buffer_saved(
7974 &mut self,
7975 buffer: Entity<Buffer>,
7976 cx: &mut Context<Self>,
7977 ) -> Option<()> {
7978 let file = File::from_dyn(buffer.read(cx).file())?;
7979 let worktree_id = file.worktree_id(cx);
7980 let abs_path = file.as_local()?.abs_path(cx);
7981 let text_document = lsp::TextDocumentIdentifier {
7982 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7983 };
7984 let local = self.as_local()?;
7985
7986 for server in local.language_servers_for_worktree(worktree_id) {
7987 if let Some(include_text) = include_text(server.as_ref()) {
7988 let text = if include_text {
7989 Some(buffer.read(cx).text())
7990 } else {
7991 None
7992 };
7993 server
7994 .notify::<lsp::notification::DidSaveTextDocument>(
7995 lsp::DidSaveTextDocumentParams {
7996 text_document: text_document.clone(),
7997 text,
7998 },
7999 )
8000 .ok();
8001 }
8002 }
8003
8004 let language_servers = buffer.update(cx, |buffer, cx| {
8005 local.language_server_ids_for_buffer(buffer, cx)
8006 });
8007 for language_server_id in language_servers {
8008 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8009 }
8010
8011 None
8012 }
8013
8014 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8015 maybe!(async move {
8016 let mut refreshed_servers = HashSet::default();
8017 let servers = lsp_store
8018 .update(cx, |lsp_store, cx| {
8019 let local = lsp_store.as_local()?;
8020
8021 let servers = local
8022 .language_server_ids
8023 .iter()
8024 .filter_map(|(seed, state)| {
8025 let worktree = lsp_store
8026 .worktree_store
8027 .read(cx)
8028 .worktree_for_id(seed.worktree_id, cx);
8029 let delegate: Arc<dyn LspAdapterDelegate> =
8030 worktree.map(|worktree| {
8031 LocalLspAdapterDelegate::new(
8032 local.languages.clone(),
8033 &local.environment,
8034 cx.weak_entity(),
8035 &worktree,
8036 local.http_client.clone(),
8037 local.fs.clone(),
8038 cx,
8039 )
8040 })?;
8041 let server_id = state.id;
8042
8043 let states = local.language_servers.get(&server_id)?;
8044
8045 match states {
8046 LanguageServerState::Starting { .. } => None,
8047 LanguageServerState::Running {
8048 adapter, server, ..
8049 } => {
8050 let adapter = adapter.clone();
8051 let server = server.clone();
8052 refreshed_servers.insert(server.name());
8053 let toolchain = seed.toolchain.clone();
8054 Some(cx.spawn(async move |_, cx| {
8055 let settings =
8056 LocalLspStore::workspace_configuration_for_adapter(
8057 adapter.adapter.clone(),
8058 &delegate,
8059 toolchain,
8060 None,
8061 cx,
8062 )
8063 .await
8064 .ok()?;
8065 server
8066 .notify::<lsp::notification::DidChangeConfiguration>(
8067 lsp::DidChangeConfigurationParams { settings },
8068 )
8069 .ok()?;
8070 Some(())
8071 }))
8072 }
8073 }
8074 })
8075 .collect::<Vec<_>>();
8076
8077 Some(servers)
8078 })
8079 .ok()
8080 .flatten()?;
8081
8082 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8083 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8084 // to stop and unregister its language server wrapper.
8085 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8086 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8087 let _: Vec<Option<()>> = join_all(servers).await;
8088
8089 Some(())
8090 })
8091 .await;
8092 }
8093
8094 fn maintain_workspace_config(
8095 external_refresh_requests: watch::Receiver<()>,
8096 cx: &mut Context<Self>,
8097 ) -> Task<Result<()>> {
8098 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8099 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8100
8101 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8102 *settings_changed_tx.borrow_mut() = ();
8103 });
8104
8105 let mut joint_future =
8106 futures::stream::select(settings_changed_rx, external_refresh_requests);
8107 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8108 // - 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).
8109 // - 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.
8110 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8111 // - 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,
8112 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8113 cx.spawn(async move |this, cx| {
8114 while let Some(()) = joint_future.next().await {
8115 this.update(cx, |this, cx| {
8116 this.refresh_server_tree(cx);
8117 })
8118 .ok();
8119
8120 Self::refresh_workspace_configurations(&this, cx).await;
8121 }
8122
8123 drop(settings_observation);
8124 anyhow::Ok(())
8125 })
8126 }
8127
8128 pub fn running_language_servers_for_local_buffer<'a>(
8129 &'a self,
8130 buffer: &Buffer,
8131 cx: &mut App,
8132 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8133 let local = self.as_local();
8134 let language_server_ids = local
8135 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8136 .unwrap_or_default();
8137
8138 language_server_ids
8139 .into_iter()
8140 .filter_map(
8141 move |server_id| match local?.language_servers.get(&server_id)? {
8142 LanguageServerState::Running {
8143 adapter, server, ..
8144 } => Some((adapter, server)),
8145 _ => None,
8146 },
8147 )
8148 }
8149
8150 pub fn language_servers_for_local_buffer(
8151 &self,
8152 buffer: &Buffer,
8153 cx: &mut App,
8154 ) -> Vec<LanguageServerId> {
8155 let local = self.as_local();
8156 local
8157 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8158 .unwrap_or_default()
8159 }
8160
8161 pub fn language_server_for_local_buffer<'a>(
8162 &'a self,
8163 buffer: &'a Buffer,
8164 server_id: LanguageServerId,
8165 cx: &'a mut App,
8166 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8167 self.as_local()?
8168 .language_servers_for_buffer(buffer, cx)
8169 .find(|(_, s)| s.server_id() == server_id)
8170 }
8171
8172 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8173 self.diagnostic_summaries.remove(&id_to_remove);
8174 if let Some(local) = self.as_local_mut() {
8175 let to_remove = local.remove_worktree(id_to_remove, cx);
8176 for server in to_remove {
8177 self.language_server_statuses.remove(&server);
8178 }
8179 }
8180 }
8181
8182 pub fn shared(
8183 &mut self,
8184 project_id: u64,
8185 downstream_client: AnyProtoClient,
8186 _: &mut Context<Self>,
8187 ) {
8188 self.downstream_client = Some((downstream_client.clone(), project_id));
8189
8190 for (server_id, status) in &self.language_server_statuses {
8191 if let Some(server) = self.language_server_for_id(*server_id) {
8192 downstream_client
8193 .send(proto::StartLanguageServer {
8194 project_id,
8195 server: Some(proto::LanguageServer {
8196 id: server_id.to_proto(),
8197 name: status.name.to_string(),
8198 worktree_id: status.worktree.map(|id| id.to_proto()),
8199 }),
8200 capabilities: serde_json::to_string(&server.capabilities())
8201 .expect("serializing server LSP capabilities"),
8202 })
8203 .log_err();
8204 }
8205 }
8206 }
8207
8208 pub fn disconnected_from_host(&mut self) {
8209 self.downstream_client.take();
8210 }
8211
8212 pub fn disconnected_from_ssh_remote(&mut self) {
8213 if let LspStoreMode::Remote(RemoteLspStore {
8214 upstream_client, ..
8215 }) = &mut self.mode
8216 {
8217 upstream_client.take();
8218 }
8219 }
8220
8221 pub(crate) fn set_language_server_statuses_from_proto(
8222 &mut self,
8223 project: WeakEntity<Project>,
8224 language_servers: Vec<proto::LanguageServer>,
8225 server_capabilities: Vec<String>,
8226 cx: &mut Context<Self>,
8227 ) {
8228 let lsp_logs = cx
8229 .try_global::<GlobalLogStore>()
8230 .map(|lsp_store| lsp_store.0.clone());
8231
8232 self.language_server_statuses = language_servers
8233 .into_iter()
8234 .zip(server_capabilities)
8235 .map(|(server, server_capabilities)| {
8236 let server_id = LanguageServerId(server.id as usize);
8237 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8238 self.lsp_server_capabilities
8239 .insert(server_id, server_capabilities);
8240 }
8241
8242 let name = LanguageServerName::from_proto(server.name);
8243 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8244
8245 if let Some(lsp_logs) = &lsp_logs {
8246 lsp_logs.update(cx, |lsp_logs, cx| {
8247 lsp_logs.add_language_server(
8248 // Only remote clients get their language servers set from proto
8249 LanguageServerKind::Remote {
8250 project: project.clone(),
8251 },
8252 server_id,
8253 Some(name.clone()),
8254 worktree,
8255 None,
8256 cx,
8257 );
8258 });
8259 }
8260
8261 (
8262 server_id,
8263 LanguageServerStatus {
8264 name,
8265 pending_work: Default::default(),
8266 has_pending_diagnostic_updates: false,
8267 progress_tokens: Default::default(),
8268 worktree,
8269 binary: None,
8270 configuration: None,
8271 workspace_folders: BTreeSet::new(),
8272 },
8273 )
8274 })
8275 .collect();
8276 }
8277
8278 #[cfg(test)]
8279 pub fn update_diagnostic_entries(
8280 &mut self,
8281 server_id: LanguageServerId,
8282 abs_path: PathBuf,
8283 result_id: Option<SharedString>,
8284 version: Option<i32>,
8285 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8286 cx: &mut Context<Self>,
8287 ) -> anyhow::Result<()> {
8288 self.merge_diagnostic_entries(
8289 vec![DocumentDiagnosticsUpdate {
8290 diagnostics: DocumentDiagnostics {
8291 diagnostics,
8292 document_abs_path: abs_path,
8293 version,
8294 },
8295 result_id,
8296 server_id,
8297 disk_based_sources: Cow::Borrowed(&[]),
8298 registration_id: None,
8299 }],
8300 |_, _, _| false,
8301 cx,
8302 )?;
8303 Ok(())
8304 }
8305
8306 pub fn merge_diagnostic_entries<'a>(
8307 &mut self,
8308 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8309 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8310 cx: &mut Context<Self>,
8311 ) -> anyhow::Result<()> {
8312 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8313 let mut updated_diagnostics_paths = HashMap::default();
8314 for mut update in diagnostic_updates {
8315 let abs_path = &update.diagnostics.document_abs_path;
8316 let server_id = update.server_id;
8317 let Some((worktree, relative_path)) =
8318 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8319 else {
8320 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8321 return Ok(());
8322 };
8323
8324 let worktree_id = worktree.read(cx).id();
8325 let project_path = ProjectPath {
8326 worktree_id,
8327 path: relative_path,
8328 };
8329
8330 let document_uri = lsp::Uri::from_file_path(abs_path)
8331 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8332 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8333 let snapshot = buffer_handle.read(cx).snapshot();
8334 let buffer = buffer_handle.read(cx);
8335 let reused_diagnostics = buffer
8336 .buffer_diagnostics(Some(server_id))
8337 .iter()
8338 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8339 .map(|v| {
8340 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8341 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8342 DiagnosticEntry {
8343 range: start..end,
8344 diagnostic: v.diagnostic.clone(),
8345 }
8346 })
8347 .collect::<Vec<_>>();
8348
8349 self.as_local_mut()
8350 .context("cannot merge diagnostics on a remote LspStore")?
8351 .update_buffer_diagnostics(
8352 &buffer_handle,
8353 server_id,
8354 Some(update.registration_id),
8355 update.result_id,
8356 update.diagnostics.version,
8357 update.diagnostics.diagnostics.clone(),
8358 reused_diagnostics.clone(),
8359 cx,
8360 )?;
8361
8362 update.diagnostics.diagnostics.extend(reused_diagnostics);
8363 } else if let Some(local) = self.as_local() {
8364 let reused_diagnostics = local
8365 .diagnostics
8366 .get(&worktree_id)
8367 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8368 .and_then(|diagnostics_by_server_id| {
8369 diagnostics_by_server_id
8370 .binary_search_by_key(&server_id, |e| e.0)
8371 .ok()
8372 .map(|ix| &diagnostics_by_server_id[ix].1)
8373 })
8374 .into_iter()
8375 .flatten()
8376 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8377
8378 update
8379 .diagnostics
8380 .diagnostics
8381 .extend(reused_diagnostics.cloned());
8382 }
8383
8384 let updated = worktree.update(cx, |worktree, cx| {
8385 self.update_worktree_diagnostics(
8386 worktree.id(),
8387 server_id,
8388 project_path.path.clone(),
8389 update.diagnostics.diagnostics,
8390 cx,
8391 )
8392 })?;
8393 match updated {
8394 ControlFlow::Continue(new_summary) => {
8395 if let Some((project_id, new_summary)) = new_summary {
8396 match &mut diagnostics_summary {
8397 Some(diagnostics_summary) => {
8398 diagnostics_summary
8399 .more_summaries
8400 .push(proto::DiagnosticSummary {
8401 path: project_path.path.as_ref().to_proto(),
8402 language_server_id: server_id.0 as u64,
8403 error_count: new_summary.error_count,
8404 warning_count: new_summary.warning_count,
8405 })
8406 }
8407 None => {
8408 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8409 project_id,
8410 worktree_id: worktree_id.to_proto(),
8411 summary: Some(proto::DiagnosticSummary {
8412 path: project_path.path.as_ref().to_proto(),
8413 language_server_id: server_id.0 as u64,
8414 error_count: new_summary.error_count,
8415 warning_count: new_summary.warning_count,
8416 }),
8417 more_summaries: Vec::new(),
8418 })
8419 }
8420 }
8421 }
8422 updated_diagnostics_paths
8423 .entry(server_id)
8424 .or_insert_with(Vec::new)
8425 .push(project_path);
8426 }
8427 ControlFlow::Break(()) => {}
8428 }
8429 }
8430
8431 if let Some((diagnostics_summary, (downstream_client, _))) =
8432 diagnostics_summary.zip(self.downstream_client.as_ref())
8433 {
8434 downstream_client.send(diagnostics_summary).log_err();
8435 }
8436 for (server_id, paths) in updated_diagnostics_paths {
8437 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8438 }
8439 Ok(())
8440 }
8441
8442 fn update_worktree_diagnostics(
8443 &mut self,
8444 worktree_id: WorktreeId,
8445 server_id: LanguageServerId,
8446 path_in_worktree: Arc<RelPath>,
8447 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8448 _: &mut Context<Worktree>,
8449 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8450 let local = match &mut self.mode {
8451 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8452 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8453 };
8454
8455 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8456 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8457 let summaries_by_server_id = summaries_for_tree
8458 .entry(path_in_worktree.clone())
8459 .or_default();
8460
8461 let old_summary = summaries_by_server_id
8462 .remove(&server_id)
8463 .unwrap_or_default();
8464
8465 let new_summary = DiagnosticSummary::new(&diagnostics);
8466 if diagnostics.is_empty() {
8467 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8468 {
8469 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8470 diagnostics_by_server_id.remove(ix);
8471 }
8472 if diagnostics_by_server_id.is_empty() {
8473 diagnostics_for_tree.remove(&path_in_worktree);
8474 }
8475 }
8476 } else {
8477 summaries_by_server_id.insert(server_id, new_summary);
8478 let diagnostics_by_server_id = diagnostics_for_tree
8479 .entry(path_in_worktree.clone())
8480 .or_default();
8481 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8482 Ok(ix) => {
8483 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8484 }
8485 Err(ix) => {
8486 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8487 }
8488 }
8489 }
8490
8491 if !old_summary.is_empty() || !new_summary.is_empty() {
8492 if let Some((_, project_id)) = &self.downstream_client {
8493 Ok(ControlFlow::Continue(Some((
8494 *project_id,
8495 proto::DiagnosticSummary {
8496 path: path_in_worktree.to_proto(),
8497 language_server_id: server_id.0 as u64,
8498 error_count: new_summary.error_count as u32,
8499 warning_count: new_summary.warning_count as u32,
8500 },
8501 ))))
8502 } else {
8503 Ok(ControlFlow::Continue(None))
8504 }
8505 } else {
8506 Ok(ControlFlow::Break(()))
8507 }
8508 }
8509
8510 pub fn open_buffer_for_symbol(
8511 &mut self,
8512 symbol: &Symbol,
8513 cx: &mut Context<Self>,
8514 ) -> Task<Result<Entity<Buffer>>> {
8515 if let Some((client, project_id)) = self.upstream_client() {
8516 let request = client.request(proto::OpenBufferForSymbol {
8517 project_id,
8518 symbol: Some(Self::serialize_symbol(symbol)),
8519 });
8520 cx.spawn(async move |this, cx| {
8521 let response = request.await?;
8522 let buffer_id = BufferId::new(response.buffer_id)?;
8523 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8524 .await
8525 })
8526 } else if let Some(local) = self.as_local() {
8527 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8528 seed.worktree_id == symbol.source_worktree_id
8529 && state.id == symbol.source_language_server_id
8530 && symbol.language_server_name == seed.name
8531 });
8532 if !is_valid {
8533 return Task::ready(Err(anyhow!(
8534 "language server for worktree and language not found"
8535 )));
8536 };
8537
8538 let symbol_abs_path = match &symbol.path {
8539 SymbolLocation::InProject(project_path) => self
8540 .worktree_store
8541 .read(cx)
8542 .absolutize(&project_path, cx)
8543 .context("no such worktree"),
8544 SymbolLocation::OutsideProject {
8545 abs_path,
8546 signature: _,
8547 } => Ok(abs_path.to_path_buf()),
8548 };
8549 let symbol_abs_path = match symbol_abs_path {
8550 Ok(abs_path) => abs_path,
8551 Err(err) => return Task::ready(Err(err)),
8552 };
8553 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8554 uri
8555 } else {
8556 return Task::ready(Err(anyhow!("invalid symbol path")));
8557 };
8558
8559 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8560 } else {
8561 Task::ready(Err(anyhow!("no upstream client or local store")))
8562 }
8563 }
8564
8565 pub(crate) fn open_local_buffer_via_lsp(
8566 &mut self,
8567 abs_path: lsp::Uri,
8568 language_server_id: LanguageServerId,
8569 cx: &mut Context<Self>,
8570 ) -> Task<Result<Entity<Buffer>>> {
8571 cx.spawn(async move |lsp_store, cx| {
8572 // Escape percent-encoded string.
8573 let current_scheme = abs_path.scheme().to_owned();
8574 // Uri is immutable, so we can't modify the scheme
8575
8576 let abs_path = abs_path
8577 .to_file_path()
8578 .map_err(|()| anyhow!("can't convert URI to path"))?;
8579 let p = abs_path.clone();
8580 let yarn_worktree = lsp_store
8581 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8582 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8583 cx.spawn(async move |this, cx| {
8584 let t = this
8585 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8586 .ok()?;
8587 t.await
8588 })
8589 }),
8590 None => Task::ready(None),
8591 })?
8592 .await;
8593 let (worktree_root_target, known_relative_path) =
8594 if let Some((zip_root, relative_path)) = yarn_worktree {
8595 (zip_root, Some(relative_path))
8596 } else {
8597 (Arc::<Path>::from(abs_path.as_path()), None)
8598 };
8599 let (worktree, relative_path) = if let Some(result) =
8600 lsp_store.update(cx, |lsp_store, cx| {
8601 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8602 worktree_store.find_worktree(&worktree_root_target, cx)
8603 })
8604 })? {
8605 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8606 (result.0, relative_path)
8607 } else {
8608 let worktree = lsp_store
8609 .update(cx, |lsp_store, cx| {
8610 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8611 worktree_store.create_worktree(&worktree_root_target, false, cx)
8612 })
8613 })?
8614 .await?;
8615 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8616 lsp_store
8617 .update(cx, |lsp_store, cx| {
8618 if let Some(local) = lsp_store.as_local_mut() {
8619 local.register_language_server_for_invisible_worktree(
8620 &worktree,
8621 language_server_id,
8622 cx,
8623 )
8624 }
8625 })
8626 .ok();
8627 }
8628 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8629 let relative_path = if let Some(known_path) = known_relative_path {
8630 known_path
8631 } else {
8632 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8633 .into_arc()
8634 };
8635 (worktree, relative_path)
8636 };
8637 let project_path = ProjectPath {
8638 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8639 path: relative_path,
8640 };
8641 lsp_store
8642 .update(cx, |lsp_store, cx| {
8643 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8644 buffer_store.open_buffer(project_path, cx)
8645 })
8646 })?
8647 .await
8648 })
8649 }
8650
8651 fn request_multiple_lsp_locally<P, R>(
8652 &mut self,
8653 buffer: &Entity<Buffer>,
8654 position: Option<P>,
8655 request: R,
8656 cx: &mut Context<Self>,
8657 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8658 where
8659 P: ToOffset,
8660 R: LspCommand + Clone,
8661 <R::LspRequest as lsp::request::Request>::Result: Send,
8662 <R::LspRequest as lsp::request::Request>::Params: Send,
8663 {
8664 let Some(local) = self.as_local() else {
8665 return Task::ready(Vec::new());
8666 };
8667
8668 let snapshot = buffer.read(cx).snapshot();
8669 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8670
8671 let server_ids = buffer.update(cx, |buffer, cx| {
8672 local
8673 .language_servers_for_buffer(buffer, cx)
8674 .filter(|(adapter, _)| {
8675 scope
8676 .as_ref()
8677 .map(|scope| scope.language_allowed(&adapter.name))
8678 .unwrap_or(true)
8679 })
8680 .map(|(_, server)| server.server_id())
8681 .filter(|server_id| {
8682 self.as_local().is_none_or(|local| {
8683 local
8684 .buffers_opened_in_servers
8685 .get(&snapshot.remote_id())
8686 .is_some_and(|servers| servers.contains(server_id))
8687 })
8688 })
8689 .collect::<Vec<_>>()
8690 });
8691
8692 let mut response_results = server_ids
8693 .into_iter()
8694 .map(|server_id| {
8695 let task = self.request_lsp(
8696 buffer.clone(),
8697 LanguageServerToQuery::Other(server_id),
8698 request.clone(),
8699 cx,
8700 );
8701 async move { (server_id, task.await) }
8702 })
8703 .collect::<FuturesUnordered<_>>();
8704
8705 cx.background_spawn(async move {
8706 let mut responses = Vec::with_capacity(response_results.len());
8707 while let Some((server_id, response_result)) = response_results.next().await {
8708 match response_result {
8709 Ok(response) => responses.push((server_id, response)),
8710 // rust-analyzer likes to error with this when its still loading up
8711 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8712 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8713 }
8714 }
8715 responses
8716 })
8717 }
8718
8719 async fn handle_lsp_get_completions(
8720 this: Entity<Self>,
8721 envelope: TypedEnvelope<proto::GetCompletions>,
8722 mut cx: AsyncApp,
8723 ) -> Result<proto::GetCompletionsResponse> {
8724 let sender_id = envelope.original_sender_id().unwrap_or_default();
8725
8726 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8727 let buffer_handle = this.update(&mut cx, |this, cx| {
8728 this.buffer_store.read(cx).get_existing(buffer_id)
8729 })??;
8730 let request = GetCompletions::from_proto(
8731 envelope.payload,
8732 this.clone(),
8733 buffer_handle.clone(),
8734 cx.clone(),
8735 )
8736 .await?;
8737
8738 let server_to_query = match request.server_id {
8739 Some(server_id) => LanguageServerToQuery::Other(server_id),
8740 None => LanguageServerToQuery::FirstCapable,
8741 };
8742
8743 let response = this
8744 .update(&mut cx, |this, cx| {
8745 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8746 })?
8747 .await?;
8748 this.update(&mut cx, |this, cx| {
8749 Ok(GetCompletions::response_to_proto(
8750 response,
8751 this,
8752 sender_id,
8753 &buffer_handle.read(cx).version(),
8754 cx,
8755 ))
8756 })?
8757 }
8758
8759 async fn handle_lsp_command<T: LspCommand>(
8760 this: Entity<Self>,
8761 envelope: TypedEnvelope<T::ProtoRequest>,
8762 mut cx: AsyncApp,
8763 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8764 where
8765 <T::LspRequest as lsp::request::Request>::Params: Send,
8766 <T::LspRequest as lsp::request::Request>::Result: Send,
8767 {
8768 let sender_id = envelope.original_sender_id().unwrap_or_default();
8769 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8770 let buffer_handle = this.update(&mut cx, |this, cx| {
8771 this.buffer_store.read(cx).get_existing(buffer_id)
8772 })??;
8773 let request = T::from_proto(
8774 envelope.payload,
8775 this.clone(),
8776 buffer_handle.clone(),
8777 cx.clone(),
8778 )
8779 .await?;
8780 let response = this
8781 .update(&mut cx, |this, cx| {
8782 this.request_lsp(
8783 buffer_handle.clone(),
8784 LanguageServerToQuery::FirstCapable,
8785 request,
8786 cx,
8787 )
8788 })?
8789 .await?;
8790 this.update(&mut cx, |this, cx| {
8791 Ok(T::response_to_proto(
8792 response,
8793 this,
8794 sender_id,
8795 &buffer_handle.read(cx).version(),
8796 cx,
8797 ))
8798 })?
8799 }
8800
8801 async fn handle_lsp_query(
8802 lsp_store: Entity<Self>,
8803 envelope: TypedEnvelope<proto::LspQuery>,
8804 mut cx: AsyncApp,
8805 ) -> Result<proto::Ack> {
8806 use proto::lsp_query::Request;
8807 let sender_id = envelope.original_sender_id().unwrap_or_default();
8808 let lsp_query = envelope.payload;
8809 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8810 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8811 match lsp_query.request.context("invalid LSP query request")? {
8812 Request::GetReferences(get_references) => {
8813 let position = get_references.position.clone().and_then(deserialize_anchor);
8814 Self::query_lsp_locally::<GetReferences>(
8815 lsp_store,
8816 server_id,
8817 sender_id,
8818 lsp_request_id,
8819 get_references,
8820 position,
8821 &mut cx,
8822 )
8823 .await?;
8824 }
8825 Request::GetDocumentColor(get_document_color) => {
8826 Self::query_lsp_locally::<GetDocumentColor>(
8827 lsp_store,
8828 server_id,
8829 sender_id,
8830 lsp_request_id,
8831 get_document_color,
8832 None,
8833 &mut cx,
8834 )
8835 .await?;
8836 }
8837 Request::GetHover(get_hover) => {
8838 let position = get_hover.position.clone().and_then(deserialize_anchor);
8839 Self::query_lsp_locally::<GetHover>(
8840 lsp_store,
8841 server_id,
8842 sender_id,
8843 lsp_request_id,
8844 get_hover,
8845 position,
8846 &mut cx,
8847 )
8848 .await?;
8849 }
8850 Request::GetCodeActions(get_code_actions) => {
8851 Self::query_lsp_locally::<GetCodeActions>(
8852 lsp_store,
8853 server_id,
8854 sender_id,
8855 lsp_request_id,
8856 get_code_actions,
8857 None,
8858 &mut cx,
8859 )
8860 .await?;
8861 }
8862 Request::GetSignatureHelp(get_signature_help) => {
8863 let position = get_signature_help
8864 .position
8865 .clone()
8866 .and_then(deserialize_anchor);
8867 Self::query_lsp_locally::<GetSignatureHelp>(
8868 lsp_store,
8869 server_id,
8870 sender_id,
8871 lsp_request_id,
8872 get_signature_help,
8873 position,
8874 &mut cx,
8875 )
8876 .await?;
8877 }
8878 Request::GetCodeLens(get_code_lens) => {
8879 Self::query_lsp_locally::<GetCodeLens>(
8880 lsp_store,
8881 server_id,
8882 sender_id,
8883 lsp_request_id,
8884 get_code_lens,
8885 None,
8886 &mut cx,
8887 )
8888 .await?;
8889 }
8890 Request::GetDefinition(get_definition) => {
8891 let position = get_definition.position.clone().and_then(deserialize_anchor);
8892 Self::query_lsp_locally::<GetDefinitions>(
8893 lsp_store,
8894 server_id,
8895 sender_id,
8896 lsp_request_id,
8897 get_definition,
8898 position,
8899 &mut cx,
8900 )
8901 .await?;
8902 }
8903 Request::GetDeclaration(get_declaration) => {
8904 let position = get_declaration
8905 .position
8906 .clone()
8907 .and_then(deserialize_anchor);
8908 Self::query_lsp_locally::<GetDeclarations>(
8909 lsp_store,
8910 server_id,
8911 sender_id,
8912 lsp_request_id,
8913 get_declaration,
8914 position,
8915 &mut cx,
8916 )
8917 .await?;
8918 }
8919 Request::GetTypeDefinition(get_type_definition) => {
8920 let position = get_type_definition
8921 .position
8922 .clone()
8923 .and_then(deserialize_anchor);
8924 Self::query_lsp_locally::<GetTypeDefinitions>(
8925 lsp_store,
8926 server_id,
8927 sender_id,
8928 lsp_request_id,
8929 get_type_definition,
8930 position,
8931 &mut cx,
8932 )
8933 .await?;
8934 }
8935 Request::GetImplementation(get_implementation) => {
8936 let position = get_implementation
8937 .position
8938 .clone()
8939 .and_then(deserialize_anchor);
8940 Self::query_lsp_locally::<GetImplementations>(
8941 lsp_store,
8942 server_id,
8943 sender_id,
8944 lsp_request_id,
8945 get_implementation,
8946 position,
8947 &mut cx,
8948 )
8949 .await?;
8950 }
8951 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8952 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8953 let version = deserialize_version(get_document_diagnostics.buffer_version());
8954 let buffer = lsp_store.update(&mut cx, |this, cx| {
8955 this.buffer_store.read(cx).get_existing(buffer_id)
8956 })??;
8957 buffer
8958 .update(&mut cx, |buffer, _| {
8959 buffer.wait_for_version(version.clone())
8960 })?
8961 .await?;
8962 lsp_store.update(&mut cx, |lsp_store, cx| {
8963 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8964 let key = LspKey {
8965 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8966 server_queried: server_id,
8967 };
8968 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8969 ) {
8970 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8971 lsp_requests.clear();
8972 };
8973 }
8974
8975 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8976 existing_queries.insert(
8977 lsp_request_id,
8978 cx.spawn(async move |lsp_store, cx| {
8979 let diagnostics_pull = lsp_store
8980 .update(cx, |lsp_store, cx| {
8981 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8982 })
8983 .ok();
8984 if let Some(diagnostics_pull) = diagnostics_pull {
8985 match diagnostics_pull.await {
8986 Ok(()) => {}
8987 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8988 };
8989 }
8990 }),
8991 );
8992 })?;
8993 }
8994 Request::InlayHints(inlay_hints) => {
8995 let query_start = inlay_hints
8996 .start
8997 .clone()
8998 .and_then(deserialize_anchor)
8999 .context("invalid inlay hints range start")?;
9000 let query_end = inlay_hints
9001 .end
9002 .clone()
9003 .and_then(deserialize_anchor)
9004 .context("invalid inlay hints range end")?;
9005 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9006 &lsp_store,
9007 server_id,
9008 lsp_request_id,
9009 &inlay_hints,
9010 query_start..query_end,
9011 &mut cx,
9012 )
9013 .await
9014 .context("preparing inlay hints request")?;
9015 Self::query_lsp_locally::<InlayHints>(
9016 lsp_store,
9017 server_id,
9018 sender_id,
9019 lsp_request_id,
9020 inlay_hints,
9021 None,
9022 &mut cx,
9023 )
9024 .await
9025 .context("querying for inlay hints")?
9026 }
9027 }
9028 Ok(proto::Ack {})
9029 }
9030
9031 async fn handle_lsp_query_response(
9032 lsp_store: Entity<Self>,
9033 envelope: TypedEnvelope<proto::LspQueryResponse>,
9034 cx: AsyncApp,
9035 ) -> Result<()> {
9036 lsp_store.read_with(&cx, |lsp_store, _| {
9037 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9038 upstream_client.handle_lsp_response(envelope.clone());
9039 }
9040 })?;
9041 Ok(())
9042 }
9043
9044 async fn handle_apply_code_action(
9045 this: Entity<Self>,
9046 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9047 mut cx: AsyncApp,
9048 ) -> Result<proto::ApplyCodeActionResponse> {
9049 let sender_id = envelope.original_sender_id().unwrap_or_default();
9050 let action =
9051 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9052 let apply_code_action = this.update(&mut cx, |this, cx| {
9053 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9054 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9055 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9056 })??;
9057
9058 let project_transaction = apply_code_action.await?;
9059 let project_transaction = this.update(&mut cx, |this, cx| {
9060 this.buffer_store.update(cx, |buffer_store, cx| {
9061 buffer_store.serialize_project_transaction_for_peer(
9062 project_transaction,
9063 sender_id,
9064 cx,
9065 )
9066 })
9067 })?;
9068 Ok(proto::ApplyCodeActionResponse {
9069 transaction: Some(project_transaction),
9070 })
9071 }
9072
9073 async fn handle_register_buffer_with_language_servers(
9074 this: Entity<Self>,
9075 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9076 mut cx: AsyncApp,
9077 ) -> Result<proto::Ack> {
9078 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9079 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9080 this.update(&mut cx, |this, cx| {
9081 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9082 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9083 project_id: upstream_project_id,
9084 buffer_id: buffer_id.to_proto(),
9085 only_servers: envelope.payload.only_servers,
9086 });
9087 }
9088
9089 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9090 anyhow::bail!("buffer is not open");
9091 };
9092
9093 let handle = this.register_buffer_with_language_servers(
9094 &buffer,
9095 envelope
9096 .payload
9097 .only_servers
9098 .into_iter()
9099 .filter_map(|selector| {
9100 Some(match selector.selector? {
9101 proto::language_server_selector::Selector::ServerId(server_id) => {
9102 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9103 }
9104 proto::language_server_selector::Selector::Name(name) => {
9105 LanguageServerSelector::Name(LanguageServerName(
9106 SharedString::from(name),
9107 ))
9108 }
9109 })
9110 })
9111 .collect(),
9112 false,
9113 cx,
9114 );
9115 this.buffer_store().update(cx, |buffer_store, _| {
9116 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9117 });
9118
9119 Ok(())
9120 })??;
9121 Ok(proto::Ack {})
9122 }
9123
9124 async fn handle_rename_project_entry(
9125 this: Entity<Self>,
9126 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9127 mut cx: AsyncApp,
9128 ) -> Result<proto::ProjectEntryResponse> {
9129 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9130 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9131 let new_path =
9132 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9133
9134 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9135 .update(&mut cx, |this, cx| {
9136 let (worktree, entry) = this
9137 .worktree_store
9138 .read(cx)
9139 .worktree_and_entry_for_id(entry_id, cx)?;
9140 let new_worktree = this
9141 .worktree_store
9142 .read(cx)
9143 .worktree_for_id(new_worktree_id, cx)?;
9144 Some((
9145 this.worktree_store.clone(),
9146 worktree,
9147 new_worktree,
9148 entry.clone(),
9149 ))
9150 })?
9151 .context("worktree not found")?;
9152 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9153 (worktree.absolutize(&old_entry.path), worktree.id())
9154 })?;
9155 let new_abs_path =
9156 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9157
9158 let _transaction = Self::will_rename_entry(
9159 this.downgrade(),
9160 old_worktree_id,
9161 &old_abs_path,
9162 &new_abs_path,
9163 old_entry.is_dir(),
9164 cx.clone(),
9165 )
9166 .await;
9167 let response = WorktreeStore::handle_rename_project_entry(
9168 worktree_store,
9169 envelope.payload,
9170 cx.clone(),
9171 )
9172 .await;
9173 this.read_with(&cx, |this, _| {
9174 this.did_rename_entry(
9175 old_worktree_id,
9176 &old_abs_path,
9177 &new_abs_path,
9178 old_entry.is_dir(),
9179 );
9180 })
9181 .ok();
9182 response
9183 }
9184
9185 async fn handle_update_diagnostic_summary(
9186 this: Entity<Self>,
9187 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9188 mut cx: AsyncApp,
9189 ) -> Result<()> {
9190 this.update(&mut cx, |lsp_store, cx| {
9191 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9192 let mut updated_diagnostics_paths = HashMap::default();
9193 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9194 for message_summary in envelope
9195 .payload
9196 .summary
9197 .into_iter()
9198 .chain(envelope.payload.more_summaries)
9199 {
9200 let project_path = ProjectPath {
9201 worktree_id,
9202 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9203 };
9204 let path = project_path.path.clone();
9205 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9206 let summary = DiagnosticSummary {
9207 error_count: message_summary.error_count as usize,
9208 warning_count: message_summary.warning_count as usize,
9209 };
9210
9211 if summary.is_empty() {
9212 if let Some(worktree_summaries) =
9213 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9214 && let Some(summaries) = worktree_summaries.get_mut(&path)
9215 {
9216 summaries.remove(&server_id);
9217 if summaries.is_empty() {
9218 worktree_summaries.remove(&path);
9219 }
9220 }
9221 } else {
9222 lsp_store
9223 .diagnostic_summaries
9224 .entry(worktree_id)
9225 .or_default()
9226 .entry(path)
9227 .or_default()
9228 .insert(server_id, summary);
9229 }
9230
9231 if let Some((_, project_id)) = &lsp_store.downstream_client {
9232 match &mut diagnostics_summary {
9233 Some(diagnostics_summary) => {
9234 diagnostics_summary
9235 .more_summaries
9236 .push(proto::DiagnosticSummary {
9237 path: project_path.path.as_ref().to_proto(),
9238 language_server_id: server_id.0 as u64,
9239 error_count: summary.error_count as u32,
9240 warning_count: summary.warning_count as u32,
9241 })
9242 }
9243 None => {
9244 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9245 project_id: *project_id,
9246 worktree_id: worktree_id.to_proto(),
9247 summary: Some(proto::DiagnosticSummary {
9248 path: project_path.path.as_ref().to_proto(),
9249 language_server_id: server_id.0 as u64,
9250 error_count: summary.error_count as u32,
9251 warning_count: summary.warning_count as u32,
9252 }),
9253 more_summaries: Vec::new(),
9254 })
9255 }
9256 }
9257 }
9258 updated_diagnostics_paths
9259 .entry(server_id)
9260 .or_insert_with(Vec::new)
9261 .push(project_path);
9262 }
9263
9264 if let Some((diagnostics_summary, (downstream_client, _))) =
9265 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9266 {
9267 downstream_client.send(diagnostics_summary).log_err();
9268 }
9269 for (server_id, paths) in updated_diagnostics_paths {
9270 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9271 }
9272 Ok(())
9273 })?
9274 }
9275
9276 async fn handle_start_language_server(
9277 lsp_store: Entity<Self>,
9278 envelope: TypedEnvelope<proto::StartLanguageServer>,
9279 mut cx: AsyncApp,
9280 ) -> Result<()> {
9281 let server = envelope.payload.server.context("invalid server")?;
9282 let server_capabilities =
9283 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9284 .with_context(|| {
9285 format!(
9286 "incorrect server capabilities {}",
9287 envelope.payload.capabilities
9288 )
9289 })?;
9290 lsp_store.update(&mut cx, |lsp_store, cx| {
9291 let server_id = LanguageServerId(server.id as usize);
9292 let server_name = LanguageServerName::from_proto(server.name.clone());
9293 lsp_store
9294 .lsp_server_capabilities
9295 .insert(server_id, server_capabilities);
9296 lsp_store.language_server_statuses.insert(
9297 server_id,
9298 LanguageServerStatus {
9299 name: server_name.clone(),
9300 pending_work: Default::default(),
9301 has_pending_diagnostic_updates: false,
9302 progress_tokens: Default::default(),
9303 worktree: server.worktree_id.map(WorktreeId::from_proto),
9304 binary: None,
9305 configuration: None,
9306 workspace_folders: BTreeSet::new(),
9307 },
9308 );
9309 cx.emit(LspStoreEvent::LanguageServerAdded(
9310 server_id,
9311 server_name,
9312 server.worktree_id.map(WorktreeId::from_proto),
9313 ));
9314 cx.notify();
9315 })?;
9316 Ok(())
9317 }
9318
9319 async fn handle_update_language_server(
9320 lsp_store: Entity<Self>,
9321 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9322 mut cx: AsyncApp,
9323 ) -> Result<()> {
9324 lsp_store.update(&mut cx, |lsp_store, cx| {
9325 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9326
9327 match envelope.payload.variant.context("invalid variant")? {
9328 proto::update_language_server::Variant::WorkStart(payload) => {
9329 lsp_store.on_lsp_work_start(
9330 language_server_id,
9331 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9332 .context("invalid progress token value")?,
9333 LanguageServerProgress {
9334 title: payload.title,
9335 is_disk_based_diagnostics_progress: false,
9336 is_cancellable: payload.is_cancellable.unwrap_or(false),
9337 message: payload.message,
9338 percentage: payload.percentage.map(|p| p as usize),
9339 last_update_at: cx.background_executor().now(),
9340 },
9341 cx,
9342 );
9343 }
9344 proto::update_language_server::Variant::WorkProgress(payload) => {
9345 lsp_store.on_lsp_work_progress(
9346 language_server_id,
9347 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9348 .context("invalid progress token value")?,
9349 LanguageServerProgress {
9350 title: None,
9351 is_disk_based_diagnostics_progress: false,
9352 is_cancellable: payload.is_cancellable.unwrap_or(false),
9353 message: payload.message,
9354 percentage: payload.percentage.map(|p| p as usize),
9355 last_update_at: cx.background_executor().now(),
9356 },
9357 cx,
9358 );
9359 }
9360
9361 proto::update_language_server::Variant::WorkEnd(payload) => {
9362 lsp_store.on_lsp_work_end(
9363 language_server_id,
9364 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9365 .context("invalid progress token value")?,
9366 cx,
9367 );
9368 }
9369
9370 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9371 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9372 }
9373
9374 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9375 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9376 }
9377
9378 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9379 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9380 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9381 cx.emit(LspStoreEvent::LanguageServerUpdate {
9382 language_server_id,
9383 name: envelope
9384 .payload
9385 .server_name
9386 .map(SharedString::new)
9387 .map(LanguageServerName),
9388 message: non_lsp,
9389 });
9390 }
9391 }
9392
9393 Ok(())
9394 })?
9395 }
9396
9397 async fn handle_language_server_log(
9398 this: Entity<Self>,
9399 envelope: TypedEnvelope<proto::LanguageServerLog>,
9400 mut cx: AsyncApp,
9401 ) -> Result<()> {
9402 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9403 let log_type = envelope
9404 .payload
9405 .log_type
9406 .map(LanguageServerLogType::from_proto)
9407 .context("invalid language server log type")?;
9408
9409 let message = envelope.payload.message;
9410
9411 this.update(&mut cx, |_, cx| {
9412 cx.emit(LspStoreEvent::LanguageServerLog(
9413 language_server_id,
9414 log_type,
9415 message,
9416 ));
9417 })
9418 }
9419
9420 async fn handle_lsp_ext_cancel_flycheck(
9421 lsp_store: Entity<Self>,
9422 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9423 cx: AsyncApp,
9424 ) -> Result<proto::Ack> {
9425 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9426 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9427 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9428 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9429 } else {
9430 None
9431 }
9432 })?;
9433 if let Some(task) = task {
9434 task.context("handling lsp ext cancel flycheck")?;
9435 }
9436
9437 Ok(proto::Ack {})
9438 }
9439
9440 async fn handle_lsp_ext_run_flycheck(
9441 lsp_store: Entity<Self>,
9442 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9443 mut cx: AsyncApp,
9444 ) -> Result<proto::Ack> {
9445 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9446 lsp_store.update(&mut cx, |lsp_store, cx| {
9447 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9448 let text_document = if envelope.payload.current_file_only {
9449 let buffer_id = envelope
9450 .payload
9451 .buffer_id
9452 .map(|id| BufferId::new(id))
9453 .transpose()?;
9454 buffer_id
9455 .and_then(|buffer_id| {
9456 lsp_store
9457 .buffer_store()
9458 .read(cx)
9459 .get(buffer_id)
9460 .and_then(|buffer| {
9461 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9462 })
9463 .map(|path| make_text_document_identifier(&path))
9464 })
9465 .transpose()?
9466 } else {
9467 None
9468 };
9469 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9470 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9471 )?;
9472 }
9473 anyhow::Ok(())
9474 })??;
9475
9476 Ok(proto::Ack {})
9477 }
9478
9479 async fn handle_lsp_ext_clear_flycheck(
9480 lsp_store: Entity<Self>,
9481 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9482 cx: AsyncApp,
9483 ) -> Result<proto::Ack> {
9484 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9485 lsp_store
9486 .read_with(&cx, |lsp_store, _| {
9487 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9488 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9489 } else {
9490 None
9491 }
9492 })
9493 .context("handling lsp ext clear flycheck")?;
9494
9495 Ok(proto::Ack {})
9496 }
9497
9498 pub fn disk_based_diagnostics_started(
9499 &mut self,
9500 language_server_id: LanguageServerId,
9501 cx: &mut Context<Self>,
9502 ) {
9503 if let Some(language_server_status) =
9504 self.language_server_statuses.get_mut(&language_server_id)
9505 {
9506 language_server_status.has_pending_diagnostic_updates = true;
9507 }
9508
9509 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9510 cx.emit(LspStoreEvent::LanguageServerUpdate {
9511 language_server_id,
9512 name: self
9513 .language_server_adapter_for_id(language_server_id)
9514 .map(|adapter| adapter.name()),
9515 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9516 Default::default(),
9517 ),
9518 })
9519 }
9520
9521 pub fn disk_based_diagnostics_finished(
9522 &mut self,
9523 language_server_id: LanguageServerId,
9524 cx: &mut Context<Self>,
9525 ) {
9526 if let Some(language_server_status) =
9527 self.language_server_statuses.get_mut(&language_server_id)
9528 {
9529 language_server_status.has_pending_diagnostic_updates = false;
9530 }
9531
9532 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9533 cx.emit(LspStoreEvent::LanguageServerUpdate {
9534 language_server_id,
9535 name: self
9536 .language_server_adapter_for_id(language_server_id)
9537 .map(|adapter| adapter.name()),
9538 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9539 Default::default(),
9540 ),
9541 })
9542 }
9543
9544 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9545 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9546 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9547 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9548 // the language server might take some time to publish diagnostics.
9549 fn simulate_disk_based_diagnostics_events_if_needed(
9550 &mut self,
9551 language_server_id: LanguageServerId,
9552 cx: &mut Context<Self>,
9553 ) {
9554 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9555
9556 let Some(LanguageServerState::Running {
9557 simulate_disk_based_diagnostics_completion,
9558 adapter,
9559 ..
9560 }) = self
9561 .as_local_mut()
9562 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9563 else {
9564 return;
9565 };
9566
9567 if adapter.disk_based_diagnostics_progress_token.is_some() {
9568 return;
9569 }
9570
9571 let prev_task =
9572 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9573 cx.background_executor()
9574 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9575 .await;
9576
9577 this.update(cx, |this, cx| {
9578 this.disk_based_diagnostics_finished(language_server_id, cx);
9579
9580 if let Some(LanguageServerState::Running {
9581 simulate_disk_based_diagnostics_completion,
9582 ..
9583 }) = this.as_local_mut().and_then(|local_store| {
9584 local_store.language_servers.get_mut(&language_server_id)
9585 }) {
9586 *simulate_disk_based_diagnostics_completion = None;
9587 }
9588 })
9589 .ok();
9590 }));
9591
9592 if prev_task.is_none() {
9593 self.disk_based_diagnostics_started(language_server_id, cx);
9594 }
9595 }
9596
9597 pub fn language_server_statuses(
9598 &self,
9599 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9600 self.language_server_statuses
9601 .iter()
9602 .map(|(key, value)| (*key, value))
9603 }
9604
9605 pub(super) fn did_rename_entry(
9606 &self,
9607 worktree_id: WorktreeId,
9608 old_path: &Path,
9609 new_path: &Path,
9610 is_dir: bool,
9611 ) {
9612 maybe!({
9613 let local_store = self.as_local()?;
9614
9615 let old_uri = lsp::Uri::from_file_path(old_path)
9616 .ok()
9617 .map(|uri| uri.to_string())?;
9618 let new_uri = lsp::Uri::from_file_path(new_path)
9619 .ok()
9620 .map(|uri| uri.to_string())?;
9621
9622 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9623 let Some(filter) = local_store
9624 .language_server_paths_watched_for_rename
9625 .get(&language_server.server_id())
9626 else {
9627 continue;
9628 };
9629
9630 if filter.should_send_did_rename(&old_uri, is_dir) {
9631 language_server
9632 .notify::<DidRenameFiles>(RenameFilesParams {
9633 files: vec![FileRename {
9634 old_uri: old_uri.clone(),
9635 new_uri: new_uri.clone(),
9636 }],
9637 })
9638 .ok();
9639 }
9640 }
9641 Some(())
9642 });
9643 }
9644
9645 pub(super) fn will_rename_entry(
9646 this: WeakEntity<Self>,
9647 worktree_id: WorktreeId,
9648 old_path: &Path,
9649 new_path: &Path,
9650 is_dir: bool,
9651 cx: AsyncApp,
9652 ) -> Task<ProjectTransaction> {
9653 let old_uri = lsp::Uri::from_file_path(old_path)
9654 .ok()
9655 .map(|uri| uri.to_string());
9656 let new_uri = lsp::Uri::from_file_path(new_path)
9657 .ok()
9658 .map(|uri| uri.to_string());
9659 cx.spawn(async move |cx| {
9660 let mut tasks = vec![];
9661 this.update(cx, |this, cx| {
9662 let local_store = this.as_local()?;
9663 let old_uri = old_uri?;
9664 let new_uri = new_uri?;
9665 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9666 let Some(filter) = local_store
9667 .language_server_paths_watched_for_rename
9668 .get(&language_server.server_id())
9669 else {
9670 continue;
9671 };
9672
9673 if filter.should_send_will_rename(&old_uri, is_dir) {
9674 let apply_edit = cx.spawn({
9675 let old_uri = old_uri.clone();
9676 let new_uri = new_uri.clone();
9677 let language_server = language_server.clone();
9678 async move |this, cx| {
9679 let edit = language_server
9680 .request::<WillRenameFiles>(RenameFilesParams {
9681 files: vec![FileRename { old_uri, new_uri }],
9682 })
9683 .await
9684 .into_response()
9685 .context("will rename files")
9686 .log_err()
9687 .flatten()?;
9688
9689 let transaction = LocalLspStore::deserialize_workspace_edit(
9690 this.upgrade()?,
9691 edit,
9692 false,
9693 language_server.clone(),
9694 cx,
9695 )
9696 .await
9697 .ok()?;
9698 Some(transaction)
9699 }
9700 });
9701 tasks.push(apply_edit);
9702 }
9703 }
9704 Some(())
9705 })
9706 .ok()
9707 .flatten();
9708 let mut merged_transaction = ProjectTransaction::default();
9709 for task in tasks {
9710 // Await on tasks sequentially so that the order of application of edits is deterministic
9711 // (at least with regards to the order of registration of language servers)
9712 if let Some(transaction) = task.await {
9713 for (buffer, buffer_transaction) in transaction.0 {
9714 merged_transaction.0.insert(buffer, buffer_transaction);
9715 }
9716 }
9717 }
9718 merged_transaction
9719 })
9720 }
9721
9722 fn lsp_notify_abs_paths_changed(
9723 &mut self,
9724 server_id: LanguageServerId,
9725 changes: Vec<PathEvent>,
9726 ) {
9727 maybe!({
9728 let server = self.language_server_for_id(server_id)?;
9729 let changes = changes
9730 .into_iter()
9731 .filter_map(|event| {
9732 let typ = match event.kind? {
9733 PathEventKind::Created => lsp::FileChangeType::CREATED,
9734 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9735 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9736 };
9737 Some(lsp::FileEvent {
9738 uri: file_path_to_lsp_url(&event.path).log_err()?,
9739 typ,
9740 })
9741 })
9742 .collect::<Vec<_>>();
9743 if !changes.is_empty() {
9744 server
9745 .notify::<lsp::notification::DidChangeWatchedFiles>(
9746 lsp::DidChangeWatchedFilesParams { changes },
9747 )
9748 .ok();
9749 }
9750 Some(())
9751 });
9752 }
9753
9754 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9755 self.as_local()?.language_server_for_id(id)
9756 }
9757
9758 fn on_lsp_progress(
9759 &mut self,
9760 progress_params: lsp::ProgressParams,
9761 language_server_id: LanguageServerId,
9762 disk_based_diagnostics_progress_token: Option<String>,
9763 cx: &mut Context<Self>,
9764 ) {
9765 match progress_params.value {
9766 lsp::ProgressParamsValue::WorkDone(progress) => {
9767 self.handle_work_done_progress(
9768 progress,
9769 language_server_id,
9770 disk_based_diagnostics_progress_token,
9771 ProgressToken::from_lsp(progress_params.token),
9772 cx,
9773 );
9774 }
9775 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9776 let registration_id = match progress_params.token {
9777 lsp::NumberOrString::Number(_) => None,
9778 lsp::NumberOrString::String(token) => token
9779 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9780 .map(|(_, id)| id.to_owned()),
9781 };
9782 if let Some(LanguageServerState::Running {
9783 workspace_diagnostics_refresh_tasks,
9784 ..
9785 }) = self
9786 .as_local_mut()
9787 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9788 && let Some(workspace_diagnostics) =
9789 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9790 {
9791 workspace_diagnostics.progress_tx.try_send(()).ok();
9792 self.apply_workspace_diagnostic_report(
9793 language_server_id,
9794 report,
9795 registration_id.map(SharedString::from),
9796 cx,
9797 )
9798 }
9799 }
9800 }
9801 }
9802
9803 fn handle_work_done_progress(
9804 &mut self,
9805 progress: lsp::WorkDoneProgress,
9806 language_server_id: LanguageServerId,
9807 disk_based_diagnostics_progress_token: Option<String>,
9808 token: ProgressToken,
9809 cx: &mut Context<Self>,
9810 ) {
9811 let language_server_status =
9812 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9813 status
9814 } else {
9815 return;
9816 };
9817
9818 if !language_server_status.progress_tokens.contains(&token) {
9819 return;
9820 }
9821
9822 let is_disk_based_diagnostics_progress =
9823 if let (Some(disk_based_token), ProgressToken::String(token)) =
9824 (&disk_based_diagnostics_progress_token, &token)
9825 {
9826 token.starts_with(disk_based_token)
9827 } else {
9828 false
9829 };
9830
9831 match progress {
9832 lsp::WorkDoneProgress::Begin(report) => {
9833 if is_disk_based_diagnostics_progress {
9834 self.disk_based_diagnostics_started(language_server_id, cx);
9835 }
9836 self.on_lsp_work_start(
9837 language_server_id,
9838 token.clone(),
9839 LanguageServerProgress {
9840 title: Some(report.title),
9841 is_disk_based_diagnostics_progress,
9842 is_cancellable: report.cancellable.unwrap_or(false),
9843 message: report.message.clone(),
9844 percentage: report.percentage.map(|p| p as usize),
9845 last_update_at: cx.background_executor().now(),
9846 },
9847 cx,
9848 );
9849 }
9850 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9851 language_server_id,
9852 token,
9853 LanguageServerProgress {
9854 title: None,
9855 is_disk_based_diagnostics_progress,
9856 is_cancellable: report.cancellable.unwrap_or(false),
9857 message: report.message,
9858 percentage: report.percentage.map(|p| p as usize),
9859 last_update_at: cx.background_executor().now(),
9860 },
9861 cx,
9862 ),
9863 lsp::WorkDoneProgress::End(_) => {
9864 language_server_status.progress_tokens.remove(&token);
9865 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9866 if is_disk_based_diagnostics_progress {
9867 self.disk_based_diagnostics_finished(language_server_id, cx);
9868 }
9869 }
9870 }
9871 }
9872
9873 fn on_lsp_work_start(
9874 &mut self,
9875 language_server_id: LanguageServerId,
9876 token: ProgressToken,
9877 progress: LanguageServerProgress,
9878 cx: &mut Context<Self>,
9879 ) {
9880 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9881 status.pending_work.insert(token.clone(), progress.clone());
9882 cx.notify();
9883 }
9884 cx.emit(LspStoreEvent::LanguageServerUpdate {
9885 language_server_id,
9886 name: self
9887 .language_server_adapter_for_id(language_server_id)
9888 .map(|adapter| adapter.name()),
9889 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9890 token: Some(token.to_proto()),
9891 title: progress.title,
9892 message: progress.message,
9893 percentage: progress.percentage.map(|p| p as u32),
9894 is_cancellable: Some(progress.is_cancellable),
9895 }),
9896 })
9897 }
9898
9899 fn on_lsp_work_progress(
9900 &mut self,
9901 language_server_id: LanguageServerId,
9902 token: ProgressToken,
9903 progress: LanguageServerProgress,
9904 cx: &mut Context<Self>,
9905 ) {
9906 let mut did_update = false;
9907 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9908 match status.pending_work.entry(token.clone()) {
9909 btree_map::Entry::Vacant(entry) => {
9910 entry.insert(progress.clone());
9911 did_update = true;
9912 }
9913 btree_map::Entry::Occupied(mut entry) => {
9914 let entry = entry.get_mut();
9915 if (progress.last_update_at - entry.last_update_at)
9916 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9917 {
9918 entry.last_update_at = progress.last_update_at;
9919 if progress.message.is_some() {
9920 entry.message = progress.message.clone();
9921 }
9922 if progress.percentage.is_some() {
9923 entry.percentage = progress.percentage;
9924 }
9925 if progress.is_cancellable != entry.is_cancellable {
9926 entry.is_cancellable = progress.is_cancellable;
9927 }
9928 did_update = true;
9929 }
9930 }
9931 }
9932 }
9933
9934 if did_update {
9935 cx.emit(LspStoreEvent::LanguageServerUpdate {
9936 language_server_id,
9937 name: self
9938 .language_server_adapter_for_id(language_server_id)
9939 .map(|adapter| adapter.name()),
9940 message: proto::update_language_server::Variant::WorkProgress(
9941 proto::LspWorkProgress {
9942 token: Some(token.to_proto()),
9943 message: progress.message,
9944 percentage: progress.percentage.map(|p| p as u32),
9945 is_cancellable: Some(progress.is_cancellable),
9946 },
9947 ),
9948 })
9949 }
9950 }
9951
9952 fn on_lsp_work_end(
9953 &mut self,
9954 language_server_id: LanguageServerId,
9955 token: ProgressToken,
9956 cx: &mut Context<Self>,
9957 ) {
9958 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9959 if let Some(work) = status.pending_work.remove(&token)
9960 && !work.is_disk_based_diagnostics_progress
9961 {
9962 cx.emit(LspStoreEvent::RefreshInlayHints {
9963 server_id: language_server_id,
9964 request_id: None,
9965 });
9966 }
9967 cx.notify();
9968 }
9969
9970 cx.emit(LspStoreEvent::LanguageServerUpdate {
9971 language_server_id,
9972 name: self
9973 .language_server_adapter_for_id(language_server_id)
9974 .map(|adapter| adapter.name()),
9975 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9976 token: Some(token.to_proto()),
9977 }),
9978 })
9979 }
9980
9981 pub async fn handle_resolve_completion_documentation(
9982 this: Entity<Self>,
9983 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9984 mut cx: AsyncApp,
9985 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9986 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9987
9988 let completion = this
9989 .read_with(&cx, |this, cx| {
9990 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9991 let server = this
9992 .language_server_for_id(id)
9993 .with_context(|| format!("No language server {id}"))?;
9994
9995 anyhow::Ok(cx.background_spawn(async move {
9996 let can_resolve = server
9997 .capabilities()
9998 .completion_provider
9999 .as_ref()
10000 .and_then(|options| options.resolve_provider)
10001 .unwrap_or(false);
10002 if can_resolve {
10003 server
10004 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10005 .await
10006 .into_response()
10007 .context("resolve completion item")
10008 } else {
10009 anyhow::Ok(lsp_completion)
10010 }
10011 }))
10012 })??
10013 .await?;
10014
10015 let mut documentation_is_markdown = false;
10016 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10017 let documentation = match completion.documentation {
10018 Some(lsp::Documentation::String(text)) => text,
10019
10020 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10021 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10022 value
10023 }
10024
10025 _ => String::new(),
10026 };
10027
10028 // If we have a new buffer_id, that means we're talking to a new client
10029 // and want to check for new text_edits in the completion too.
10030 let mut old_replace_start = None;
10031 let mut old_replace_end = None;
10032 let mut old_insert_start = None;
10033 let mut old_insert_end = None;
10034 let mut new_text = String::default();
10035 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10036 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10037 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10038 anyhow::Ok(buffer.read(cx).snapshot())
10039 })??;
10040
10041 if let Some(text_edit) = completion.text_edit.as_ref() {
10042 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10043
10044 if let Some(mut edit) = edit {
10045 LineEnding::normalize(&mut edit.new_text);
10046
10047 new_text = edit.new_text;
10048 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10049 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10050 if let Some(insert_range) = edit.insert_range {
10051 old_insert_start = Some(serialize_anchor(&insert_range.start));
10052 old_insert_end = Some(serialize_anchor(&insert_range.end));
10053 }
10054 }
10055 }
10056 }
10057
10058 Ok(proto::ResolveCompletionDocumentationResponse {
10059 documentation,
10060 documentation_is_markdown,
10061 old_replace_start,
10062 old_replace_end,
10063 new_text,
10064 lsp_completion,
10065 old_insert_start,
10066 old_insert_end,
10067 })
10068 }
10069
10070 async fn handle_on_type_formatting(
10071 this: Entity<Self>,
10072 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10073 mut cx: AsyncApp,
10074 ) -> Result<proto::OnTypeFormattingResponse> {
10075 let on_type_formatting = this.update(&mut cx, |this, cx| {
10076 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10077 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10078 let position = envelope
10079 .payload
10080 .position
10081 .and_then(deserialize_anchor)
10082 .context("invalid position")?;
10083 anyhow::Ok(this.apply_on_type_formatting(
10084 buffer,
10085 position,
10086 envelope.payload.trigger.clone(),
10087 cx,
10088 ))
10089 })??;
10090
10091 let transaction = on_type_formatting
10092 .await?
10093 .as_ref()
10094 .map(language::proto::serialize_transaction);
10095 Ok(proto::OnTypeFormattingResponse { transaction })
10096 }
10097
10098 async fn handle_refresh_inlay_hints(
10099 lsp_store: Entity<Self>,
10100 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10101 mut cx: AsyncApp,
10102 ) -> Result<proto::Ack> {
10103 lsp_store.update(&mut cx, |_, cx| {
10104 cx.emit(LspStoreEvent::RefreshInlayHints {
10105 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10106 request_id: envelope.payload.request_id.map(|id| id as usize),
10107 });
10108 })?;
10109 Ok(proto::Ack {})
10110 }
10111
10112 async fn handle_pull_workspace_diagnostics(
10113 lsp_store: Entity<Self>,
10114 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10115 mut cx: AsyncApp,
10116 ) -> Result<proto::Ack> {
10117 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10118 lsp_store.update(&mut cx, |lsp_store, _| {
10119 lsp_store.pull_workspace_diagnostics(server_id);
10120 })?;
10121 Ok(proto::Ack {})
10122 }
10123
10124 async fn handle_get_color_presentation(
10125 lsp_store: Entity<Self>,
10126 envelope: TypedEnvelope<proto::GetColorPresentation>,
10127 mut cx: AsyncApp,
10128 ) -> Result<proto::GetColorPresentationResponse> {
10129 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10130 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10131 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10132 })??;
10133
10134 let color = envelope
10135 .payload
10136 .color
10137 .context("invalid color resolve request")?;
10138 let start = color
10139 .lsp_range_start
10140 .context("invalid color resolve request")?;
10141 let end = color
10142 .lsp_range_end
10143 .context("invalid color resolve request")?;
10144
10145 let color = DocumentColor {
10146 lsp_range: lsp::Range {
10147 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10148 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10149 },
10150 color: lsp::Color {
10151 red: color.red,
10152 green: color.green,
10153 blue: color.blue,
10154 alpha: color.alpha,
10155 },
10156 resolved: false,
10157 color_presentations: Vec::new(),
10158 };
10159 let resolved_color = lsp_store
10160 .update(&mut cx, |lsp_store, cx| {
10161 lsp_store.resolve_color_presentation(
10162 color,
10163 buffer.clone(),
10164 LanguageServerId(envelope.payload.server_id as usize),
10165 cx,
10166 )
10167 })?
10168 .await
10169 .context("resolving color presentation")?;
10170
10171 Ok(proto::GetColorPresentationResponse {
10172 presentations: resolved_color
10173 .color_presentations
10174 .into_iter()
10175 .map(|presentation| proto::ColorPresentation {
10176 label: presentation.label.to_string(),
10177 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10178 additional_text_edits: presentation
10179 .additional_text_edits
10180 .into_iter()
10181 .map(serialize_lsp_edit)
10182 .collect(),
10183 })
10184 .collect(),
10185 })
10186 }
10187
10188 async fn handle_resolve_inlay_hint(
10189 lsp_store: Entity<Self>,
10190 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10191 mut cx: AsyncApp,
10192 ) -> Result<proto::ResolveInlayHintResponse> {
10193 let proto_hint = envelope
10194 .payload
10195 .hint
10196 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10197 let hint = InlayHints::proto_to_project_hint(proto_hint)
10198 .context("resolved proto inlay hint conversion")?;
10199 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10200 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10201 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10202 })??;
10203 let response_hint = lsp_store
10204 .update(&mut cx, |lsp_store, cx| {
10205 lsp_store.resolve_inlay_hint(
10206 hint,
10207 buffer,
10208 LanguageServerId(envelope.payload.language_server_id as usize),
10209 cx,
10210 )
10211 })?
10212 .await
10213 .context("inlay hints fetch")?;
10214 Ok(proto::ResolveInlayHintResponse {
10215 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10216 })
10217 }
10218
10219 async fn handle_refresh_code_lens(
10220 this: Entity<Self>,
10221 _: TypedEnvelope<proto::RefreshCodeLens>,
10222 mut cx: AsyncApp,
10223 ) -> Result<proto::Ack> {
10224 this.update(&mut cx, |_, cx| {
10225 cx.emit(LspStoreEvent::RefreshCodeLens);
10226 })?;
10227 Ok(proto::Ack {})
10228 }
10229
10230 async fn handle_open_buffer_for_symbol(
10231 this: Entity<Self>,
10232 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10233 mut cx: AsyncApp,
10234 ) -> Result<proto::OpenBufferForSymbolResponse> {
10235 let peer_id = envelope.original_sender_id().unwrap_or_default();
10236 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10237 let symbol = Self::deserialize_symbol(symbol)?;
10238 this.read_with(&cx, |this, _| {
10239 if let SymbolLocation::OutsideProject {
10240 abs_path,
10241 signature,
10242 } = &symbol.path
10243 {
10244 let new_signature = this.symbol_signature(&abs_path);
10245 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10246 }
10247 Ok(())
10248 })??;
10249 let buffer = this
10250 .update(&mut cx, |this, cx| {
10251 this.open_buffer_for_symbol(
10252 &Symbol {
10253 language_server_name: symbol.language_server_name,
10254 source_worktree_id: symbol.source_worktree_id,
10255 source_language_server_id: symbol.source_language_server_id,
10256 path: symbol.path,
10257 name: symbol.name,
10258 kind: symbol.kind,
10259 range: symbol.range,
10260 label: CodeLabel::default(),
10261 },
10262 cx,
10263 )
10264 })?
10265 .await?;
10266
10267 this.update(&mut cx, |this, cx| {
10268 let is_private = buffer
10269 .read(cx)
10270 .file()
10271 .map(|f| f.is_private())
10272 .unwrap_or_default();
10273 if is_private {
10274 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10275 } else {
10276 this.buffer_store
10277 .update(cx, |buffer_store, cx| {
10278 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10279 })
10280 .detach_and_log_err(cx);
10281 let buffer_id = buffer.read(cx).remote_id().to_proto();
10282 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10283 }
10284 })?
10285 }
10286
10287 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10288 let mut hasher = Sha256::new();
10289 hasher.update(abs_path.to_string_lossy().as_bytes());
10290 hasher.update(self.nonce.to_be_bytes());
10291 hasher.finalize().as_slice().try_into().unwrap()
10292 }
10293
10294 pub async fn handle_get_project_symbols(
10295 this: Entity<Self>,
10296 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10297 mut cx: AsyncApp,
10298 ) -> Result<proto::GetProjectSymbolsResponse> {
10299 let symbols = this
10300 .update(&mut cx, |this, cx| {
10301 this.symbols(&envelope.payload.query, cx)
10302 })?
10303 .await?;
10304
10305 Ok(proto::GetProjectSymbolsResponse {
10306 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10307 })
10308 }
10309
10310 pub async fn handle_restart_language_servers(
10311 this: Entity<Self>,
10312 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10313 mut cx: AsyncApp,
10314 ) -> Result<proto::Ack> {
10315 this.update(&mut cx, |lsp_store, cx| {
10316 let buffers =
10317 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10318 lsp_store.restart_language_servers_for_buffers(
10319 buffers,
10320 envelope
10321 .payload
10322 .only_servers
10323 .into_iter()
10324 .filter_map(|selector| {
10325 Some(match selector.selector? {
10326 proto::language_server_selector::Selector::ServerId(server_id) => {
10327 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10328 }
10329 proto::language_server_selector::Selector::Name(name) => {
10330 LanguageServerSelector::Name(LanguageServerName(
10331 SharedString::from(name),
10332 ))
10333 }
10334 })
10335 })
10336 .collect(),
10337 cx,
10338 );
10339 })?;
10340
10341 Ok(proto::Ack {})
10342 }
10343
10344 pub async fn handle_stop_language_servers(
10345 lsp_store: Entity<Self>,
10346 envelope: TypedEnvelope<proto::StopLanguageServers>,
10347 mut cx: AsyncApp,
10348 ) -> Result<proto::Ack> {
10349 lsp_store.update(&mut cx, |lsp_store, cx| {
10350 if envelope.payload.all
10351 && envelope.payload.also_servers.is_empty()
10352 && envelope.payload.buffer_ids.is_empty()
10353 {
10354 lsp_store.stop_all_language_servers(cx);
10355 } else {
10356 let buffers =
10357 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10358 lsp_store
10359 .stop_language_servers_for_buffers(
10360 buffers,
10361 envelope
10362 .payload
10363 .also_servers
10364 .into_iter()
10365 .filter_map(|selector| {
10366 Some(match selector.selector? {
10367 proto::language_server_selector::Selector::ServerId(
10368 server_id,
10369 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10370 server_id,
10371 )),
10372 proto::language_server_selector::Selector::Name(name) => {
10373 LanguageServerSelector::Name(LanguageServerName(
10374 SharedString::from(name),
10375 ))
10376 }
10377 })
10378 })
10379 .collect(),
10380 cx,
10381 )
10382 .detach_and_log_err(cx);
10383 }
10384 })?;
10385
10386 Ok(proto::Ack {})
10387 }
10388
10389 pub async fn handle_cancel_language_server_work(
10390 lsp_store: Entity<Self>,
10391 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10392 mut cx: AsyncApp,
10393 ) -> Result<proto::Ack> {
10394 lsp_store.update(&mut cx, |lsp_store, cx| {
10395 if let Some(work) = envelope.payload.work {
10396 match work {
10397 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10398 let buffers =
10399 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10400 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10401 }
10402 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10403 let server_id = LanguageServerId::from_proto(work.language_server_id);
10404 let token = work
10405 .token
10406 .map(|token| {
10407 ProgressToken::from_proto(token)
10408 .context("invalid work progress token")
10409 })
10410 .transpose()?;
10411 lsp_store.cancel_language_server_work(server_id, token, cx);
10412 }
10413 }
10414 }
10415 anyhow::Ok(())
10416 })??;
10417
10418 Ok(proto::Ack {})
10419 }
10420
10421 fn buffer_ids_to_buffers(
10422 &mut self,
10423 buffer_ids: impl Iterator<Item = u64>,
10424 cx: &mut Context<Self>,
10425 ) -> Vec<Entity<Buffer>> {
10426 buffer_ids
10427 .into_iter()
10428 .flat_map(|buffer_id| {
10429 self.buffer_store
10430 .read(cx)
10431 .get(BufferId::new(buffer_id).log_err()?)
10432 })
10433 .collect::<Vec<_>>()
10434 }
10435
10436 async fn handle_apply_additional_edits_for_completion(
10437 this: Entity<Self>,
10438 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10439 mut cx: AsyncApp,
10440 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10441 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10442 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10443 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10444 let completion = Self::deserialize_completion(
10445 envelope.payload.completion.context("invalid completion")?,
10446 )?;
10447 anyhow::Ok((buffer, completion))
10448 })??;
10449
10450 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10451 this.apply_additional_edits_for_completion(
10452 buffer,
10453 Rc::new(RefCell::new(Box::new([Completion {
10454 replace_range: completion.replace_range,
10455 new_text: completion.new_text,
10456 source: completion.source,
10457 documentation: None,
10458 label: CodeLabel::default(),
10459 match_start: None,
10460 snippet_deduplication_key: None,
10461 insert_text_mode: None,
10462 icon_path: None,
10463 confirm: None,
10464 }]))),
10465 0,
10466 false,
10467 cx,
10468 )
10469 })?;
10470
10471 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10472 transaction: apply_additional_edits
10473 .await?
10474 .as_ref()
10475 .map(language::proto::serialize_transaction),
10476 })
10477 }
10478
10479 pub fn last_formatting_failure(&self) -> Option<&str> {
10480 self.last_formatting_failure.as_deref()
10481 }
10482
10483 pub fn reset_last_formatting_failure(&mut self) {
10484 self.last_formatting_failure = None;
10485 }
10486
10487 pub fn environment_for_buffer(
10488 &self,
10489 buffer: &Entity<Buffer>,
10490 cx: &mut Context<Self>,
10491 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10492 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10493 environment.update(cx, |env, cx| {
10494 env.buffer_environment(buffer, &self.worktree_store, cx)
10495 })
10496 } else {
10497 Task::ready(None).shared()
10498 }
10499 }
10500
10501 pub fn format(
10502 &mut self,
10503 buffers: HashSet<Entity<Buffer>>,
10504 target: LspFormatTarget,
10505 push_to_history: bool,
10506 trigger: FormatTrigger,
10507 cx: &mut Context<Self>,
10508 ) -> Task<anyhow::Result<ProjectTransaction>> {
10509 let logger = zlog::scoped!("format");
10510 if self.as_local().is_some() {
10511 zlog::trace!(logger => "Formatting locally");
10512 let logger = zlog::scoped!(logger => "local");
10513 let buffers = buffers
10514 .into_iter()
10515 .map(|buffer_handle| {
10516 let buffer = buffer_handle.read(cx);
10517 let buffer_abs_path = File::from_dyn(buffer.file())
10518 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10519
10520 (buffer_handle, buffer_abs_path, buffer.remote_id())
10521 })
10522 .collect::<Vec<_>>();
10523
10524 cx.spawn(async move |lsp_store, cx| {
10525 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10526
10527 for (handle, abs_path, id) in buffers {
10528 let env = lsp_store
10529 .update(cx, |lsp_store, cx| {
10530 lsp_store.environment_for_buffer(&handle, cx)
10531 })?
10532 .await;
10533
10534 let ranges = match &target {
10535 LspFormatTarget::Buffers => None,
10536 LspFormatTarget::Ranges(ranges) => {
10537 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10538 }
10539 };
10540
10541 formattable_buffers.push(FormattableBuffer {
10542 handle,
10543 abs_path,
10544 env,
10545 ranges,
10546 });
10547 }
10548 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10549
10550 let format_timer = zlog::time!(logger => "Formatting buffers");
10551 let result = LocalLspStore::format_locally(
10552 lsp_store.clone(),
10553 formattable_buffers,
10554 push_to_history,
10555 trigger,
10556 logger,
10557 cx,
10558 )
10559 .await;
10560 format_timer.end();
10561
10562 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10563
10564 lsp_store.update(cx, |lsp_store, _| {
10565 lsp_store.update_last_formatting_failure(&result);
10566 })?;
10567
10568 result
10569 })
10570 } else if let Some((client, project_id)) = self.upstream_client() {
10571 zlog::trace!(logger => "Formatting remotely");
10572 let logger = zlog::scoped!(logger => "remote");
10573 // Don't support formatting ranges via remote
10574 match target {
10575 LspFormatTarget::Buffers => {}
10576 LspFormatTarget::Ranges(_) => {
10577 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10578 return Task::ready(Ok(ProjectTransaction::default()));
10579 }
10580 }
10581
10582 let buffer_store = self.buffer_store();
10583 cx.spawn(async move |lsp_store, cx| {
10584 zlog::trace!(logger => "Sending remote format request");
10585 let request_timer = zlog::time!(logger => "remote format request");
10586 let result = client
10587 .request(proto::FormatBuffers {
10588 project_id,
10589 trigger: trigger as i32,
10590 buffer_ids: buffers
10591 .iter()
10592 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10593 .collect::<Result<_>>()?,
10594 })
10595 .await
10596 .and_then(|result| result.transaction.context("missing transaction"));
10597 request_timer.end();
10598
10599 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10600
10601 lsp_store.update(cx, |lsp_store, _| {
10602 lsp_store.update_last_formatting_failure(&result);
10603 })?;
10604
10605 let transaction_response = result?;
10606 let _timer = zlog::time!(logger => "deserializing project transaction");
10607 buffer_store
10608 .update(cx, |buffer_store, cx| {
10609 buffer_store.deserialize_project_transaction(
10610 transaction_response,
10611 push_to_history,
10612 cx,
10613 )
10614 })?
10615 .await
10616 })
10617 } else {
10618 zlog::trace!(logger => "Not formatting");
10619 Task::ready(Ok(ProjectTransaction::default()))
10620 }
10621 }
10622
10623 async fn handle_format_buffers(
10624 this: Entity<Self>,
10625 envelope: TypedEnvelope<proto::FormatBuffers>,
10626 mut cx: AsyncApp,
10627 ) -> Result<proto::FormatBuffersResponse> {
10628 let sender_id = envelope.original_sender_id().unwrap_or_default();
10629 let format = this.update(&mut cx, |this, cx| {
10630 let mut buffers = HashSet::default();
10631 for buffer_id in &envelope.payload.buffer_ids {
10632 let buffer_id = BufferId::new(*buffer_id)?;
10633 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10634 }
10635 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10636 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10637 })??;
10638
10639 let project_transaction = format.await?;
10640 let project_transaction = this.update(&mut cx, |this, cx| {
10641 this.buffer_store.update(cx, |buffer_store, cx| {
10642 buffer_store.serialize_project_transaction_for_peer(
10643 project_transaction,
10644 sender_id,
10645 cx,
10646 )
10647 })
10648 })?;
10649 Ok(proto::FormatBuffersResponse {
10650 transaction: Some(project_transaction),
10651 })
10652 }
10653
10654 async fn handle_apply_code_action_kind(
10655 this: Entity<Self>,
10656 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10657 mut cx: AsyncApp,
10658 ) -> Result<proto::ApplyCodeActionKindResponse> {
10659 let sender_id = envelope.original_sender_id().unwrap_or_default();
10660 let format = this.update(&mut cx, |this, cx| {
10661 let mut buffers = HashSet::default();
10662 for buffer_id in &envelope.payload.buffer_ids {
10663 let buffer_id = BufferId::new(*buffer_id)?;
10664 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10665 }
10666 let kind = match envelope.payload.kind.as_str() {
10667 "" => CodeActionKind::EMPTY,
10668 "quickfix" => CodeActionKind::QUICKFIX,
10669 "refactor" => CodeActionKind::REFACTOR,
10670 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10671 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10672 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10673 "source" => CodeActionKind::SOURCE,
10674 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10675 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10676 _ => anyhow::bail!(
10677 "Invalid code action kind {}",
10678 envelope.payload.kind.as_str()
10679 ),
10680 };
10681 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10682 })??;
10683
10684 let project_transaction = format.await?;
10685 let project_transaction = this.update(&mut cx, |this, cx| {
10686 this.buffer_store.update(cx, |buffer_store, cx| {
10687 buffer_store.serialize_project_transaction_for_peer(
10688 project_transaction,
10689 sender_id,
10690 cx,
10691 )
10692 })
10693 })?;
10694 Ok(proto::ApplyCodeActionKindResponse {
10695 transaction: Some(project_transaction),
10696 })
10697 }
10698
10699 async fn shutdown_language_server(
10700 server_state: Option<LanguageServerState>,
10701 name: LanguageServerName,
10702 cx: &mut AsyncApp,
10703 ) {
10704 let server = match server_state {
10705 Some(LanguageServerState::Starting { startup, .. }) => {
10706 let mut timer = cx
10707 .background_executor()
10708 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10709 .fuse();
10710
10711 select! {
10712 server = startup.fuse() => server,
10713 () = timer => {
10714 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10715 None
10716 },
10717 }
10718 }
10719
10720 Some(LanguageServerState::Running { server, .. }) => Some(server),
10721
10722 None => None,
10723 };
10724
10725 if let Some(server) = server
10726 && let Some(shutdown) = server.shutdown()
10727 {
10728 shutdown.await;
10729 }
10730 }
10731
10732 // Returns a list of all of the worktrees which no longer have a language server and the root path
10733 // for the stopped server
10734 fn stop_local_language_server(
10735 &mut self,
10736 server_id: LanguageServerId,
10737 cx: &mut Context<Self>,
10738 ) -> Task<()> {
10739 let local = match &mut self.mode {
10740 LspStoreMode::Local(local) => local,
10741 _ => {
10742 return Task::ready(());
10743 }
10744 };
10745
10746 // Remove this server ID from all entries in the given worktree.
10747 local
10748 .language_server_ids
10749 .retain(|_, state| state.id != server_id);
10750 self.buffer_store.update(cx, |buffer_store, cx| {
10751 for buffer in buffer_store.buffers() {
10752 buffer.update(cx, |buffer, cx| {
10753 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10754 buffer.set_completion_triggers(server_id, Default::default(), cx);
10755 });
10756 }
10757 });
10758
10759 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10760 summaries.retain(|path, summaries_by_server_id| {
10761 if summaries_by_server_id.remove(&server_id).is_some() {
10762 if let Some((client, project_id)) = self.downstream_client.clone() {
10763 client
10764 .send(proto::UpdateDiagnosticSummary {
10765 project_id,
10766 worktree_id: worktree_id.to_proto(),
10767 summary: Some(proto::DiagnosticSummary {
10768 path: path.as_ref().to_proto(),
10769 language_server_id: server_id.0 as u64,
10770 error_count: 0,
10771 warning_count: 0,
10772 }),
10773 more_summaries: Vec::new(),
10774 })
10775 .log_err();
10776 }
10777 !summaries_by_server_id.is_empty()
10778 } else {
10779 true
10780 }
10781 });
10782 }
10783
10784 let local = self.as_local_mut().unwrap();
10785 for diagnostics in local.diagnostics.values_mut() {
10786 diagnostics.retain(|_, diagnostics_by_server_id| {
10787 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10788 diagnostics_by_server_id.remove(ix);
10789 !diagnostics_by_server_id.is_empty()
10790 } else {
10791 true
10792 }
10793 });
10794 }
10795 local.language_server_watched_paths.remove(&server_id);
10796
10797 let server_state = local.language_servers.remove(&server_id);
10798 self.cleanup_lsp_data(server_id);
10799 let name = self
10800 .language_server_statuses
10801 .remove(&server_id)
10802 .map(|status| status.name)
10803 .or_else(|| {
10804 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10805 Some(adapter.name())
10806 } else {
10807 None
10808 }
10809 });
10810
10811 if let Some(name) = name {
10812 log::info!("stopping language server {name}");
10813 self.languages
10814 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10815 cx.notify();
10816
10817 return cx.spawn(async move |lsp_store, cx| {
10818 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10819 lsp_store
10820 .update(cx, |lsp_store, cx| {
10821 lsp_store
10822 .languages
10823 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10824 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10825 cx.notify();
10826 })
10827 .ok();
10828 });
10829 }
10830
10831 if server_state.is_some() {
10832 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10833 }
10834 Task::ready(())
10835 }
10836
10837 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10838 if let Some((client, project_id)) = self.upstream_client() {
10839 let request = client.request(proto::StopLanguageServers {
10840 project_id,
10841 buffer_ids: Vec::new(),
10842 also_servers: Vec::new(),
10843 all: true,
10844 });
10845 cx.background_spawn(request).detach_and_log_err(cx);
10846 } else {
10847 let Some(local) = self.as_local_mut() else {
10848 return;
10849 };
10850 let language_servers_to_stop = local
10851 .language_server_ids
10852 .values()
10853 .map(|state| state.id)
10854 .collect();
10855 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10856 let tasks = language_servers_to_stop
10857 .into_iter()
10858 .map(|server| self.stop_local_language_server(server, cx))
10859 .collect::<Vec<_>>();
10860 cx.background_spawn(async move {
10861 futures::future::join_all(tasks).await;
10862 })
10863 .detach();
10864 }
10865 }
10866
10867 pub fn restart_language_servers_for_buffers(
10868 &mut self,
10869 buffers: Vec<Entity<Buffer>>,
10870 only_restart_servers: HashSet<LanguageServerSelector>,
10871 cx: &mut Context<Self>,
10872 ) {
10873 if let Some((client, project_id)) = self.upstream_client() {
10874 let request = client.request(proto::RestartLanguageServers {
10875 project_id,
10876 buffer_ids: buffers
10877 .into_iter()
10878 .map(|b| b.read(cx).remote_id().to_proto())
10879 .collect(),
10880 only_servers: only_restart_servers
10881 .into_iter()
10882 .map(|selector| {
10883 let selector = match selector {
10884 LanguageServerSelector::Id(language_server_id) => {
10885 proto::language_server_selector::Selector::ServerId(
10886 language_server_id.to_proto(),
10887 )
10888 }
10889 LanguageServerSelector::Name(language_server_name) => {
10890 proto::language_server_selector::Selector::Name(
10891 language_server_name.to_string(),
10892 )
10893 }
10894 };
10895 proto::LanguageServerSelector {
10896 selector: Some(selector),
10897 }
10898 })
10899 .collect(),
10900 all: false,
10901 });
10902 cx.background_spawn(request).detach_and_log_err(cx);
10903 } else {
10904 let stop_task = if only_restart_servers.is_empty() {
10905 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10906 } else {
10907 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10908 };
10909 cx.spawn(async move |lsp_store, cx| {
10910 stop_task.await;
10911 lsp_store
10912 .update(cx, |lsp_store, cx| {
10913 for buffer in buffers {
10914 lsp_store.register_buffer_with_language_servers(
10915 &buffer,
10916 only_restart_servers.clone(),
10917 true,
10918 cx,
10919 );
10920 }
10921 })
10922 .ok()
10923 })
10924 .detach();
10925 }
10926 }
10927
10928 pub fn stop_language_servers_for_buffers(
10929 &mut self,
10930 buffers: Vec<Entity<Buffer>>,
10931 also_stop_servers: HashSet<LanguageServerSelector>,
10932 cx: &mut Context<Self>,
10933 ) -> Task<Result<()>> {
10934 if let Some((client, project_id)) = self.upstream_client() {
10935 let request = client.request(proto::StopLanguageServers {
10936 project_id,
10937 buffer_ids: buffers
10938 .into_iter()
10939 .map(|b| b.read(cx).remote_id().to_proto())
10940 .collect(),
10941 also_servers: also_stop_servers
10942 .into_iter()
10943 .map(|selector| {
10944 let selector = match selector {
10945 LanguageServerSelector::Id(language_server_id) => {
10946 proto::language_server_selector::Selector::ServerId(
10947 language_server_id.to_proto(),
10948 )
10949 }
10950 LanguageServerSelector::Name(language_server_name) => {
10951 proto::language_server_selector::Selector::Name(
10952 language_server_name.to_string(),
10953 )
10954 }
10955 };
10956 proto::LanguageServerSelector {
10957 selector: Some(selector),
10958 }
10959 })
10960 .collect(),
10961 all: false,
10962 });
10963 cx.background_spawn(async move {
10964 let _ = request.await?;
10965 Ok(())
10966 })
10967 } else {
10968 let task =
10969 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10970 cx.background_spawn(async move {
10971 task.await;
10972 Ok(())
10973 })
10974 }
10975 }
10976
10977 fn stop_local_language_servers_for_buffers(
10978 &mut self,
10979 buffers: &[Entity<Buffer>],
10980 also_stop_servers: HashSet<LanguageServerSelector>,
10981 cx: &mut Context<Self>,
10982 ) -> Task<()> {
10983 let Some(local) = self.as_local_mut() else {
10984 return Task::ready(());
10985 };
10986 let mut language_server_names_to_stop = BTreeSet::default();
10987 let mut language_servers_to_stop = also_stop_servers
10988 .into_iter()
10989 .flat_map(|selector| match selector {
10990 LanguageServerSelector::Id(id) => Some(id),
10991 LanguageServerSelector::Name(name) => {
10992 language_server_names_to_stop.insert(name);
10993 None
10994 }
10995 })
10996 .collect::<BTreeSet<_>>();
10997
10998 let mut covered_worktrees = HashSet::default();
10999 for buffer in buffers {
11000 buffer.update(cx, |buffer, cx| {
11001 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11002 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11003 && covered_worktrees.insert(worktree_id)
11004 {
11005 language_server_names_to_stop.retain(|name| {
11006 let old_ids_count = language_servers_to_stop.len();
11007 let all_language_servers_with_this_name = local
11008 .language_server_ids
11009 .iter()
11010 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11011 language_servers_to_stop.extend(all_language_servers_with_this_name);
11012 old_ids_count == language_servers_to_stop.len()
11013 });
11014 }
11015 });
11016 }
11017 for name in language_server_names_to_stop {
11018 language_servers_to_stop.extend(
11019 local
11020 .language_server_ids
11021 .iter()
11022 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11023 );
11024 }
11025
11026 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11027 let tasks = language_servers_to_stop
11028 .into_iter()
11029 .map(|server| self.stop_local_language_server(server, cx))
11030 .collect::<Vec<_>>();
11031
11032 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11033 }
11034
11035 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11036 let (worktree, relative_path) =
11037 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11038
11039 let project_path = ProjectPath {
11040 worktree_id: worktree.read(cx).id(),
11041 path: relative_path,
11042 };
11043
11044 Some(
11045 self.buffer_store()
11046 .read(cx)
11047 .get_by_path(&project_path)?
11048 .read(cx),
11049 )
11050 }
11051
11052 #[cfg(any(test, feature = "test-support"))]
11053 pub fn update_diagnostics(
11054 &mut self,
11055 server_id: LanguageServerId,
11056 diagnostics: lsp::PublishDiagnosticsParams,
11057 result_id: Option<SharedString>,
11058 source_kind: DiagnosticSourceKind,
11059 disk_based_sources: &[String],
11060 cx: &mut Context<Self>,
11061 ) -> Result<()> {
11062 self.merge_lsp_diagnostics(
11063 source_kind,
11064 vec![DocumentDiagnosticsUpdate {
11065 diagnostics,
11066 result_id,
11067 server_id,
11068 disk_based_sources: Cow::Borrowed(disk_based_sources),
11069 registration_id: None,
11070 }],
11071 |_, _, _| false,
11072 cx,
11073 )
11074 }
11075
11076 pub fn merge_lsp_diagnostics(
11077 &mut self,
11078 source_kind: DiagnosticSourceKind,
11079 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11080 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11081 cx: &mut Context<Self>,
11082 ) -> Result<()> {
11083 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11084 let updates = lsp_diagnostics
11085 .into_iter()
11086 .filter_map(|update| {
11087 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11088 Some(DocumentDiagnosticsUpdate {
11089 diagnostics: self.lsp_to_document_diagnostics(
11090 abs_path,
11091 source_kind,
11092 update.server_id,
11093 update.diagnostics,
11094 &update.disk_based_sources,
11095 update.registration_id.clone(),
11096 ),
11097 result_id: update.result_id,
11098 server_id: update.server_id,
11099 disk_based_sources: update.disk_based_sources,
11100 registration_id: update.registration_id,
11101 })
11102 })
11103 .collect();
11104 self.merge_diagnostic_entries(updates, merge, cx)?;
11105 Ok(())
11106 }
11107
11108 fn lsp_to_document_diagnostics(
11109 &mut self,
11110 document_abs_path: PathBuf,
11111 source_kind: DiagnosticSourceKind,
11112 server_id: LanguageServerId,
11113 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11114 disk_based_sources: &[String],
11115 registration_id: Option<SharedString>,
11116 ) -> DocumentDiagnostics {
11117 let mut diagnostics = Vec::default();
11118 let mut primary_diagnostic_group_ids = HashMap::default();
11119 let mut sources_by_group_id = HashMap::default();
11120 let mut supporting_diagnostics = HashMap::default();
11121
11122 let adapter = self.language_server_adapter_for_id(server_id);
11123
11124 // Ensure that primary diagnostics are always the most severe
11125 lsp_diagnostics
11126 .diagnostics
11127 .sort_by_key(|item| item.severity);
11128
11129 for diagnostic in &lsp_diagnostics.diagnostics {
11130 let source = diagnostic.source.as_ref();
11131 let range = range_from_lsp(diagnostic.range);
11132 let is_supporting = diagnostic
11133 .related_information
11134 .as_ref()
11135 .is_some_and(|infos| {
11136 infos.iter().any(|info| {
11137 primary_diagnostic_group_ids.contains_key(&(
11138 source,
11139 diagnostic.code.clone(),
11140 range_from_lsp(info.location.range),
11141 ))
11142 })
11143 });
11144
11145 let is_unnecessary = diagnostic
11146 .tags
11147 .as_ref()
11148 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11149
11150 let underline = self
11151 .language_server_adapter_for_id(server_id)
11152 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11153
11154 if is_supporting {
11155 supporting_diagnostics.insert(
11156 (source, diagnostic.code.clone(), range),
11157 (diagnostic.severity, is_unnecessary),
11158 );
11159 } else {
11160 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11161 let is_disk_based =
11162 source.is_some_and(|source| disk_based_sources.contains(source));
11163
11164 sources_by_group_id.insert(group_id, source);
11165 primary_diagnostic_group_ids
11166 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11167
11168 diagnostics.push(DiagnosticEntry {
11169 range,
11170 diagnostic: Diagnostic {
11171 source: diagnostic.source.clone(),
11172 source_kind,
11173 code: diagnostic.code.clone(),
11174 code_description: diagnostic
11175 .code_description
11176 .as_ref()
11177 .and_then(|d| d.href.clone()),
11178 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11179 markdown: adapter.as_ref().and_then(|adapter| {
11180 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11181 }),
11182 message: diagnostic.message.trim().to_string(),
11183 group_id,
11184 is_primary: true,
11185 is_disk_based,
11186 is_unnecessary,
11187 underline,
11188 data: diagnostic.data.clone(),
11189 registration_id: registration_id.clone(),
11190 },
11191 });
11192 if let Some(infos) = &diagnostic.related_information {
11193 for info in infos {
11194 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11195 let range = range_from_lsp(info.location.range);
11196 diagnostics.push(DiagnosticEntry {
11197 range,
11198 diagnostic: Diagnostic {
11199 source: diagnostic.source.clone(),
11200 source_kind,
11201 code: diagnostic.code.clone(),
11202 code_description: diagnostic
11203 .code_description
11204 .as_ref()
11205 .and_then(|d| d.href.clone()),
11206 severity: DiagnosticSeverity::INFORMATION,
11207 markdown: adapter.as_ref().and_then(|adapter| {
11208 adapter.diagnostic_message_to_markdown(&info.message)
11209 }),
11210 message: info.message.trim().to_string(),
11211 group_id,
11212 is_primary: false,
11213 is_disk_based,
11214 is_unnecessary: false,
11215 underline,
11216 data: diagnostic.data.clone(),
11217 registration_id: registration_id.clone(),
11218 },
11219 });
11220 }
11221 }
11222 }
11223 }
11224 }
11225
11226 for entry in &mut diagnostics {
11227 let diagnostic = &mut entry.diagnostic;
11228 if !diagnostic.is_primary {
11229 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11230 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11231 source,
11232 diagnostic.code.clone(),
11233 entry.range.clone(),
11234 )) {
11235 if let Some(severity) = severity {
11236 diagnostic.severity = severity;
11237 }
11238 diagnostic.is_unnecessary = is_unnecessary;
11239 }
11240 }
11241 }
11242
11243 DocumentDiagnostics {
11244 diagnostics,
11245 document_abs_path,
11246 version: lsp_diagnostics.version,
11247 }
11248 }
11249
11250 fn insert_newly_running_language_server(
11251 &mut self,
11252 adapter: Arc<CachedLspAdapter>,
11253 language_server: Arc<LanguageServer>,
11254 server_id: LanguageServerId,
11255 key: LanguageServerSeed,
11256 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11257 cx: &mut Context<Self>,
11258 ) {
11259 let Some(local) = self.as_local_mut() else {
11260 return;
11261 };
11262 // If the language server for this key doesn't match the server id, don't store the
11263 // server. Which will cause it to be dropped, killing the process
11264 if local
11265 .language_server_ids
11266 .get(&key)
11267 .map(|state| state.id != server_id)
11268 .unwrap_or(false)
11269 {
11270 return;
11271 }
11272
11273 // Update language_servers collection with Running variant of LanguageServerState
11274 // indicating that the server is up and running and ready
11275 let workspace_folders = workspace_folders.lock().clone();
11276 language_server.set_workspace_folders(workspace_folders);
11277
11278 let workspace_diagnostics_refresh_tasks = language_server
11279 .capabilities()
11280 .diagnostic_provider
11281 .and_then(|provider| {
11282 local
11283 .language_server_dynamic_registrations
11284 .entry(server_id)
11285 .or_default()
11286 .diagnostics
11287 .entry(None)
11288 .or_insert(provider.clone());
11289 let workspace_refresher =
11290 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11291
11292 Some((None, workspace_refresher))
11293 })
11294 .into_iter()
11295 .collect();
11296 local.language_servers.insert(
11297 server_id,
11298 LanguageServerState::Running {
11299 workspace_diagnostics_refresh_tasks,
11300 adapter: adapter.clone(),
11301 server: language_server.clone(),
11302 simulate_disk_based_diagnostics_completion: None,
11303 },
11304 );
11305 local
11306 .languages
11307 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11308 if let Some(file_ops_caps) = language_server
11309 .capabilities()
11310 .workspace
11311 .as_ref()
11312 .and_then(|ws| ws.file_operations.as_ref())
11313 {
11314 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11315 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11316 if did_rename_caps.or(will_rename_caps).is_some() {
11317 let watcher = RenamePathsWatchedForServer::default()
11318 .with_did_rename_patterns(did_rename_caps)
11319 .with_will_rename_patterns(will_rename_caps);
11320 local
11321 .language_server_paths_watched_for_rename
11322 .insert(server_id, watcher);
11323 }
11324 }
11325
11326 self.language_server_statuses.insert(
11327 server_id,
11328 LanguageServerStatus {
11329 name: language_server.name(),
11330 pending_work: Default::default(),
11331 has_pending_diagnostic_updates: false,
11332 progress_tokens: Default::default(),
11333 worktree: Some(key.worktree_id),
11334 binary: Some(language_server.binary().clone()),
11335 configuration: Some(language_server.configuration().clone()),
11336 workspace_folders: language_server.workspace_folders(),
11337 },
11338 );
11339
11340 cx.emit(LspStoreEvent::LanguageServerAdded(
11341 server_id,
11342 language_server.name(),
11343 Some(key.worktree_id),
11344 ));
11345
11346 let server_capabilities = language_server.capabilities();
11347 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11348 downstream_client
11349 .send(proto::StartLanguageServer {
11350 project_id: *project_id,
11351 server: Some(proto::LanguageServer {
11352 id: server_id.to_proto(),
11353 name: language_server.name().to_string(),
11354 worktree_id: Some(key.worktree_id.to_proto()),
11355 }),
11356 capabilities: serde_json::to_string(&server_capabilities)
11357 .expect("serializing server LSP capabilities"),
11358 })
11359 .log_err();
11360 }
11361 self.lsp_server_capabilities
11362 .insert(server_id, server_capabilities);
11363
11364 // Tell the language server about every open buffer in the worktree that matches the language.
11365 // Also check for buffers in worktrees that reused this server
11366 let mut worktrees_using_server = vec![key.worktree_id];
11367 if let Some(local) = self.as_local() {
11368 // Find all worktrees that have this server in their language server tree
11369 for (worktree_id, servers) in &local.lsp_tree.instances {
11370 if *worktree_id != key.worktree_id {
11371 for server_map in servers.roots.values() {
11372 if server_map
11373 .values()
11374 .any(|(node, _)| node.id() == Some(server_id))
11375 {
11376 worktrees_using_server.push(*worktree_id);
11377 }
11378 }
11379 }
11380 }
11381 }
11382
11383 let mut buffer_paths_registered = Vec::new();
11384 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11385 let mut lsp_adapters = HashMap::default();
11386 for buffer_handle in buffer_store.buffers() {
11387 let buffer = buffer_handle.read(cx);
11388 let file = match File::from_dyn(buffer.file()) {
11389 Some(file) => file,
11390 None => continue,
11391 };
11392 let language = match buffer.language() {
11393 Some(language) => language,
11394 None => continue,
11395 };
11396
11397 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11398 || !lsp_adapters
11399 .entry(language.name())
11400 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11401 .iter()
11402 .any(|a| a.name == key.name)
11403 {
11404 continue;
11405 }
11406 // didOpen
11407 let file = match file.as_local() {
11408 Some(file) => file,
11409 None => continue,
11410 };
11411
11412 let local = self.as_local_mut().unwrap();
11413
11414 let buffer_id = buffer.remote_id();
11415 if local.registered_buffers.contains_key(&buffer_id) {
11416 let versions = local
11417 .buffer_snapshots
11418 .entry(buffer_id)
11419 .or_default()
11420 .entry(server_id)
11421 .and_modify(|_| {
11422 assert!(
11423 false,
11424 "There should not be an existing snapshot for a newly inserted buffer"
11425 )
11426 })
11427 .or_insert_with(|| {
11428 vec![LspBufferSnapshot {
11429 version: 0,
11430 snapshot: buffer.text_snapshot(),
11431 }]
11432 });
11433
11434 let snapshot = versions.last().unwrap();
11435 let version = snapshot.version;
11436 let initial_snapshot = &snapshot.snapshot;
11437 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11438 language_server.register_buffer(
11439 uri,
11440 adapter.language_id(&language.name()),
11441 version,
11442 initial_snapshot.text(),
11443 );
11444 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11445 local
11446 .buffers_opened_in_servers
11447 .entry(buffer_id)
11448 .or_default()
11449 .insert(server_id);
11450 }
11451 buffer_handle.update(cx, |buffer, cx| {
11452 buffer.set_completion_triggers(
11453 server_id,
11454 language_server
11455 .capabilities()
11456 .completion_provider
11457 .as_ref()
11458 .and_then(|provider| {
11459 provider
11460 .trigger_characters
11461 .as_ref()
11462 .map(|characters| characters.iter().cloned().collect())
11463 })
11464 .unwrap_or_default(),
11465 cx,
11466 )
11467 });
11468 }
11469 });
11470
11471 for (buffer_id, abs_path) in buffer_paths_registered {
11472 cx.emit(LspStoreEvent::LanguageServerUpdate {
11473 language_server_id: server_id,
11474 name: Some(adapter.name()),
11475 message: proto::update_language_server::Variant::RegisteredForBuffer(
11476 proto::RegisteredForBuffer {
11477 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11478 buffer_id: buffer_id.to_proto(),
11479 },
11480 ),
11481 });
11482 }
11483
11484 cx.notify();
11485 }
11486
11487 pub fn language_servers_running_disk_based_diagnostics(
11488 &self,
11489 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11490 self.language_server_statuses
11491 .iter()
11492 .filter_map(|(id, status)| {
11493 if status.has_pending_diagnostic_updates {
11494 Some(*id)
11495 } else {
11496 None
11497 }
11498 })
11499 }
11500
11501 pub(crate) fn cancel_language_server_work_for_buffers(
11502 &mut self,
11503 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11504 cx: &mut Context<Self>,
11505 ) {
11506 if let Some((client, project_id)) = self.upstream_client() {
11507 let request = client.request(proto::CancelLanguageServerWork {
11508 project_id,
11509 work: Some(proto::cancel_language_server_work::Work::Buffers(
11510 proto::cancel_language_server_work::Buffers {
11511 buffer_ids: buffers
11512 .into_iter()
11513 .map(|b| b.read(cx).remote_id().to_proto())
11514 .collect(),
11515 },
11516 )),
11517 });
11518 cx.background_spawn(request).detach_and_log_err(cx);
11519 } else if let Some(local) = self.as_local() {
11520 let servers = buffers
11521 .into_iter()
11522 .flat_map(|buffer| {
11523 buffer.update(cx, |buffer, cx| {
11524 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11525 })
11526 })
11527 .collect::<HashSet<_>>();
11528 for server_id in servers {
11529 self.cancel_language_server_work(server_id, None, cx);
11530 }
11531 }
11532 }
11533
11534 pub(crate) fn cancel_language_server_work(
11535 &mut self,
11536 server_id: LanguageServerId,
11537 token_to_cancel: Option<ProgressToken>,
11538 cx: &mut Context<Self>,
11539 ) {
11540 if let Some(local) = self.as_local() {
11541 let status = self.language_server_statuses.get(&server_id);
11542 let server = local.language_servers.get(&server_id);
11543 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11544 {
11545 for (token, progress) in &status.pending_work {
11546 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11547 && token != token_to_cancel
11548 {
11549 continue;
11550 }
11551 if progress.is_cancellable {
11552 server
11553 .notify::<lsp::notification::WorkDoneProgressCancel>(
11554 WorkDoneProgressCancelParams {
11555 token: token.to_lsp(),
11556 },
11557 )
11558 .ok();
11559 }
11560 }
11561 }
11562 } else if let Some((client, project_id)) = self.upstream_client() {
11563 let request = client.request(proto::CancelLanguageServerWork {
11564 project_id,
11565 work: Some(
11566 proto::cancel_language_server_work::Work::LanguageServerWork(
11567 proto::cancel_language_server_work::LanguageServerWork {
11568 language_server_id: server_id.to_proto(),
11569 token: token_to_cancel.map(|token| token.to_proto()),
11570 },
11571 ),
11572 ),
11573 });
11574 cx.background_spawn(request).detach_and_log_err(cx);
11575 }
11576 }
11577
11578 fn register_supplementary_language_server(
11579 &mut self,
11580 id: LanguageServerId,
11581 name: LanguageServerName,
11582 server: Arc<LanguageServer>,
11583 cx: &mut Context<Self>,
11584 ) {
11585 if let Some(local) = self.as_local_mut() {
11586 local
11587 .supplementary_language_servers
11588 .insert(id, (name.clone(), server));
11589 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11590 }
11591 }
11592
11593 fn unregister_supplementary_language_server(
11594 &mut self,
11595 id: LanguageServerId,
11596 cx: &mut Context<Self>,
11597 ) {
11598 if let Some(local) = self.as_local_mut() {
11599 local.supplementary_language_servers.remove(&id);
11600 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11601 }
11602 }
11603
11604 pub(crate) fn supplementary_language_servers(
11605 &self,
11606 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11607 self.as_local().into_iter().flat_map(|local| {
11608 local
11609 .supplementary_language_servers
11610 .iter()
11611 .map(|(id, (name, _))| (*id, name.clone()))
11612 })
11613 }
11614
11615 pub fn language_server_adapter_for_id(
11616 &self,
11617 id: LanguageServerId,
11618 ) -> Option<Arc<CachedLspAdapter>> {
11619 self.as_local()
11620 .and_then(|local| local.language_servers.get(&id))
11621 .and_then(|language_server_state| match language_server_state {
11622 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11623 _ => None,
11624 })
11625 }
11626
11627 pub(super) fn update_local_worktree_language_servers(
11628 &mut self,
11629 worktree_handle: &Entity<Worktree>,
11630 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11631 cx: &mut Context<Self>,
11632 ) {
11633 if changes.is_empty() {
11634 return;
11635 }
11636
11637 let Some(local) = self.as_local() else { return };
11638
11639 local.prettier_store.update(cx, |prettier_store, cx| {
11640 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11641 });
11642
11643 let worktree_id = worktree_handle.read(cx).id();
11644 let mut language_server_ids = local
11645 .language_server_ids
11646 .iter()
11647 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11648 .collect::<Vec<_>>();
11649 language_server_ids.sort();
11650 language_server_ids.dedup();
11651
11652 // let abs_path = worktree_handle.read(cx).abs_path();
11653 for server_id in &language_server_ids {
11654 if let Some(LanguageServerState::Running { server, .. }) =
11655 local.language_servers.get(server_id)
11656 && let Some(watched_paths) = local
11657 .language_server_watched_paths
11658 .get(server_id)
11659 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11660 {
11661 let params = lsp::DidChangeWatchedFilesParams {
11662 changes: changes
11663 .iter()
11664 .filter_map(|(path, _, change)| {
11665 if !watched_paths.is_match(path.as_std_path()) {
11666 return None;
11667 }
11668 let typ = match change {
11669 PathChange::Loaded => return None,
11670 PathChange::Added => lsp::FileChangeType::CREATED,
11671 PathChange::Removed => lsp::FileChangeType::DELETED,
11672 PathChange::Updated => lsp::FileChangeType::CHANGED,
11673 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11674 };
11675 let uri = lsp::Uri::from_file_path(
11676 worktree_handle.read(cx).absolutize(&path),
11677 )
11678 .ok()?;
11679 Some(lsp::FileEvent { uri, typ })
11680 })
11681 .collect(),
11682 };
11683 if !params.changes.is_empty() {
11684 server
11685 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11686 .ok();
11687 }
11688 }
11689 }
11690 for (path, _, _) in changes {
11691 if let Some(file_name) = path.file_name()
11692 && local.watched_manifest_filenames.contains(file_name)
11693 {
11694 self.request_workspace_config_refresh();
11695 break;
11696 }
11697 }
11698 }
11699
11700 pub fn wait_for_remote_buffer(
11701 &mut self,
11702 id: BufferId,
11703 cx: &mut Context<Self>,
11704 ) -> Task<Result<Entity<Buffer>>> {
11705 self.buffer_store.update(cx, |buffer_store, cx| {
11706 buffer_store.wait_for_remote_buffer(id, cx)
11707 })
11708 }
11709
11710 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11711 let mut result = proto::Symbol {
11712 language_server_name: symbol.language_server_name.0.to_string(),
11713 source_worktree_id: symbol.source_worktree_id.to_proto(),
11714 language_server_id: symbol.source_language_server_id.to_proto(),
11715 name: symbol.name.clone(),
11716 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11717 start: Some(proto::PointUtf16 {
11718 row: symbol.range.start.0.row,
11719 column: symbol.range.start.0.column,
11720 }),
11721 end: Some(proto::PointUtf16 {
11722 row: symbol.range.end.0.row,
11723 column: symbol.range.end.0.column,
11724 }),
11725 worktree_id: Default::default(),
11726 path: Default::default(),
11727 signature: Default::default(),
11728 };
11729 match &symbol.path {
11730 SymbolLocation::InProject(path) => {
11731 result.worktree_id = path.worktree_id.to_proto();
11732 result.path = path.path.to_proto();
11733 }
11734 SymbolLocation::OutsideProject {
11735 abs_path,
11736 signature,
11737 } => {
11738 result.path = abs_path.to_string_lossy().into_owned();
11739 result.signature = signature.to_vec();
11740 }
11741 }
11742 result
11743 }
11744
11745 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11746 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11747 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11748 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11749
11750 let path = if serialized_symbol.signature.is_empty() {
11751 SymbolLocation::InProject(ProjectPath {
11752 worktree_id,
11753 path: RelPath::from_proto(&serialized_symbol.path)
11754 .context("invalid symbol path")?,
11755 })
11756 } else {
11757 SymbolLocation::OutsideProject {
11758 abs_path: Path::new(&serialized_symbol.path).into(),
11759 signature: serialized_symbol
11760 .signature
11761 .try_into()
11762 .map_err(|_| anyhow!("invalid signature"))?,
11763 }
11764 };
11765
11766 let start = serialized_symbol.start.context("invalid start")?;
11767 let end = serialized_symbol.end.context("invalid end")?;
11768 Ok(CoreSymbol {
11769 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11770 source_worktree_id,
11771 source_language_server_id: LanguageServerId::from_proto(
11772 serialized_symbol.language_server_id,
11773 ),
11774 path,
11775 name: serialized_symbol.name,
11776 range: Unclipped(PointUtf16::new(start.row, start.column))
11777 ..Unclipped(PointUtf16::new(end.row, end.column)),
11778 kind,
11779 })
11780 }
11781
11782 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11783 let mut serialized_completion = proto::Completion {
11784 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11785 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11786 new_text: completion.new_text.clone(),
11787 ..proto::Completion::default()
11788 };
11789 match &completion.source {
11790 CompletionSource::Lsp {
11791 insert_range,
11792 server_id,
11793 lsp_completion,
11794 lsp_defaults,
11795 resolved,
11796 } => {
11797 let (old_insert_start, old_insert_end) = insert_range
11798 .as_ref()
11799 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11800 .unzip();
11801
11802 serialized_completion.old_insert_start = old_insert_start;
11803 serialized_completion.old_insert_end = old_insert_end;
11804 serialized_completion.source = proto::completion::Source::Lsp as i32;
11805 serialized_completion.server_id = server_id.0 as u64;
11806 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11807 serialized_completion.lsp_defaults = lsp_defaults
11808 .as_deref()
11809 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11810 serialized_completion.resolved = *resolved;
11811 }
11812 CompletionSource::BufferWord {
11813 word_range,
11814 resolved,
11815 } => {
11816 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11817 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11818 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11819 serialized_completion.resolved = *resolved;
11820 }
11821 CompletionSource::Custom => {
11822 serialized_completion.source = proto::completion::Source::Custom as i32;
11823 serialized_completion.resolved = true;
11824 }
11825 CompletionSource::Dap { sort_text } => {
11826 serialized_completion.source = proto::completion::Source::Dap as i32;
11827 serialized_completion.sort_text = Some(sort_text.clone());
11828 }
11829 }
11830
11831 serialized_completion
11832 }
11833
11834 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11835 let old_replace_start = completion
11836 .old_replace_start
11837 .and_then(deserialize_anchor)
11838 .context("invalid old start")?;
11839 let old_replace_end = completion
11840 .old_replace_end
11841 .and_then(deserialize_anchor)
11842 .context("invalid old end")?;
11843 let insert_range = {
11844 match completion.old_insert_start.zip(completion.old_insert_end) {
11845 Some((start, end)) => {
11846 let start = deserialize_anchor(start).context("invalid insert old start")?;
11847 let end = deserialize_anchor(end).context("invalid insert old end")?;
11848 Some(start..end)
11849 }
11850 None => None,
11851 }
11852 };
11853 Ok(CoreCompletion {
11854 replace_range: old_replace_start..old_replace_end,
11855 new_text: completion.new_text,
11856 source: match proto::completion::Source::from_i32(completion.source) {
11857 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11858 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11859 insert_range,
11860 server_id: LanguageServerId::from_proto(completion.server_id),
11861 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11862 lsp_defaults: completion
11863 .lsp_defaults
11864 .as_deref()
11865 .map(serde_json::from_slice)
11866 .transpose()?,
11867 resolved: completion.resolved,
11868 },
11869 Some(proto::completion::Source::BufferWord) => {
11870 let word_range = completion
11871 .buffer_word_start
11872 .and_then(deserialize_anchor)
11873 .context("invalid buffer word start")?
11874 ..completion
11875 .buffer_word_end
11876 .and_then(deserialize_anchor)
11877 .context("invalid buffer word end")?;
11878 CompletionSource::BufferWord {
11879 word_range,
11880 resolved: completion.resolved,
11881 }
11882 }
11883 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11884 sort_text: completion
11885 .sort_text
11886 .context("expected sort text to exist")?,
11887 },
11888 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11889 },
11890 })
11891 }
11892
11893 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11894 let (kind, lsp_action) = match &action.lsp_action {
11895 LspAction::Action(code_action) => (
11896 proto::code_action::Kind::Action as i32,
11897 serde_json::to_vec(code_action).unwrap(),
11898 ),
11899 LspAction::Command(command) => (
11900 proto::code_action::Kind::Command as i32,
11901 serde_json::to_vec(command).unwrap(),
11902 ),
11903 LspAction::CodeLens(code_lens) => (
11904 proto::code_action::Kind::CodeLens as i32,
11905 serde_json::to_vec(code_lens).unwrap(),
11906 ),
11907 };
11908
11909 proto::CodeAction {
11910 server_id: action.server_id.0 as u64,
11911 start: Some(serialize_anchor(&action.range.start)),
11912 end: Some(serialize_anchor(&action.range.end)),
11913 lsp_action,
11914 kind,
11915 resolved: action.resolved,
11916 }
11917 }
11918
11919 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11920 let start = action
11921 .start
11922 .and_then(deserialize_anchor)
11923 .context("invalid start")?;
11924 let end = action
11925 .end
11926 .and_then(deserialize_anchor)
11927 .context("invalid end")?;
11928 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11929 Some(proto::code_action::Kind::Action) => {
11930 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11931 }
11932 Some(proto::code_action::Kind::Command) => {
11933 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11934 }
11935 Some(proto::code_action::Kind::CodeLens) => {
11936 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11937 }
11938 None => anyhow::bail!("Unknown action kind {}", action.kind),
11939 };
11940 Ok(CodeAction {
11941 server_id: LanguageServerId(action.server_id as usize),
11942 range: start..end,
11943 resolved: action.resolved,
11944 lsp_action,
11945 })
11946 }
11947
11948 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11949 match &formatting_result {
11950 Ok(_) => self.last_formatting_failure = None,
11951 Err(error) => {
11952 let error_string = format!("{error:#}");
11953 log::error!("Formatting failed: {error_string}");
11954 self.last_formatting_failure
11955 .replace(error_string.lines().join(" "));
11956 }
11957 }
11958 }
11959
11960 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11961 self.lsp_server_capabilities.remove(&for_server);
11962 for lsp_data in self.lsp_data.values_mut() {
11963 lsp_data.remove_server_data(for_server);
11964 }
11965 if let Some(local) = self.as_local_mut() {
11966 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11967 local
11968 .workspace_pull_diagnostics_result_ids
11969 .remove(&for_server);
11970 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11971 buffer_servers.remove(&for_server);
11972 }
11973 }
11974 }
11975
11976 pub fn result_id_for_buffer_pull(
11977 &self,
11978 server_id: LanguageServerId,
11979 buffer_id: BufferId,
11980 registration_id: &Option<SharedString>,
11981 cx: &App,
11982 ) -> Option<SharedString> {
11983 let abs_path = self
11984 .buffer_store
11985 .read(cx)
11986 .get(buffer_id)
11987 .and_then(|b| File::from_dyn(b.read(cx).file()))
11988 .map(|f| f.abs_path(cx))?;
11989 self.as_local()?
11990 .buffer_pull_diagnostics_result_ids
11991 .get(&server_id)?
11992 .get(registration_id)?
11993 .get(&abs_path)?
11994 .clone()
11995 }
11996
11997 /// Gets all result_ids for a workspace diagnostics pull request.
11998 /// 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.
11999 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12000 pub fn result_ids_for_workspace_refresh(
12001 &self,
12002 server_id: LanguageServerId,
12003 registration_id: &Option<SharedString>,
12004 ) -> HashMap<PathBuf, SharedString> {
12005 let Some(local) = self.as_local() else {
12006 return HashMap::default();
12007 };
12008 local
12009 .workspace_pull_diagnostics_result_ids
12010 .get(&server_id)
12011 .into_iter()
12012 .filter_map(|diagnostics| diagnostics.get(registration_id))
12013 .flatten()
12014 .filter_map(|(abs_path, result_id)| {
12015 let result_id = local
12016 .buffer_pull_diagnostics_result_ids
12017 .get(&server_id)
12018 .and_then(|buffer_ids_result_ids| {
12019 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12020 })
12021 .cloned()
12022 .flatten()
12023 .or_else(|| result_id.clone())?;
12024 Some((abs_path.clone(), result_id))
12025 })
12026 .collect()
12027 }
12028
12029 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12030 if let Some(LanguageServerState::Running {
12031 workspace_diagnostics_refresh_tasks,
12032 ..
12033 }) = self
12034 .as_local_mut()
12035 .and_then(|local| local.language_servers.get_mut(&server_id))
12036 {
12037 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12038 diagnostics.refresh_tx.try_send(()).ok();
12039 }
12040 }
12041 }
12042
12043 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12044 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12045 return;
12046 };
12047 let Some(local) = self.as_local_mut() else {
12048 return;
12049 };
12050
12051 for server_id in buffer.update(cx, |buffer, cx| {
12052 local.language_server_ids_for_buffer(buffer, cx)
12053 }) {
12054 if let Some(LanguageServerState::Running {
12055 workspace_diagnostics_refresh_tasks,
12056 ..
12057 }) = local.language_servers.get_mut(&server_id)
12058 {
12059 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12060 diagnostics.refresh_tx.try_send(()).ok();
12061 }
12062 }
12063 }
12064 }
12065
12066 fn apply_workspace_diagnostic_report(
12067 &mut self,
12068 server_id: LanguageServerId,
12069 report: lsp::WorkspaceDiagnosticReportResult,
12070 registration_id: Option<SharedString>,
12071 cx: &mut Context<Self>,
12072 ) {
12073 let workspace_diagnostics =
12074 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12075 report,
12076 server_id,
12077 registration_id,
12078 );
12079 let mut unchanged_buffers = HashMap::default();
12080 let workspace_diagnostics_updates = workspace_diagnostics
12081 .into_iter()
12082 .filter_map(
12083 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12084 LspPullDiagnostics::Response {
12085 server_id,
12086 uri,
12087 diagnostics,
12088 registration_id,
12089 } => Some((
12090 server_id,
12091 uri,
12092 diagnostics,
12093 workspace_diagnostics.version,
12094 registration_id,
12095 )),
12096 LspPullDiagnostics::Default => None,
12097 },
12098 )
12099 .fold(
12100 HashMap::default(),
12101 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12102 let (result_id, diagnostics) = match diagnostics {
12103 PulledDiagnostics::Unchanged { result_id } => {
12104 unchanged_buffers
12105 .entry(new_registration_id.clone())
12106 .or_insert_with(HashSet::default)
12107 .insert(uri.clone());
12108 (Some(result_id), Vec::new())
12109 }
12110 PulledDiagnostics::Changed {
12111 result_id,
12112 diagnostics,
12113 } => (result_id, diagnostics),
12114 };
12115 let disk_based_sources = Cow::Owned(
12116 self.language_server_adapter_for_id(server_id)
12117 .as_ref()
12118 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12119 .unwrap_or(&[])
12120 .to_vec(),
12121 );
12122
12123 let Some(abs_path) = uri.to_file_path().ok() else {
12124 return acc;
12125 };
12126 let Some((worktree, relative_path)) =
12127 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12128 else {
12129 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12130 return acc;
12131 };
12132 let worktree_id = worktree.read(cx).id();
12133 let project_path = ProjectPath {
12134 worktree_id,
12135 path: relative_path,
12136 };
12137 if let Some(local_lsp_store) = self.as_local_mut() {
12138 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12139 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12140 }
12141 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12142 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12143 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12144 acc.entry(server_id)
12145 .or_insert_with(HashMap::default)
12146 .entry(new_registration_id.clone())
12147 .or_insert_with(Vec::new)
12148 .push(DocumentDiagnosticsUpdate {
12149 server_id,
12150 diagnostics: lsp::PublishDiagnosticsParams {
12151 uri,
12152 diagnostics,
12153 version,
12154 },
12155 result_id,
12156 disk_based_sources,
12157 registration_id: new_registration_id,
12158 });
12159 }
12160 acc
12161 },
12162 );
12163
12164 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12165 for (registration_id, diagnostic_updates) in diagnostic_updates {
12166 self.merge_lsp_diagnostics(
12167 DiagnosticSourceKind::Pulled,
12168 diagnostic_updates,
12169 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12170 DiagnosticSourceKind::Pulled => {
12171 old_diagnostic.registration_id != registration_id
12172 || unchanged_buffers
12173 .get(&old_diagnostic.registration_id)
12174 .is_some_and(|unchanged_buffers| {
12175 unchanged_buffers.contains(&document_uri)
12176 })
12177 }
12178 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12179 },
12180 cx,
12181 )
12182 .log_err();
12183 }
12184 }
12185 }
12186
12187 fn register_server_capabilities(
12188 &mut self,
12189 server_id: LanguageServerId,
12190 params: lsp::RegistrationParams,
12191 cx: &mut Context<Self>,
12192 ) -> anyhow::Result<()> {
12193 let server = self
12194 .language_server_for_id(server_id)
12195 .with_context(|| format!("no server {server_id} found"))?;
12196 for reg in params.registrations {
12197 match reg.method.as_str() {
12198 "workspace/didChangeWatchedFiles" => {
12199 if let Some(options) = reg.register_options {
12200 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12201 let caps = serde_json::from_value(options)?;
12202 local_lsp_store
12203 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12204 true
12205 } else {
12206 false
12207 };
12208 if notify {
12209 notify_server_capabilities_updated(&server, cx);
12210 }
12211 }
12212 }
12213 "workspace/didChangeConfiguration" => {
12214 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12215 }
12216 "workspace/didChangeWorkspaceFolders" => {
12217 // In this case register options is an empty object, we can ignore it
12218 let caps = lsp::WorkspaceFoldersServerCapabilities {
12219 supported: Some(true),
12220 change_notifications: Some(OneOf::Right(reg.id)),
12221 };
12222 server.update_capabilities(|capabilities| {
12223 capabilities
12224 .workspace
12225 .get_or_insert_default()
12226 .workspace_folders = Some(caps);
12227 });
12228 notify_server_capabilities_updated(&server, cx);
12229 }
12230 "workspace/symbol" => {
12231 let options = parse_register_capabilities(reg)?;
12232 server.update_capabilities(|capabilities| {
12233 capabilities.workspace_symbol_provider = Some(options);
12234 });
12235 notify_server_capabilities_updated(&server, cx);
12236 }
12237 "workspace/fileOperations" => {
12238 if let Some(options) = reg.register_options {
12239 let caps = serde_json::from_value(options)?;
12240 server.update_capabilities(|capabilities| {
12241 capabilities
12242 .workspace
12243 .get_or_insert_default()
12244 .file_operations = Some(caps);
12245 });
12246 notify_server_capabilities_updated(&server, cx);
12247 }
12248 }
12249 "workspace/executeCommand" => {
12250 if let Some(options) = reg.register_options {
12251 let options = serde_json::from_value(options)?;
12252 server.update_capabilities(|capabilities| {
12253 capabilities.execute_command_provider = Some(options);
12254 });
12255 notify_server_capabilities_updated(&server, cx);
12256 }
12257 }
12258 "textDocument/rangeFormatting" => {
12259 let options = parse_register_capabilities(reg)?;
12260 server.update_capabilities(|capabilities| {
12261 capabilities.document_range_formatting_provider = Some(options);
12262 });
12263 notify_server_capabilities_updated(&server, cx);
12264 }
12265 "textDocument/onTypeFormatting" => {
12266 if let Some(options) = reg
12267 .register_options
12268 .map(serde_json::from_value)
12269 .transpose()?
12270 {
12271 server.update_capabilities(|capabilities| {
12272 capabilities.document_on_type_formatting_provider = Some(options);
12273 });
12274 notify_server_capabilities_updated(&server, cx);
12275 }
12276 }
12277 "textDocument/formatting" => {
12278 let options = parse_register_capabilities(reg)?;
12279 server.update_capabilities(|capabilities| {
12280 capabilities.document_formatting_provider = Some(options);
12281 });
12282 notify_server_capabilities_updated(&server, cx);
12283 }
12284 "textDocument/rename" => {
12285 let options = parse_register_capabilities(reg)?;
12286 server.update_capabilities(|capabilities| {
12287 capabilities.rename_provider = Some(options);
12288 });
12289 notify_server_capabilities_updated(&server, cx);
12290 }
12291 "textDocument/inlayHint" => {
12292 let options = parse_register_capabilities(reg)?;
12293 server.update_capabilities(|capabilities| {
12294 capabilities.inlay_hint_provider = Some(options);
12295 });
12296 notify_server_capabilities_updated(&server, cx);
12297 }
12298 "textDocument/documentSymbol" => {
12299 let options = parse_register_capabilities(reg)?;
12300 server.update_capabilities(|capabilities| {
12301 capabilities.document_symbol_provider = Some(options);
12302 });
12303 notify_server_capabilities_updated(&server, cx);
12304 }
12305 "textDocument/codeAction" => {
12306 let options = parse_register_capabilities(reg)?;
12307 let provider = match options {
12308 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12309 OneOf::Right(caps) => caps,
12310 };
12311 server.update_capabilities(|capabilities| {
12312 capabilities.code_action_provider = Some(provider);
12313 });
12314 notify_server_capabilities_updated(&server, cx);
12315 }
12316 "textDocument/definition" => {
12317 let options = parse_register_capabilities(reg)?;
12318 server.update_capabilities(|capabilities| {
12319 capabilities.definition_provider = Some(options);
12320 });
12321 notify_server_capabilities_updated(&server, cx);
12322 }
12323 "textDocument/completion" => {
12324 if let Some(caps) = reg
12325 .register_options
12326 .map(serde_json::from_value::<CompletionOptions>)
12327 .transpose()?
12328 {
12329 server.update_capabilities(|capabilities| {
12330 capabilities.completion_provider = Some(caps.clone());
12331 });
12332
12333 if let Some(local) = self.as_local() {
12334 let mut buffers_with_language_server = Vec::new();
12335 for handle in self.buffer_store.read(cx).buffers() {
12336 let buffer_id = handle.read(cx).remote_id();
12337 if local
12338 .buffers_opened_in_servers
12339 .get(&buffer_id)
12340 .filter(|s| s.contains(&server_id))
12341 .is_some()
12342 {
12343 buffers_with_language_server.push(handle);
12344 }
12345 }
12346 let triggers = caps
12347 .trigger_characters
12348 .unwrap_or_default()
12349 .into_iter()
12350 .collect::<BTreeSet<_>>();
12351 for handle in buffers_with_language_server {
12352 let triggers = triggers.clone();
12353 let _ = handle.update(cx, move |buffer, cx| {
12354 buffer.set_completion_triggers(server_id, triggers, cx);
12355 });
12356 }
12357 }
12358 notify_server_capabilities_updated(&server, cx);
12359 }
12360 }
12361 "textDocument/hover" => {
12362 let options = parse_register_capabilities(reg)?;
12363 let provider = match options {
12364 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12365 OneOf::Right(caps) => caps,
12366 };
12367 server.update_capabilities(|capabilities| {
12368 capabilities.hover_provider = Some(provider);
12369 });
12370 notify_server_capabilities_updated(&server, cx);
12371 }
12372 "textDocument/signatureHelp" => {
12373 if let Some(caps) = reg
12374 .register_options
12375 .map(serde_json::from_value)
12376 .transpose()?
12377 {
12378 server.update_capabilities(|capabilities| {
12379 capabilities.signature_help_provider = Some(caps);
12380 });
12381 notify_server_capabilities_updated(&server, cx);
12382 }
12383 }
12384 "textDocument/didChange" => {
12385 if let Some(sync_kind) = reg
12386 .register_options
12387 .and_then(|opts| opts.get("syncKind").cloned())
12388 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12389 .transpose()?
12390 {
12391 server.update_capabilities(|capabilities| {
12392 let mut sync_options =
12393 Self::take_text_document_sync_options(capabilities);
12394 sync_options.change = Some(sync_kind);
12395 capabilities.text_document_sync =
12396 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12397 });
12398 notify_server_capabilities_updated(&server, cx);
12399 }
12400 }
12401 "textDocument/didSave" => {
12402 if let Some(include_text) = reg
12403 .register_options
12404 .map(|opts| {
12405 let transpose = opts
12406 .get("includeText")
12407 .cloned()
12408 .map(serde_json::from_value::<Option<bool>>)
12409 .transpose();
12410 match transpose {
12411 Ok(value) => Ok(value.flatten()),
12412 Err(e) => Err(e),
12413 }
12414 })
12415 .transpose()?
12416 {
12417 server.update_capabilities(|capabilities| {
12418 let mut sync_options =
12419 Self::take_text_document_sync_options(capabilities);
12420 sync_options.save =
12421 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12422 include_text,
12423 }));
12424 capabilities.text_document_sync =
12425 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12426 });
12427 notify_server_capabilities_updated(&server, cx);
12428 }
12429 }
12430 "textDocument/codeLens" => {
12431 if let Some(caps) = reg
12432 .register_options
12433 .map(serde_json::from_value)
12434 .transpose()?
12435 {
12436 server.update_capabilities(|capabilities| {
12437 capabilities.code_lens_provider = Some(caps);
12438 });
12439 notify_server_capabilities_updated(&server, cx);
12440 }
12441 }
12442 "textDocument/diagnostic" => {
12443 if let Some(caps) = reg
12444 .register_options
12445 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12446 .transpose()?
12447 {
12448 let local = self
12449 .as_local_mut()
12450 .context("Expected LSP Store to be local")?;
12451 let state = local
12452 .language_servers
12453 .get_mut(&server_id)
12454 .context("Could not obtain Language Servers state")?;
12455 local
12456 .language_server_dynamic_registrations
12457 .entry(server_id)
12458 .or_default()
12459 .diagnostics
12460 .insert(Some(reg.id.clone()), caps.clone());
12461
12462 let supports_workspace_diagnostics =
12463 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12464 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12465 diagnostic_options.workspace_diagnostics
12466 }
12467 DiagnosticServerCapabilities::RegistrationOptions(
12468 diagnostic_registration_options,
12469 ) => {
12470 diagnostic_registration_options
12471 .diagnostic_options
12472 .workspace_diagnostics
12473 }
12474 };
12475
12476 if supports_workspace_diagnostics(&caps) {
12477 if let LanguageServerState::Running {
12478 workspace_diagnostics_refresh_tasks,
12479 ..
12480 } = state
12481 && let Some(task) = lsp_workspace_diagnostics_refresh(
12482 Some(reg.id.clone()),
12483 caps.clone(),
12484 server.clone(),
12485 cx,
12486 )
12487 {
12488 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12489 }
12490 }
12491
12492 server.update_capabilities(|capabilities| {
12493 capabilities.diagnostic_provider = Some(caps);
12494 });
12495
12496 notify_server_capabilities_updated(&server, cx);
12497 }
12498 }
12499 "textDocument/documentColor" => {
12500 let options = parse_register_capabilities(reg)?;
12501 let provider = match options {
12502 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12503 OneOf::Right(caps) => caps,
12504 };
12505 server.update_capabilities(|capabilities| {
12506 capabilities.color_provider = Some(provider);
12507 });
12508 notify_server_capabilities_updated(&server, cx);
12509 }
12510 _ => log::warn!("unhandled capability registration: {reg:?}"),
12511 }
12512 }
12513
12514 Ok(())
12515 }
12516
12517 fn unregister_server_capabilities(
12518 &mut self,
12519 server_id: LanguageServerId,
12520 params: lsp::UnregistrationParams,
12521 cx: &mut Context<Self>,
12522 ) -> anyhow::Result<()> {
12523 let server = self
12524 .language_server_for_id(server_id)
12525 .with_context(|| format!("no server {server_id} found"))?;
12526 for unreg in params.unregisterations.iter() {
12527 match unreg.method.as_str() {
12528 "workspace/didChangeWatchedFiles" => {
12529 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12530 local_lsp_store
12531 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12532 true
12533 } else {
12534 false
12535 };
12536 if notify {
12537 notify_server_capabilities_updated(&server, cx);
12538 }
12539 }
12540 "workspace/didChangeConfiguration" => {
12541 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12542 }
12543 "workspace/didChangeWorkspaceFolders" => {
12544 server.update_capabilities(|capabilities| {
12545 capabilities
12546 .workspace
12547 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12548 workspace_folders: None,
12549 file_operations: None,
12550 })
12551 .workspace_folders = None;
12552 });
12553 notify_server_capabilities_updated(&server, cx);
12554 }
12555 "workspace/symbol" => {
12556 server.update_capabilities(|capabilities| {
12557 capabilities.workspace_symbol_provider = None
12558 });
12559 notify_server_capabilities_updated(&server, cx);
12560 }
12561 "workspace/fileOperations" => {
12562 server.update_capabilities(|capabilities| {
12563 capabilities
12564 .workspace
12565 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12566 workspace_folders: None,
12567 file_operations: None,
12568 })
12569 .file_operations = None;
12570 });
12571 notify_server_capabilities_updated(&server, cx);
12572 }
12573 "workspace/executeCommand" => {
12574 server.update_capabilities(|capabilities| {
12575 capabilities.execute_command_provider = None;
12576 });
12577 notify_server_capabilities_updated(&server, cx);
12578 }
12579 "textDocument/rangeFormatting" => {
12580 server.update_capabilities(|capabilities| {
12581 capabilities.document_range_formatting_provider = None
12582 });
12583 notify_server_capabilities_updated(&server, cx);
12584 }
12585 "textDocument/onTypeFormatting" => {
12586 server.update_capabilities(|capabilities| {
12587 capabilities.document_on_type_formatting_provider = None;
12588 });
12589 notify_server_capabilities_updated(&server, cx);
12590 }
12591 "textDocument/formatting" => {
12592 server.update_capabilities(|capabilities| {
12593 capabilities.document_formatting_provider = None;
12594 });
12595 notify_server_capabilities_updated(&server, cx);
12596 }
12597 "textDocument/rename" => {
12598 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12599 notify_server_capabilities_updated(&server, cx);
12600 }
12601 "textDocument/codeAction" => {
12602 server.update_capabilities(|capabilities| {
12603 capabilities.code_action_provider = None;
12604 });
12605 notify_server_capabilities_updated(&server, cx);
12606 }
12607 "textDocument/definition" => {
12608 server.update_capabilities(|capabilities| {
12609 capabilities.definition_provider = None;
12610 });
12611 notify_server_capabilities_updated(&server, cx);
12612 }
12613 "textDocument/completion" => {
12614 server.update_capabilities(|capabilities| {
12615 capabilities.completion_provider = None;
12616 });
12617 notify_server_capabilities_updated(&server, cx);
12618 }
12619 "textDocument/hover" => {
12620 server.update_capabilities(|capabilities| {
12621 capabilities.hover_provider = None;
12622 });
12623 notify_server_capabilities_updated(&server, cx);
12624 }
12625 "textDocument/signatureHelp" => {
12626 server.update_capabilities(|capabilities| {
12627 capabilities.signature_help_provider = None;
12628 });
12629 notify_server_capabilities_updated(&server, cx);
12630 }
12631 "textDocument/didChange" => {
12632 server.update_capabilities(|capabilities| {
12633 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12634 sync_options.change = None;
12635 capabilities.text_document_sync =
12636 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12637 });
12638 notify_server_capabilities_updated(&server, cx);
12639 }
12640 "textDocument/didSave" => {
12641 server.update_capabilities(|capabilities| {
12642 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12643 sync_options.save = None;
12644 capabilities.text_document_sync =
12645 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12646 });
12647 notify_server_capabilities_updated(&server, cx);
12648 }
12649 "textDocument/codeLens" => {
12650 server.update_capabilities(|capabilities| {
12651 capabilities.code_lens_provider = None;
12652 });
12653 notify_server_capabilities_updated(&server, cx);
12654 }
12655 "textDocument/diagnostic" => {
12656 let local = self
12657 .as_local_mut()
12658 .context("Expected LSP Store to be local")?;
12659
12660 let state = local
12661 .language_servers
12662 .get_mut(&server_id)
12663 .context("Could not obtain Language Servers state")?;
12664 let registrations = local
12665 .language_server_dynamic_registrations
12666 .get_mut(&server_id)
12667 .with_context(|| {
12668 format!("Expected dynamic registration to exist for server {server_id}")
12669 })?;
12670 registrations.diagnostics
12671 .remove(&Some(unreg.id.clone()))
12672 .with_context(|| format!(
12673 "Attempted to unregister non-existent diagnostic registration with ID {}",
12674 unreg.id)
12675 )?;
12676 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12677
12678 if let LanguageServerState::Running {
12679 workspace_diagnostics_refresh_tasks,
12680 ..
12681 } = state
12682 {
12683 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12684 }
12685
12686 if removed_last_diagnostic_provider {
12687 server.update_capabilities(|capabilities| {
12688 debug_assert!(capabilities.diagnostic_provider.is_some());
12689 capabilities.diagnostic_provider = None;
12690 });
12691 }
12692
12693 notify_server_capabilities_updated(&server, cx);
12694 }
12695 "textDocument/documentColor" => {
12696 server.update_capabilities(|capabilities| {
12697 capabilities.color_provider = None;
12698 });
12699 notify_server_capabilities_updated(&server, cx);
12700 }
12701 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12702 }
12703 }
12704
12705 Ok(())
12706 }
12707
12708 async fn deduplicate_range_based_lsp_requests<T>(
12709 lsp_store: &Entity<Self>,
12710 server_id: Option<LanguageServerId>,
12711 lsp_request_id: LspRequestId,
12712 proto_request: &T::ProtoRequest,
12713 range: Range<Anchor>,
12714 cx: &mut AsyncApp,
12715 ) -> Result<()>
12716 where
12717 T: LspCommand,
12718 T::ProtoRequest: proto::LspRequestMessage,
12719 {
12720 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12721 let version = deserialize_version(proto_request.buffer_version());
12722 let buffer = lsp_store.update(cx, |this, cx| {
12723 this.buffer_store.read(cx).get_existing(buffer_id)
12724 })??;
12725 buffer
12726 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12727 .await?;
12728 lsp_store.update(cx, |lsp_store, cx| {
12729 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12730 let chunks_queried_for = lsp_data
12731 .inlay_hints
12732 .applicable_chunks(&[range])
12733 .collect::<Vec<_>>();
12734 match chunks_queried_for.as_slice() {
12735 &[chunk] => {
12736 let key = LspKey {
12737 request_type: TypeId::of::<T>(),
12738 server_queried: server_id,
12739 };
12740 let previous_request = lsp_data
12741 .chunk_lsp_requests
12742 .entry(key)
12743 .or_default()
12744 .insert(chunk, lsp_request_id);
12745 if let Some((previous_request, running_requests)) =
12746 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12747 {
12748 running_requests.remove(&previous_request);
12749 }
12750 }
12751 _ambiguous_chunks => {
12752 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12753 // there, a buffer version-based check will be performed and outdated requests discarded.
12754 }
12755 }
12756 anyhow::Ok(())
12757 })??;
12758
12759 Ok(())
12760 }
12761
12762 async fn query_lsp_locally<T>(
12763 lsp_store: Entity<Self>,
12764 for_server_id: Option<LanguageServerId>,
12765 sender_id: proto::PeerId,
12766 lsp_request_id: LspRequestId,
12767 proto_request: T::ProtoRequest,
12768 position: Option<Anchor>,
12769 cx: &mut AsyncApp,
12770 ) -> Result<()>
12771 where
12772 T: LspCommand + Clone,
12773 T::ProtoRequest: proto::LspRequestMessage,
12774 <T::ProtoRequest as proto::RequestMessage>::Response:
12775 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12776 {
12777 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12778 let version = deserialize_version(proto_request.buffer_version());
12779 let buffer = lsp_store.update(cx, |this, cx| {
12780 this.buffer_store.read(cx).get_existing(buffer_id)
12781 })??;
12782 buffer
12783 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12784 .await?;
12785 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12786 let request =
12787 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12788 let key = LspKey {
12789 request_type: TypeId::of::<T>(),
12790 server_queried: for_server_id,
12791 };
12792 lsp_store.update(cx, |lsp_store, cx| {
12793 let request_task = match for_server_id {
12794 Some(server_id) => {
12795 let server_task = lsp_store.request_lsp(
12796 buffer.clone(),
12797 LanguageServerToQuery::Other(server_id),
12798 request.clone(),
12799 cx,
12800 );
12801 cx.background_spawn(async move {
12802 let mut responses = Vec::new();
12803 match server_task.await {
12804 Ok(response) => responses.push((server_id, response)),
12805 // rust-analyzer likes to error with this when its still loading up
12806 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12807 Err(e) => log::error!(
12808 "Error handling response for request {request:?}: {e:#}"
12809 ),
12810 }
12811 responses
12812 })
12813 }
12814 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12815 };
12816 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12817 if T::ProtoRequest::stop_previous_requests() {
12818 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12819 lsp_requests.clear();
12820 }
12821 }
12822 lsp_data.lsp_requests.entry(key).or_default().insert(
12823 lsp_request_id,
12824 cx.spawn(async move |lsp_store, cx| {
12825 let response = request_task.await;
12826 lsp_store
12827 .update(cx, |lsp_store, cx| {
12828 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12829 {
12830 let response = response
12831 .into_iter()
12832 .map(|(server_id, response)| {
12833 (
12834 server_id.to_proto(),
12835 T::response_to_proto(
12836 response,
12837 lsp_store,
12838 sender_id,
12839 &buffer_version,
12840 cx,
12841 )
12842 .into(),
12843 )
12844 })
12845 .collect::<HashMap<_, _>>();
12846 match client.send_lsp_response::<T::ProtoRequest>(
12847 project_id,
12848 lsp_request_id,
12849 response,
12850 ) {
12851 Ok(()) => {}
12852 Err(e) => {
12853 log::error!("Failed to send LSP response: {e:#}",)
12854 }
12855 }
12856 }
12857 })
12858 .ok();
12859 }),
12860 );
12861 })?;
12862 Ok(())
12863 }
12864
12865 fn take_text_document_sync_options(
12866 capabilities: &mut lsp::ServerCapabilities,
12867 ) -> lsp::TextDocumentSyncOptions {
12868 match capabilities.text_document_sync.take() {
12869 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12870 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12871 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12872 sync_options.change = Some(sync_kind);
12873 sync_options
12874 }
12875 None => lsp::TextDocumentSyncOptions::default(),
12876 }
12877 }
12878
12879 #[cfg(any(test, feature = "test-support"))]
12880 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12881 Some(
12882 self.lsp_data
12883 .get_mut(&buffer_id)?
12884 .code_lens
12885 .take()?
12886 .update
12887 .take()?
12888 .1,
12889 )
12890 }
12891
12892 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12893 self.downstream_client.clone()
12894 }
12895
12896 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12897 self.worktree_store.clone()
12898 }
12899
12900 /// Gets what's stored in the LSP data for the given buffer.
12901 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12902 self.lsp_data.get_mut(&buffer_id)
12903 }
12904
12905 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12906 /// new [`BufferLspData`] will be created to replace the previous state.
12907 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12908 let (buffer_id, buffer_version) =
12909 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12910 let lsp_data = self
12911 .lsp_data
12912 .entry(buffer_id)
12913 .or_insert_with(|| BufferLspData::new(buffer, cx));
12914 if buffer_version.changed_since(&lsp_data.buffer_version) {
12915 *lsp_data = BufferLspData::new(buffer, cx);
12916 }
12917 lsp_data
12918 }
12919}
12920
12921// Registration with registerOptions as null, should fallback to true.
12922// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12923fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12924 reg: lsp::Registration,
12925) -> Result<OneOf<bool, T>> {
12926 Ok(match reg.register_options {
12927 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12928 None => OneOf::Left(true),
12929 })
12930}
12931
12932fn subscribe_to_binary_statuses(
12933 languages: &Arc<LanguageRegistry>,
12934 cx: &mut Context<'_, LspStore>,
12935) -> Task<()> {
12936 let mut server_statuses = languages.language_server_binary_statuses();
12937 cx.spawn(async move |lsp_store, cx| {
12938 while let Some((server_name, binary_status)) = server_statuses.next().await {
12939 if lsp_store
12940 .update(cx, |_, cx| {
12941 let mut message = None;
12942 let binary_status = match binary_status {
12943 BinaryStatus::None => proto::ServerBinaryStatus::None,
12944 BinaryStatus::CheckingForUpdate => {
12945 proto::ServerBinaryStatus::CheckingForUpdate
12946 }
12947 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12948 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12949 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12950 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12951 BinaryStatus::Failed { error } => {
12952 message = Some(error);
12953 proto::ServerBinaryStatus::Failed
12954 }
12955 };
12956 cx.emit(LspStoreEvent::LanguageServerUpdate {
12957 // Binary updates are about the binary that might not have any language server id at that point.
12958 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12959 language_server_id: LanguageServerId(0),
12960 name: Some(server_name),
12961 message: proto::update_language_server::Variant::StatusUpdate(
12962 proto::StatusUpdate {
12963 message,
12964 status: Some(proto::status_update::Status::Binary(
12965 binary_status as i32,
12966 )),
12967 },
12968 ),
12969 });
12970 })
12971 .is_err()
12972 {
12973 break;
12974 }
12975 }
12976 })
12977}
12978
12979fn lsp_workspace_diagnostics_refresh(
12980 registration_id: Option<String>,
12981 options: DiagnosticServerCapabilities,
12982 server: Arc<LanguageServer>,
12983 cx: &mut Context<'_, LspStore>,
12984) -> Option<WorkspaceRefreshTask> {
12985 let identifier = workspace_diagnostic_identifier(&options)?;
12986 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
12987
12988 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12989 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12990 refresh_tx.try_send(()).ok();
12991
12992 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12993 let mut attempts = 0;
12994 let max_attempts = 50;
12995 let mut requests = 0;
12996
12997 loop {
12998 let Some(()) = refresh_rx.recv().await else {
12999 return;
13000 };
13001
13002 'request: loop {
13003 requests += 1;
13004 if attempts > max_attempts {
13005 log::error!(
13006 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13007 );
13008 return;
13009 }
13010 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13011 cx.background_executor()
13012 .timer(Duration::from_millis(backoff_millis))
13013 .await;
13014 attempts += 1;
13015
13016 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13017 lsp_store
13018 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13019 .into_iter()
13020 .filter_map(|(abs_path, result_id)| {
13021 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13022 Some(lsp::PreviousResultId {
13023 uri,
13024 value: result_id.to_string(),
13025 })
13026 })
13027 .collect()
13028 }) else {
13029 return;
13030 };
13031
13032 let token = if let Some(registration_id) = ®istration_id {
13033 format!(
13034 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13035 server.server_id(),
13036 )
13037 } else {
13038 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13039 };
13040
13041 progress_rx.try_recv().ok();
13042 let timer =
13043 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13044 let progress = pin!(progress_rx.recv().fuse());
13045 let response_result = server
13046 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13047 lsp::WorkspaceDiagnosticParams {
13048 previous_result_ids,
13049 identifier: identifier.clone(),
13050 work_done_progress_params: Default::default(),
13051 partial_result_params: lsp::PartialResultParams {
13052 partial_result_token: Some(lsp::ProgressToken::String(token)),
13053 },
13054 },
13055 select(timer, progress).then(|either| match either {
13056 Either::Left((message, ..)) => ready(message).left_future(),
13057 Either::Right(..) => pending::<String>().right_future(),
13058 }),
13059 )
13060 .await;
13061
13062 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13063 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13064 match response_result {
13065 ConnectionResult::Timeout => {
13066 log::error!("Timeout during workspace diagnostics pull");
13067 continue 'request;
13068 }
13069 ConnectionResult::ConnectionReset => {
13070 log::error!("Server closed a workspace diagnostics pull request");
13071 continue 'request;
13072 }
13073 ConnectionResult::Result(Err(e)) => {
13074 log::error!("Error during workspace diagnostics pull: {e:#}");
13075 break 'request;
13076 }
13077 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13078 attempts = 0;
13079 if lsp_store
13080 .update(cx, |lsp_store, cx| {
13081 lsp_store.apply_workspace_diagnostic_report(
13082 server.server_id(),
13083 pulled_diagnostics,
13084 registration_id_shared.clone(),
13085 cx,
13086 )
13087 })
13088 .is_err()
13089 {
13090 return;
13091 }
13092 break 'request;
13093 }
13094 }
13095 }
13096 }
13097 });
13098
13099 Some(WorkspaceRefreshTask {
13100 refresh_tx,
13101 progress_tx,
13102 task: workspace_query_language_server,
13103 })
13104}
13105
13106fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13107 match &options {
13108 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13109 diagnostic_options.identifier.clone()
13110 }
13111 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13112 let diagnostic_options = ®istration_options.diagnostic_options;
13113 diagnostic_options.identifier.clone()
13114 }
13115 }
13116}
13117
13118fn workspace_diagnostic_identifier(
13119 options: &DiagnosticServerCapabilities,
13120) -> Option<Option<String>> {
13121 match &options {
13122 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13123 if !diagnostic_options.workspace_diagnostics {
13124 return None;
13125 }
13126 Some(diagnostic_options.identifier.clone())
13127 }
13128 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13129 let diagnostic_options = ®istration_options.diagnostic_options;
13130 if !diagnostic_options.workspace_diagnostics {
13131 return None;
13132 }
13133 Some(diagnostic_options.identifier.clone())
13134 }
13135 }
13136}
13137
13138fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13139 let CompletionSource::BufferWord {
13140 word_range,
13141 resolved,
13142 } = &mut completion.source
13143 else {
13144 return;
13145 };
13146 if *resolved {
13147 return;
13148 }
13149
13150 if completion.new_text
13151 != snapshot
13152 .text_for_range(word_range.clone())
13153 .collect::<String>()
13154 {
13155 return;
13156 }
13157
13158 let mut offset = 0;
13159 for chunk in snapshot.chunks(word_range.clone(), true) {
13160 let end_offset = offset + chunk.text.len();
13161 if let Some(highlight_id) = chunk.syntax_highlight_id {
13162 completion
13163 .label
13164 .runs
13165 .push((offset..end_offset, highlight_id));
13166 }
13167 offset = end_offset;
13168 }
13169 *resolved = true;
13170}
13171
13172impl EventEmitter<LspStoreEvent> for LspStore {}
13173
13174fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13175 hover
13176 .contents
13177 .retain(|hover_block| !hover_block.text.trim().is_empty());
13178 if hover.contents.is_empty() {
13179 None
13180 } else {
13181 Some(hover)
13182 }
13183}
13184
13185async fn populate_labels_for_completions(
13186 new_completions: Vec<CoreCompletion>,
13187 language: Option<Arc<Language>>,
13188 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13189) -> Vec<Completion> {
13190 let lsp_completions = new_completions
13191 .iter()
13192 .filter_map(|new_completion| {
13193 new_completion
13194 .source
13195 .lsp_completion(true)
13196 .map(|lsp_completion| lsp_completion.into_owned())
13197 })
13198 .collect::<Vec<_>>();
13199
13200 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13201 lsp_adapter
13202 .labels_for_completions(&lsp_completions, language)
13203 .await
13204 .log_err()
13205 .unwrap_or_default()
13206 } else {
13207 Vec::new()
13208 }
13209 .into_iter()
13210 .fuse();
13211
13212 let mut completions = Vec::new();
13213 for completion in new_completions {
13214 match completion.source.lsp_completion(true) {
13215 Some(lsp_completion) => {
13216 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13217
13218 let mut label = labels.next().flatten().unwrap_or_else(|| {
13219 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13220 });
13221 ensure_uniform_list_compatible_label(&mut label);
13222 completions.push(Completion {
13223 label,
13224 documentation,
13225 replace_range: completion.replace_range,
13226 new_text: completion.new_text,
13227 insert_text_mode: lsp_completion.insert_text_mode,
13228 source: completion.source,
13229 icon_path: None,
13230 confirm: None,
13231 match_start: None,
13232 snippet_deduplication_key: None,
13233 });
13234 }
13235 None => {
13236 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13237 ensure_uniform_list_compatible_label(&mut label);
13238 completions.push(Completion {
13239 label,
13240 documentation: None,
13241 replace_range: completion.replace_range,
13242 new_text: completion.new_text,
13243 source: completion.source,
13244 insert_text_mode: None,
13245 icon_path: None,
13246 confirm: None,
13247 match_start: None,
13248 snippet_deduplication_key: None,
13249 });
13250 }
13251 }
13252 }
13253 completions
13254}
13255
13256#[derive(Debug)]
13257pub enum LanguageServerToQuery {
13258 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13259 FirstCapable,
13260 /// Query a specific language server.
13261 Other(LanguageServerId),
13262}
13263
13264#[derive(Default)]
13265struct RenamePathsWatchedForServer {
13266 did_rename: Vec<RenameActionPredicate>,
13267 will_rename: Vec<RenameActionPredicate>,
13268}
13269
13270impl RenamePathsWatchedForServer {
13271 fn with_did_rename_patterns(
13272 mut self,
13273 did_rename: Option<&FileOperationRegistrationOptions>,
13274 ) -> Self {
13275 if let Some(did_rename) = did_rename {
13276 self.did_rename = did_rename
13277 .filters
13278 .iter()
13279 .filter_map(|filter| filter.try_into().log_err())
13280 .collect();
13281 }
13282 self
13283 }
13284 fn with_will_rename_patterns(
13285 mut self,
13286 will_rename: Option<&FileOperationRegistrationOptions>,
13287 ) -> Self {
13288 if let Some(will_rename) = will_rename {
13289 self.will_rename = will_rename
13290 .filters
13291 .iter()
13292 .filter_map(|filter| filter.try_into().log_err())
13293 .collect();
13294 }
13295 self
13296 }
13297
13298 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13299 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13300 }
13301 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13302 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13303 }
13304}
13305
13306impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13307 type Error = globset::Error;
13308 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13309 Ok(Self {
13310 kind: ops.pattern.matches.clone(),
13311 glob: GlobBuilder::new(&ops.pattern.glob)
13312 .case_insensitive(
13313 ops.pattern
13314 .options
13315 .as_ref()
13316 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13317 )
13318 .build()?
13319 .compile_matcher(),
13320 })
13321 }
13322}
13323struct RenameActionPredicate {
13324 glob: GlobMatcher,
13325 kind: Option<FileOperationPatternKind>,
13326}
13327
13328impl RenameActionPredicate {
13329 // Returns true if language server should be notified
13330 fn eval(&self, path: &str, is_dir: bool) -> bool {
13331 self.kind.as_ref().is_none_or(|kind| {
13332 let expected_kind = if is_dir {
13333 FileOperationPatternKind::Folder
13334 } else {
13335 FileOperationPatternKind::File
13336 };
13337 kind == &expected_kind
13338 }) && self.glob.is_match(path)
13339 }
13340}
13341
13342#[derive(Default)]
13343struct LanguageServerWatchedPaths {
13344 worktree_paths: HashMap<WorktreeId, GlobSet>,
13345 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13346}
13347
13348#[derive(Default)]
13349struct LanguageServerWatchedPathsBuilder {
13350 worktree_paths: HashMap<WorktreeId, GlobSet>,
13351 abs_paths: HashMap<Arc<Path>, GlobSet>,
13352}
13353
13354impl LanguageServerWatchedPathsBuilder {
13355 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13356 self.worktree_paths.insert(worktree_id, glob_set);
13357 }
13358 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13359 self.abs_paths.insert(path, glob_set);
13360 }
13361 fn build(
13362 self,
13363 fs: Arc<dyn Fs>,
13364 language_server_id: LanguageServerId,
13365 cx: &mut Context<LspStore>,
13366 ) -> LanguageServerWatchedPaths {
13367 let lsp_store = cx.weak_entity();
13368
13369 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13370 let abs_paths = self
13371 .abs_paths
13372 .into_iter()
13373 .map(|(abs_path, globset)| {
13374 let task = cx.spawn({
13375 let abs_path = abs_path.clone();
13376 let fs = fs.clone();
13377
13378 let lsp_store = lsp_store.clone();
13379 async move |_, cx| {
13380 maybe!(async move {
13381 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13382 while let Some(update) = push_updates.0.next().await {
13383 let action = lsp_store
13384 .update(cx, |this, _| {
13385 let Some(local) = this.as_local() else {
13386 return ControlFlow::Break(());
13387 };
13388 let Some(watcher) = local
13389 .language_server_watched_paths
13390 .get(&language_server_id)
13391 else {
13392 return ControlFlow::Break(());
13393 };
13394 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13395 "Watched abs path is not registered with a watcher",
13396 );
13397 let matching_entries = update
13398 .into_iter()
13399 .filter(|event| globs.is_match(&event.path))
13400 .collect::<Vec<_>>();
13401 this.lsp_notify_abs_paths_changed(
13402 language_server_id,
13403 matching_entries,
13404 );
13405 ControlFlow::Continue(())
13406 })
13407 .ok()?;
13408
13409 if action.is_break() {
13410 break;
13411 }
13412 }
13413 Some(())
13414 })
13415 .await;
13416 }
13417 });
13418 (abs_path, (globset, task))
13419 })
13420 .collect();
13421 LanguageServerWatchedPaths {
13422 worktree_paths: self.worktree_paths,
13423 abs_paths,
13424 }
13425 }
13426}
13427
13428struct LspBufferSnapshot {
13429 version: i32,
13430 snapshot: TextBufferSnapshot,
13431}
13432
13433/// A prompt requested by LSP server.
13434#[derive(Clone, Debug)]
13435pub struct LanguageServerPromptRequest {
13436 pub level: PromptLevel,
13437 pub message: String,
13438 pub actions: Vec<MessageActionItem>,
13439 pub lsp_name: String,
13440 pub(crate) response_channel: Sender<MessageActionItem>,
13441}
13442
13443impl LanguageServerPromptRequest {
13444 pub async fn respond(self, index: usize) -> Option<()> {
13445 if let Some(response) = self.actions.into_iter().nth(index) {
13446 self.response_channel.send(response).await.ok()
13447 } else {
13448 None
13449 }
13450 }
13451}
13452impl PartialEq for LanguageServerPromptRequest {
13453 fn eq(&self, other: &Self) -> bool {
13454 self.message == other.message && self.actions == other.actions
13455 }
13456}
13457
13458#[derive(Clone, Debug, PartialEq)]
13459pub enum LanguageServerLogType {
13460 Log(MessageType),
13461 Trace { verbose_info: Option<String> },
13462 Rpc { received: bool },
13463}
13464
13465impl LanguageServerLogType {
13466 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13467 match self {
13468 Self::Log(log_type) => {
13469 use proto::log_message::LogLevel;
13470 let level = match *log_type {
13471 MessageType::ERROR => LogLevel::Error,
13472 MessageType::WARNING => LogLevel::Warning,
13473 MessageType::INFO => LogLevel::Info,
13474 MessageType::LOG => LogLevel::Log,
13475 other => {
13476 log::warn!("Unknown lsp log message type: {other:?}");
13477 LogLevel::Log
13478 }
13479 };
13480 proto::language_server_log::LogType::Log(proto::LogMessage {
13481 level: level as i32,
13482 })
13483 }
13484 Self::Trace { verbose_info } => {
13485 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13486 verbose_info: verbose_info.to_owned(),
13487 })
13488 }
13489 Self::Rpc { received } => {
13490 let kind = if *received {
13491 proto::rpc_message::Kind::Received
13492 } else {
13493 proto::rpc_message::Kind::Sent
13494 };
13495 let kind = kind as i32;
13496 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13497 }
13498 }
13499 }
13500
13501 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13502 use proto::log_message::LogLevel;
13503 use proto::rpc_message;
13504 match log_type {
13505 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13506 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13507 LogLevel::Error => MessageType::ERROR,
13508 LogLevel::Warning => MessageType::WARNING,
13509 LogLevel::Info => MessageType::INFO,
13510 LogLevel::Log => MessageType::LOG,
13511 },
13512 ),
13513 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13514 verbose_info: trace_message.verbose_info,
13515 },
13516 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13517 received: match rpc_message::Kind::from_i32(message.kind)
13518 .unwrap_or(rpc_message::Kind::Received)
13519 {
13520 rpc_message::Kind::Received => true,
13521 rpc_message::Kind::Sent => false,
13522 },
13523 },
13524 }
13525 }
13526}
13527
13528pub struct WorkspaceRefreshTask {
13529 refresh_tx: mpsc::Sender<()>,
13530 progress_tx: mpsc::Sender<()>,
13531 #[allow(dead_code)]
13532 task: Task<()>,
13533}
13534
13535pub enum LanguageServerState {
13536 Starting {
13537 startup: Task<Option<Arc<LanguageServer>>>,
13538 /// List of language servers that will be added to the workspace once it's initialization completes.
13539 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13540 },
13541
13542 Running {
13543 adapter: Arc<CachedLspAdapter>,
13544 server: Arc<LanguageServer>,
13545 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13546 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13547 },
13548}
13549
13550impl LanguageServerState {
13551 fn add_workspace_folder(&self, uri: Uri) {
13552 match self {
13553 LanguageServerState::Starting {
13554 pending_workspace_folders,
13555 ..
13556 } => {
13557 pending_workspace_folders.lock().insert(uri);
13558 }
13559 LanguageServerState::Running { server, .. } => {
13560 server.add_workspace_folder(uri);
13561 }
13562 }
13563 }
13564 fn _remove_workspace_folder(&self, uri: Uri) {
13565 match self {
13566 LanguageServerState::Starting {
13567 pending_workspace_folders,
13568 ..
13569 } => {
13570 pending_workspace_folders.lock().remove(&uri);
13571 }
13572 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13573 }
13574 }
13575}
13576
13577impl std::fmt::Debug for LanguageServerState {
13578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13579 match self {
13580 LanguageServerState::Starting { .. } => {
13581 f.debug_struct("LanguageServerState::Starting").finish()
13582 }
13583 LanguageServerState::Running { .. } => {
13584 f.debug_struct("LanguageServerState::Running").finish()
13585 }
13586 }
13587 }
13588}
13589
13590#[derive(Clone, Debug, Serialize)]
13591pub struct LanguageServerProgress {
13592 pub is_disk_based_diagnostics_progress: bool,
13593 pub is_cancellable: bool,
13594 pub title: Option<String>,
13595 pub message: Option<String>,
13596 pub percentage: Option<usize>,
13597 #[serde(skip_serializing)]
13598 pub last_update_at: Instant,
13599}
13600
13601#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13602pub struct DiagnosticSummary {
13603 pub error_count: usize,
13604 pub warning_count: usize,
13605}
13606
13607impl DiagnosticSummary {
13608 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13609 let mut this = Self {
13610 error_count: 0,
13611 warning_count: 0,
13612 };
13613
13614 for entry in diagnostics {
13615 if entry.diagnostic.is_primary {
13616 match entry.diagnostic.severity {
13617 DiagnosticSeverity::ERROR => this.error_count += 1,
13618 DiagnosticSeverity::WARNING => this.warning_count += 1,
13619 _ => {}
13620 }
13621 }
13622 }
13623
13624 this
13625 }
13626
13627 pub fn is_empty(&self) -> bool {
13628 self.error_count == 0 && self.warning_count == 0
13629 }
13630
13631 pub fn to_proto(
13632 self,
13633 language_server_id: LanguageServerId,
13634 path: &RelPath,
13635 ) -> proto::DiagnosticSummary {
13636 proto::DiagnosticSummary {
13637 path: path.to_proto(),
13638 language_server_id: language_server_id.0 as u64,
13639 error_count: self.error_count as u32,
13640 warning_count: self.warning_count as u32,
13641 }
13642 }
13643}
13644
13645#[derive(Clone, Debug)]
13646pub enum CompletionDocumentation {
13647 /// There is no documentation for this completion.
13648 Undocumented,
13649 /// A single line of documentation.
13650 SingleLine(SharedString),
13651 /// Multiple lines of plain text documentation.
13652 MultiLinePlainText(SharedString),
13653 /// Markdown documentation.
13654 MultiLineMarkdown(SharedString),
13655 /// Both single line and multiple lines of plain text documentation.
13656 SingleLineAndMultiLinePlainText {
13657 single_line: SharedString,
13658 plain_text: Option<SharedString>,
13659 },
13660}
13661
13662impl CompletionDocumentation {
13663 #[cfg(any(test, feature = "test-support"))]
13664 pub fn text(&self) -> SharedString {
13665 match self {
13666 CompletionDocumentation::Undocumented => "".into(),
13667 CompletionDocumentation::SingleLine(s) => s.clone(),
13668 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13669 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13670 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13671 single_line.clone()
13672 }
13673 }
13674 }
13675}
13676
13677impl From<lsp::Documentation> for CompletionDocumentation {
13678 fn from(docs: lsp::Documentation) -> Self {
13679 match docs {
13680 lsp::Documentation::String(text) => {
13681 if text.lines().count() <= 1 {
13682 CompletionDocumentation::SingleLine(text.into())
13683 } else {
13684 CompletionDocumentation::MultiLinePlainText(text.into())
13685 }
13686 }
13687
13688 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13689 lsp::MarkupKind::PlainText => {
13690 if value.lines().count() <= 1 {
13691 CompletionDocumentation::SingleLine(value.into())
13692 } else {
13693 CompletionDocumentation::MultiLinePlainText(value.into())
13694 }
13695 }
13696
13697 lsp::MarkupKind::Markdown => {
13698 CompletionDocumentation::MultiLineMarkdown(value.into())
13699 }
13700 },
13701 }
13702 }
13703}
13704
13705pub enum ResolvedHint {
13706 Resolved(InlayHint),
13707 Resolving(Shared<Task<()>>),
13708}
13709
13710fn glob_literal_prefix(glob: &Path) -> PathBuf {
13711 glob.components()
13712 .take_while(|component| match component {
13713 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13714 _ => true,
13715 })
13716 .collect()
13717}
13718
13719pub struct SshLspAdapter {
13720 name: LanguageServerName,
13721 binary: LanguageServerBinary,
13722 initialization_options: Option<String>,
13723 code_action_kinds: Option<Vec<CodeActionKind>>,
13724}
13725
13726impl SshLspAdapter {
13727 pub fn new(
13728 name: LanguageServerName,
13729 binary: LanguageServerBinary,
13730 initialization_options: Option<String>,
13731 code_action_kinds: Option<String>,
13732 ) -> Self {
13733 Self {
13734 name,
13735 binary,
13736 initialization_options,
13737 code_action_kinds: code_action_kinds
13738 .as_ref()
13739 .and_then(|c| serde_json::from_str(c).ok()),
13740 }
13741 }
13742}
13743
13744impl LspInstaller for SshLspAdapter {
13745 type BinaryVersion = ();
13746 async fn check_if_user_installed(
13747 &self,
13748 _: &dyn LspAdapterDelegate,
13749 _: Option<Toolchain>,
13750 _: &AsyncApp,
13751 ) -> Option<LanguageServerBinary> {
13752 Some(self.binary.clone())
13753 }
13754
13755 async fn cached_server_binary(
13756 &self,
13757 _: PathBuf,
13758 _: &dyn LspAdapterDelegate,
13759 ) -> Option<LanguageServerBinary> {
13760 None
13761 }
13762
13763 async fn fetch_latest_server_version(
13764 &self,
13765 _: &dyn LspAdapterDelegate,
13766 _: bool,
13767 _: &mut AsyncApp,
13768 ) -> Result<()> {
13769 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13770 }
13771
13772 async fn fetch_server_binary(
13773 &self,
13774 _: (),
13775 _: PathBuf,
13776 _: &dyn LspAdapterDelegate,
13777 ) -> Result<LanguageServerBinary> {
13778 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13779 }
13780}
13781
13782#[async_trait(?Send)]
13783impl LspAdapter for SshLspAdapter {
13784 fn name(&self) -> LanguageServerName {
13785 self.name.clone()
13786 }
13787
13788 async fn initialization_options(
13789 self: Arc<Self>,
13790 _: &Arc<dyn LspAdapterDelegate>,
13791 ) -> Result<Option<serde_json::Value>> {
13792 let Some(options) = &self.initialization_options else {
13793 return Ok(None);
13794 };
13795 let result = serde_json::from_str(options)?;
13796 Ok(result)
13797 }
13798
13799 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13800 self.code_action_kinds.clone()
13801 }
13802}
13803
13804pub fn language_server_settings<'a>(
13805 delegate: &'a dyn LspAdapterDelegate,
13806 language: &LanguageServerName,
13807 cx: &'a App,
13808) -> Option<&'a LspSettings> {
13809 language_server_settings_for(
13810 SettingsLocation {
13811 worktree_id: delegate.worktree_id(),
13812 path: RelPath::empty(),
13813 },
13814 language,
13815 cx,
13816 )
13817}
13818
13819pub fn language_server_settings_for<'a>(
13820 location: SettingsLocation<'a>,
13821 language: &LanguageServerName,
13822 cx: &'a App,
13823) -> Option<&'a LspSettings> {
13824 ProjectSettings::get(Some(location), cx).lsp.get(language)
13825}
13826
13827pub struct LocalLspAdapterDelegate {
13828 lsp_store: WeakEntity<LspStore>,
13829 worktree: worktree::Snapshot,
13830 fs: Arc<dyn Fs>,
13831 http_client: Arc<dyn HttpClient>,
13832 language_registry: Arc<LanguageRegistry>,
13833 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13834}
13835
13836impl LocalLspAdapterDelegate {
13837 pub fn new(
13838 language_registry: Arc<LanguageRegistry>,
13839 environment: &Entity<ProjectEnvironment>,
13840 lsp_store: WeakEntity<LspStore>,
13841 worktree: &Entity<Worktree>,
13842 http_client: Arc<dyn HttpClient>,
13843 fs: Arc<dyn Fs>,
13844 cx: &mut App,
13845 ) -> Arc<Self> {
13846 let load_shell_env_task =
13847 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13848
13849 Arc::new(Self {
13850 lsp_store,
13851 worktree: worktree.read(cx).snapshot(),
13852 fs,
13853 http_client,
13854 language_registry,
13855 load_shell_env_task,
13856 })
13857 }
13858
13859 fn from_local_lsp(
13860 local: &LocalLspStore,
13861 worktree: &Entity<Worktree>,
13862 cx: &mut App,
13863 ) -> Arc<Self> {
13864 Self::new(
13865 local.languages.clone(),
13866 &local.environment,
13867 local.weak.clone(),
13868 worktree,
13869 local.http_client.clone(),
13870 local.fs.clone(),
13871 cx,
13872 )
13873 }
13874}
13875
13876#[async_trait]
13877impl LspAdapterDelegate for LocalLspAdapterDelegate {
13878 fn show_notification(&self, message: &str, cx: &mut App) {
13879 self.lsp_store
13880 .update(cx, |_, cx| {
13881 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13882 })
13883 .ok();
13884 }
13885
13886 fn http_client(&self) -> Arc<dyn HttpClient> {
13887 self.http_client.clone()
13888 }
13889
13890 fn worktree_id(&self) -> WorktreeId {
13891 self.worktree.id()
13892 }
13893
13894 fn worktree_root_path(&self) -> &Path {
13895 self.worktree.abs_path().as_ref()
13896 }
13897
13898 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13899 self.worktree.resolve_executable_path(path)
13900 }
13901
13902 async fn shell_env(&self) -> HashMap<String, String> {
13903 let task = self.load_shell_env_task.clone();
13904 task.await.unwrap_or_default()
13905 }
13906
13907 async fn npm_package_installed_version(
13908 &self,
13909 package_name: &str,
13910 ) -> Result<Option<(PathBuf, String)>> {
13911 let local_package_directory = self.worktree_root_path();
13912 let node_modules_directory = local_package_directory.join("node_modules");
13913
13914 if let Some(version) =
13915 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13916 {
13917 return Ok(Some((node_modules_directory, version)));
13918 }
13919 let Some(npm) = self.which("npm".as_ref()).await else {
13920 log::warn!(
13921 "Failed to find npm executable for {:?}",
13922 local_package_directory
13923 );
13924 return Ok(None);
13925 };
13926
13927 let env = self.shell_env().await;
13928 let output = util::command::new_smol_command(&npm)
13929 .args(["root", "-g"])
13930 .envs(env)
13931 .current_dir(local_package_directory)
13932 .output()
13933 .await?;
13934 let global_node_modules =
13935 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13936
13937 if let Some(version) =
13938 read_package_installed_version(global_node_modules.clone(), package_name).await?
13939 {
13940 return Ok(Some((global_node_modules, version)));
13941 }
13942 return Ok(None);
13943 }
13944
13945 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13946 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13947 if self.fs.is_file(&worktree_abs_path).await {
13948 worktree_abs_path.pop();
13949 }
13950
13951 let env = self.shell_env().await;
13952
13953 let shell_path = env.get("PATH").cloned();
13954
13955 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13956 }
13957
13958 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13959 let mut working_dir = self.worktree_root_path().to_path_buf();
13960 if self.fs.is_file(&working_dir).await {
13961 working_dir.pop();
13962 }
13963 let output = util::command::new_smol_command(&command.path)
13964 .args(command.arguments)
13965 .envs(command.env.clone().unwrap_or_default())
13966 .current_dir(working_dir)
13967 .output()
13968 .await?;
13969
13970 anyhow::ensure!(
13971 output.status.success(),
13972 "{}, stdout: {:?}, stderr: {:?}",
13973 output.status,
13974 String::from_utf8_lossy(&output.stdout),
13975 String::from_utf8_lossy(&output.stderr)
13976 );
13977 Ok(())
13978 }
13979
13980 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13981 self.language_registry
13982 .update_lsp_binary_status(server_name, status);
13983 }
13984
13985 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13986 self.language_registry
13987 .all_lsp_adapters()
13988 .into_iter()
13989 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13990 .collect()
13991 }
13992
13993 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13994 let dir = self.language_registry.language_server_download_dir(name)?;
13995
13996 if !dir.exists() {
13997 smol::fs::create_dir_all(&dir)
13998 .await
13999 .context("failed to create container directory")
14000 .log_err()?;
14001 }
14002
14003 Some(dir)
14004 }
14005
14006 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14007 let entry = self
14008 .worktree
14009 .entry_for_path(path)
14010 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14011 let abs_path = self.worktree.absolutize(&entry.path);
14012 self.fs.load(&abs_path).await
14013 }
14014}
14015
14016async fn populate_labels_for_symbols(
14017 symbols: Vec<CoreSymbol>,
14018 language_registry: &Arc<LanguageRegistry>,
14019 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14020 output: &mut Vec<Symbol>,
14021) {
14022 #[allow(clippy::mutable_key_type)]
14023 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14024
14025 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14026 for symbol in symbols {
14027 let Some(file_name) = symbol.path.file_name() else {
14028 continue;
14029 };
14030 let language = language_registry
14031 .load_language_for_file_path(Path::new(file_name))
14032 .await
14033 .ok()
14034 .or_else(|| {
14035 unknown_paths.insert(file_name.into());
14036 None
14037 });
14038 symbols_by_language
14039 .entry(language)
14040 .or_default()
14041 .push(symbol);
14042 }
14043
14044 for unknown_path in unknown_paths {
14045 log::info!("no language found for symbol in file {unknown_path:?}");
14046 }
14047
14048 let mut label_params = Vec::new();
14049 for (language, mut symbols) in symbols_by_language {
14050 label_params.clear();
14051 label_params.extend(
14052 symbols
14053 .iter_mut()
14054 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14055 );
14056
14057 let mut labels = Vec::new();
14058 if let Some(language) = language {
14059 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14060 language_registry
14061 .lsp_adapters(&language.name())
14062 .first()
14063 .cloned()
14064 });
14065 if let Some(lsp_adapter) = lsp_adapter {
14066 labels = lsp_adapter
14067 .labels_for_symbols(&label_params, &language)
14068 .await
14069 .log_err()
14070 .unwrap_or_default();
14071 }
14072 }
14073
14074 for ((symbol, (name, _)), label) in symbols
14075 .into_iter()
14076 .zip(label_params.drain(..))
14077 .zip(labels.into_iter().chain(iter::repeat(None)))
14078 {
14079 output.push(Symbol {
14080 language_server_name: symbol.language_server_name,
14081 source_worktree_id: symbol.source_worktree_id,
14082 source_language_server_id: symbol.source_language_server_id,
14083 path: symbol.path,
14084 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14085 name,
14086 kind: symbol.kind,
14087 range: symbol.range,
14088 });
14089 }
14090 }
14091}
14092
14093fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14094 match server.capabilities().text_document_sync.as_ref()? {
14095 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14096 // Server wants didSave but didn't specify includeText.
14097 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14098 // Server doesn't want didSave at all.
14099 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14100 // Server provided SaveOptions.
14101 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14102 Some(save_options.include_text.unwrap_or(false))
14103 }
14104 },
14105 // We do not have any save info. Kind affects didChange only.
14106 lsp::TextDocumentSyncCapability::Kind(_) => None,
14107 }
14108}
14109
14110/// Completion items are displayed in a `UniformList`.
14111/// Usually, those items are single-line strings, but in LSP responses,
14112/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14113/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14114/// 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,
14115/// breaking the completions menu presentation.
14116///
14117/// 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.
14118fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14119 let mut new_text = String::with_capacity(label.text.len());
14120 let mut offset_map = vec![0; label.text.len() + 1];
14121 let mut last_char_was_space = false;
14122 let mut new_idx = 0;
14123 let chars = label.text.char_indices().fuse();
14124 let mut newlines_removed = false;
14125
14126 for (idx, c) in chars {
14127 offset_map[idx] = new_idx;
14128
14129 match c {
14130 '\n' if last_char_was_space => {
14131 newlines_removed = true;
14132 }
14133 '\t' | ' ' if last_char_was_space => {}
14134 '\n' if !last_char_was_space => {
14135 new_text.push(' ');
14136 new_idx += 1;
14137 last_char_was_space = true;
14138 newlines_removed = true;
14139 }
14140 ' ' | '\t' => {
14141 new_text.push(' ');
14142 new_idx += 1;
14143 last_char_was_space = true;
14144 }
14145 _ => {
14146 new_text.push(c);
14147 new_idx += c.len_utf8();
14148 last_char_was_space = false;
14149 }
14150 }
14151 }
14152 offset_map[label.text.len()] = new_idx;
14153
14154 // Only modify the label if newlines were removed.
14155 if !newlines_removed {
14156 return;
14157 }
14158
14159 let last_index = new_idx;
14160 let mut run_ranges_errors = Vec::new();
14161 label.runs.retain_mut(|(range, _)| {
14162 match offset_map.get(range.start) {
14163 Some(&start) => range.start = start,
14164 None => {
14165 run_ranges_errors.push(range.clone());
14166 return false;
14167 }
14168 }
14169
14170 match offset_map.get(range.end) {
14171 Some(&end) => range.end = end,
14172 None => {
14173 run_ranges_errors.push(range.clone());
14174 range.end = last_index;
14175 }
14176 }
14177 true
14178 });
14179 if !run_ranges_errors.is_empty() {
14180 log::error!(
14181 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14182 label.text
14183 );
14184 }
14185
14186 let mut wrong_filter_range = None;
14187 if label.filter_range == (0..label.text.len()) {
14188 label.filter_range = 0..new_text.len();
14189 } else {
14190 let mut original_filter_range = Some(label.filter_range.clone());
14191 match offset_map.get(label.filter_range.start) {
14192 Some(&start) => label.filter_range.start = start,
14193 None => {
14194 wrong_filter_range = original_filter_range.take();
14195 label.filter_range.start = last_index;
14196 }
14197 }
14198
14199 match offset_map.get(label.filter_range.end) {
14200 Some(&end) => label.filter_range.end = end,
14201 None => {
14202 wrong_filter_range = original_filter_range.take();
14203 label.filter_range.end = last_index;
14204 }
14205 }
14206 }
14207 if let Some(wrong_filter_range) = wrong_filter_range {
14208 log::error!(
14209 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14210 label.text
14211 );
14212 }
14213
14214 label.text = new_text;
14215}
14216
14217#[cfg(test)]
14218mod tests {
14219 use language::HighlightId;
14220
14221 use super::*;
14222
14223 #[test]
14224 fn test_glob_literal_prefix() {
14225 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14226 assert_eq!(
14227 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14228 Path::new("node_modules")
14229 );
14230 assert_eq!(
14231 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14232 Path::new("foo")
14233 );
14234 assert_eq!(
14235 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14236 Path::new("foo/bar/baz.js")
14237 );
14238
14239 #[cfg(target_os = "windows")]
14240 {
14241 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14242 assert_eq!(
14243 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14244 Path::new("node_modules")
14245 );
14246 assert_eq!(
14247 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14248 Path::new("foo")
14249 );
14250 assert_eq!(
14251 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14252 Path::new("foo/bar/baz.js")
14253 );
14254 }
14255 }
14256
14257 #[test]
14258 fn test_multi_len_chars_normalization() {
14259 let mut label = CodeLabel::new(
14260 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14261 0..6,
14262 vec![(0..6, HighlightId(1))],
14263 );
14264 ensure_uniform_list_compatible_label(&mut label);
14265 assert_eq!(
14266 label,
14267 CodeLabel::new(
14268 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14269 0..6,
14270 vec![(0..6, HighlightId(1))],
14271 )
14272 );
14273 }
14274}