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 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
79 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
80 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
81 LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
82 LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture,
83 MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
84 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
85 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 settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum FormatTrigger {
144 Save,
145 Manual,
146}
147
148pub enum LspFormatTarget {
149 Buffers,
150 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
151}
152
153pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
154
155impl FormatTrigger {
156 fn from_proto(value: i32) -> FormatTrigger {
157 match value {
158 0 => FormatTrigger::Save,
159 1 => FormatTrigger::Manual,
160 _ => FormatTrigger::Save,
161 }
162 }
163}
164
165#[derive(Clone)]
166struct UnifiedLanguageServer {
167 id: LanguageServerId,
168 project_roots: HashSet<Arc<RelPath>>,
169}
170
171#[derive(Clone, Hash, PartialEq, Eq)]
172struct LanguageServerSeed {
173 worktree_id: WorktreeId,
174 name: LanguageServerName,
175 toolchain: Option<Toolchain>,
176 settings: Arc<LspSettings>,
177}
178
179#[derive(Debug)]
180pub struct DocumentDiagnosticsUpdate<'a, D> {
181 pub diagnostics: D,
182 pub result_id: Option<String>,
183 pub server_id: LanguageServerId,
184 pub disk_based_sources: Cow<'a, [String]>,
185}
186
187pub struct DocumentDiagnostics {
188 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
189 document_abs_path: PathBuf,
190 version: Option<i32>,
191}
192
193pub struct LocalLspStore {
194 weak: WeakEntity<LspStore>,
195 worktree_store: Entity<WorktreeStore>,
196 toolchain_store: Entity<LocalToolchainStore>,
197 http_client: Arc<dyn HttpClient>,
198 environment: Entity<ProjectEnvironment>,
199 fs: Arc<dyn Fs>,
200 languages: Arc<LanguageRegistry>,
201 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
202 yarn: Entity<YarnPathStore>,
203 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
204 buffers_being_formatted: HashSet<BufferId>,
205 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
206 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
207 watched_manifest_filenames: HashSet<ManifestName>,
208 language_server_paths_watched_for_rename:
209 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
210 language_server_watcher_registrations:
211 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
212 supplementary_language_servers:
213 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
214 prettier_store: Entity<PrettierStore>,
215 next_diagnostic_group_id: usize,
216 diagnostics: HashMap<
217 WorktreeId,
218 HashMap<
219 Arc<RelPath>,
220 Vec<(
221 LanguageServerId,
222 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
223 )>,
224 >,
225 >,
226 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
227 _subscription: gpui::Subscription,
228 lsp_tree: LanguageServerTree,
229 registered_buffers: HashMap<BufferId, usize>,
230 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
231 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
232}
233
234impl LocalLspStore {
235 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
236 pub fn running_language_server_for_id(
237 &self,
238 id: LanguageServerId,
239 ) -> Option<&Arc<LanguageServer>> {
240 let language_server_state = self.language_servers.get(&id)?;
241
242 match language_server_state {
243 LanguageServerState::Running { server, .. } => Some(server),
244 LanguageServerState::Starting { .. } => None,
245 }
246 }
247
248 fn get_or_insert_language_server(
249 &mut self,
250 worktree_handle: &Entity<Worktree>,
251 delegate: Arc<LocalLspAdapterDelegate>,
252 disposition: &Arc<LaunchDisposition>,
253 language_name: &LanguageName,
254 cx: &mut App,
255 ) -> LanguageServerId {
256 let key = LanguageServerSeed {
257 worktree_id: worktree_handle.read(cx).id(),
258 name: disposition.server_name.clone(),
259 settings: disposition.settings.clone(),
260 toolchain: disposition.toolchain.clone(),
261 };
262 if let Some(state) = self.language_server_ids.get_mut(&key) {
263 state.project_roots.insert(disposition.path.path.clone());
264 state.id
265 } else {
266 let adapter = self
267 .languages
268 .lsp_adapters(language_name)
269 .into_iter()
270 .find(|adapter| adapter.name() == disposition.server_name)
271 .expect("To find LSP adapter");
272 let new_language_server_id = self.start_language_server(
273 worktree_handle,
274 delegate,
275 adapter,
276 disposition.settings.clone(),
277 key.clone(),
278 cx,
279 );
280 if let Some(state) = self.language_server_ids.get_mut(&key) {
281 state.project_roots.insert(disposition.path.path.clone());
282 } else {
283 debug_assert!(
284 false,
285 "Expected `start_language_server` to ensure that `key` exists in a map"
286 );
287 }
288 new_language_server_id
289 }
290 }
291
292 fn start_language_server(
293 &mut self,
294 worktree_handle: &Entity<Worktree>,
295 delegate: Arc<LocalLspAdapterDelegate>,
296 adapter: Arc<CachedLspAdapter>,
297 settings: Arc<LspSettings>,
298 key: LanguageServerSeed,
299 cx: &mut App,
300 ) -> LanguageServerId {
301 let worktree = worktree_handle.read(cx);
302
303 let root_path = worktree.abs_path();
304 let toolchain = key.toolchain.clone();
305 let override_options = settings.initialization_options.clone();
306
307 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
308
309 let server_id = self.languages.next_language_server_id();
310 log::trace!(
311 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
312 adapter.name.0
313 );
314
315 let binary = self.get_language_server_binary(
316 adapter.clone(),
317 settings,
318 toolchain.clone(),
319 delegate.clone(),
320 true,
321 cx,
322 );
323 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
324
325 let pending_server = cx.spawn({
326 let adapter = adapter.clone();
327 let server_name = adapter.name.clone();
328 let stderr_capture = stderr_capture.clone();
329 #[cfg(any(test, feature = "test-support"))]
330 let lsp_store = self.weak.clone();
331 let pending_workspace_folders = pending_workspace_folders.clone();
332 async move |cx| {
333 let binary = binary.await?;
334 #[cfg(any(test, feature = "test-support"))]
335 if let Some(server) = lsp_store
336 .update(&mut cx.clone(), |this, cx| {
337 this.languages.create_fake_language_server(
338 server_id,
339 &server_name,
340 binary.clone(),
341 &mut cx.to_async(),
342 )
343 })
344 .ok()
345 .flatten()
346 {
347 return Ok(server);
348 }
349
350 let code_action_kinds = adapter.code_action_kinds();
351 lsp::LanguageServer::new(
352 stderr_capture,
353 server_id,
354 server_name,
355 binary,
356 &root_path,
357 code_action_kinds,
358 Some(pending_workspace_folders),
359 cx,
360 )
361 }
362 });
363
364 let startup = {
365 let server_name = adapter.name.0.clone();
366 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
367 let key = key.clone();
368 let adapter = adapter.clone();
369 let lsp_store = self.weak.clone();
370 let pending_workspace_folders = pending_workspace_folders.clone();
371
372 let pull_diagnostics = ProjectSettings::get_global(cx)
373 .diagnostics
374 .lsp_pull_diagnostics
375 .enabled;
376 cx.spawn(async move |cx| {
377 let result = async {
378 let language_server = pending_server.await?;
379
380 let workspace_config = Self::workspace_configuration_for_adapter(
381 adapter.adapter.clone(),
382 &delegate,
383 toolchain,
384 cx,
385 )
386 .await?;
387
388 let mut initialization_options = Self::initialization_options_for_adapter(
389 adapter.adapter.clone(),
390 &delegate,
391 )
392 .await?;
393
394 match (&mut initialization_options, override_options) {
395 (Some(initialization_options), Some(override_options)) => {
396 merge_json_value_into(override_options, initialization_options);
397 }
398 (None, override_options) => initialization_options = override_options,
399 _ => {}
400 }
401
402 let initialization_params = cx.update(|cx| {
403 let mut params =
404 language_server.default_initialize_params(pull_diagnostics, cx);
405 params.initialization_options = initialization_options;
406 adapter.adapter.prepare_initialize_params(params, cx)
407 })??;
408
409 Self::setup_lsp_messages(
410 lsp_store.clone(),
411 &language_server,
412 delegate.clone(),
413 adapter.clone(),
414 );
415
416 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
417 settings: workspace_config,
418 };
419 let language_server = cx
420 .update(|cx| {
421 language_server.initialize(
422 initialization_params,
423 Arc::new(did_change_configuration_params.clone()),
424 cx,
425 )
426 })?
427 .await
428 .inspect_err(|_| {
429 if let Some(lsp_store) = lsp_store.upgrade() {
430 lsp_store
431 .update(cx, |lsp_store, cx| {
432 lsp_store.cleanup_lsp_data(server_id);
433 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
434 })
435 .ok();
436 }
437 })?;
438
439 language_server.notify::<lsp::notification::DidChangeConfiguration>(
440 did_change_configuration_params,
441 )?;
442
443 anyhow::Ok(language_server)
444 }
445 .await;
446
447 match result {
448 Ok(server) => {
449 lsp_store
450 .update(cx, |lsp_store, cx| {
451 lsp_store.insert_newly_running_language_server(
452 adapter,
453 server.clone(),
454 server_id,
455 key,
456 pending_workspace_folders,
457 cx,
458 );
459 })
460 .ok();
461 stderr_capture.lock().take();
462 Some(server)
463 }
464
465 Err(err) => {
466 let log = stderr_capture.lock().take().unwrap_or_default();
467 delegate.update_status(
468 adapter.name(),
469 BinaryStatus::Failed {
470 error: if log.is_empty() {
471 format!("{err:#}")
472 } else {
473 format!("{err:#}\n-- stderr --\n{log}")
474 },
475 },
476 );
477 log::error!("Failed to start language server {server_name:?}: {err:?}");
478 if !log.is_empty() {
479 log::error!("server stderr: {log}");
480 }
481 None
482 }
483 }
484 })
485 };
486 let state = LanguageServerState::Starting {
487 startup,
488 pending_workspace_folders,
489 };
490
491 self.languages
492 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
493
494 self.language_servers.insert(server_id, state);
495 self.language_server_ids
496 .entry(key)
497 .or_insert(UnifiedLanguageServer {
498 id: server_id,
499 project_roots: Default::default(),
500 });
501 server_id
502 }
503
504 fn get_language_server_binary(
505 &self,
506 adapter: Arc<CachedLspAdapter>,
507 settings: Arc<LspSettings>,
508 toolchain: Option<Toolchain>,
509 delegate: Arc<dyn LspAdapterDelegate>,
510 allow_binary_download: bool,
511 cx: &mut App,
512 ) -> Task<Result<LanguageServerBinary>> {
513 if let Some(settings) = settings.binary.as_ref()
514 && settings.path.is_some()
515 {
516 let settings = settings.clone();
517
518 return cx.background_spawn(async move {
519 let mut env = delegate.shell_env().await;
520 env.extend(settings.env.unwrap_or_default());
521
522 Ok(LanguageServerBinary {
523 path: PathBuf::from(&settings.path.unwrap()),
524 env: Some(env),
525 arguments: settings
526 .arguments
527 .unwrap_or_default()
528 .iter()
529 .map(Into::into)
530 .collect(),
531 })
532 });
533 }
534 let lsp_binary_options = LanguageServerBinaryOptions {
535 allow_path_lookup: !settings
536 .binary
537 .as_ref()
538 .and_then(|b| b.ignore_system_version)
539 .unwrap_or_default(),
540 allow_binary_download,
541 pre_release: settings
542 .fetch
543 .as_ref()
544 .and_then(|f| f.pre_release)
545 .unwrap_or(false),
546 };
547
548 cx.spawn(async move |cx| {
549 let binary_result = adapter
550 .clone()
551 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
552 .await;
553
554 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
555
556 let mut binary = binary_result?;
557 let mut shell_env = delegate.shell_env().await;
558
559 shell_env.extend(binary.env.unwrap_or_default());
560
561 if let Some(settings) = settings.binary.as_ref() {
562 if let Some(arguments) = &settings.arguments {
563 binary.arguments = arguments.iter().map(Into::into).collect();
564 }
565 if let Some(env) = &settings.env {
566 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
567 }
568 }
569
570 binary.env = Some(shell_env);
571 Ok(binary)
572 })
573 }
574
575 fn setup_lsp_messages(
576 lsp_store: WeakEntity<LspStore>,
577 language_server: &LanguageServer,
578 delegate: Arc<dyn LspAdapterDelegate>,
579 adapter: Arc<CachedLspAdapter>,
580 ) {
581 let name = language_server.name();
582 let server_id = language_server.server_id();
583 language_server
584 .on_notification::<lsp::notification::PublishDiagnostics, _>({
585 let adapter = adapter.clone();
586 let this = lsp_store.clone();
587 move |mut params, cx| {
588 let adapter = adapter.clone();
589 if let Some(this) = this.upgrade() {
590 this.update(cx, |this, cx| {
591 {
592 let buffer = params
593 .uri
594 .to_file_path()
595 .map(|file_path| this.get_buffer(&file_path, cx))
596 .ok()
597 .flatten();
598 adapter.process_diagnostics(&mut params, server_id, buffer);
599 }
600
601 this.merge_lsp_diagnostics(
602 DiagnosticSourceKind::Pushed,
603 vec![DocumentDiagnosticsUpdate {
604 server_id,
605 diagnostics: params,
606 result_id: None,
607 disk_based_sources: Cow::Borrowed(
608 &adapter.disk_based_diagnostic_sources,
609 ),
610 }],
611 |_, diagnostic, cx| match diagnostic.source_kind {
612 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
613 adapter.retain_old_diagnostic(diagnostic, cx)
614 }
615 DiagnosticSourceKind::Pulled => true,
616 },
617 cx,
618 )
619 .log_err();
620 })
621 .ok();
622 }
623 }
624 })
625 .detach();
626 language_server
627 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
628 let adapter = adapter.adapter.clone();
629 let delegate = delegate.clone();
630 let this = lsp_store.clone();
631 move |params, cx| {
632 let adapter = adapter.clone();
633 let delegate = delegate.clone();
634 let this = this.clone();
635 let mut cx = cx.clone();
636 async move {
637 let toolchain_for_id = this
638 .update(&mut cx, |this, _| {
639 this.as_local()?.language_server_ids.iter().find_map(
640 |(seed, value)| {
641 (value.id == server_id).then(|| seed.toolchain.clone())
642 },
643 )
644 })?
645 .context("Expected the LSP store to be in a local mode")?;
646 let workspace_config = Self::workspace_configuration_for_adapter(
647 adapter.clone(),
648 &delegate,
649 toolchain_for_id,
650 &mut cx,
651 )
652 .await?;
653
654 Ok(params
655 .items
656 .into_iter()
657 .map(|item| {
658 if let Some(section) = &item.section {
659 workspace_config
660 .get(section)
661 .cloned()
662 .unwrap_or(serde_json::Value::Null)
663 } else {
664 workspace_config.clone()
665 }
666 })
667 .collect())
668 }
669 }
670 })
671 .detach();
672
673 language_server
674 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
675 let this = lsp_store.clone();
676 move |_, cx| {
677 let this = this.clone();
678 let cx = cx.clone();
679 async move {
680 let Some(server) =
681 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
682 else {
683 return Ok(None);
684 };
685 let root = server.workspace_folders();
686 Ok(Some(
687 root.into_iter()
688 .map(|uri| WorkspaceFolder {
689 uri,
690 name: Default::default(),
691 })
692 .collect(),
693 ))
694 }
695 }
696 })
697 .detach();
698 // Even though we don't have handling for these requests, respond to them to
699 // avoid stalling any language server like `gopls` which waits for a response
700 // to these requests when initializing.
701 language_server
702 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
703 let this = lsp_store.clone();
704 move |params, cx| {
705 let this = this.clone();
706 let mut cx = cx.clone();
707 async move {
708 this.update(&mut cx, |this, _| {
709 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
710 && let lsp::NumberOrString::String(token) = params.token
711 {
712 status.progress_tokens.insert(token);
713 }
714 })?;
715
716 Ok(())
717 }
718 }
719 })
720 .detach();
721
722 language_server
723 .on_request::<lsp::request::RegisterCapability, _, _>({
724 let lsp_store = lsp_store.clone();
725 move |params, cx| {
726 let lsp_store = lsp_store.clone();
727 let mut cx = cx.clone();
728 async move {
729 lsp_store
730 .update(&mut cx, |lsp_store, cx| {
731 if lsp_store.as_local().is_some() {
732 match lsp_store
733 .register_server_capabilities(server_id, params, cx)
734 {
735 Ok(()) => {}
736 Err(e) => {
737 log::error!(
738 "Failed to register server capabilities: {e:#}"
739 );
740 }
741 };
742 }
743 })
744 .ok();
745 Ok(())
746 }
747 }
748 })
749 .detach();
750
751 language_server
752 .on_request::<lsp::request::UnregisterCapability, _, _>({
753 let lsp_store = lsp_store.clone();
754 move |params, cx| {
755 let lsp_store = lsp_store.clone();
756 let mut cx = cx.clone();
757 async move {
758 lsp_store
759 .update(&mut cx, |lsp_store, cx| {
760 if lsp_store.as_local().is_some() {
761 match lsp_store
762 .unregister_server_capabilities(server_id, params, cx)
763 {
764 Ok(()) => {}
765 Err(e) => {
766 log::error!(
767 "Failed to unregister server capabilities: {e:#}"
768 );
769 }
770 }
771 }
772 })
773 .ok();
774 Ok(())
775 }
776 }
777 })
778 .detach();
779
780 language_server
781 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
782 let this = lsp_store.clone();
783 move |params, cx| {
784 let mut cx = cx.clone();
785 let this = this.clone();
786 async move {
787 LocalLspStore::on_lsp_workspace_edit(
788 this.clone(),
789 params,
790 server_id,
791 &mut cx,
792 )
793 .await
794 }
795 }
796 })
797 .detach();
798
799 language_server
800 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
801 let lsp_store = lsp_store.clone();
802 move |(), cx| {
803 let this = lsp_store.clone();
804 let mut cx = cx.clone();
805 async move {
806 this.update(&mut cx, |lsp_store, cx| {
807 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
808 lsp_store
809 .downstream_client
810 .as_ref()
811 .map(|(client, project_id)| {
812 client.send(proto::RefreshInlayHints {
813 project_id: *project_id,
814 server_id: server_id.to_proto(),
815 })
816 })
817 })?
818 .transpose()?;
819 Ok(())
820 }
821 }
822 })
823 .detach();
824
825 language_server
826 .on_request::<lsp::request::CodeLensRefresh, _, _>({
827 let this = lsp_store.clone();
828 move |(), cx| {
829 let this = this.clone();
830 let mut cx = cx.clone();
831 async move {
832 this.update(&mut cx, |this, cx| {
833 cx.emit(LspStoreEvent::RefreshCodeLens);
834 this.downstream_client.as_ref().map(|(client, project_id)| {
835 client.send(proto::RefreshCodeLens {
836 project_id: *project_id,
837 })
838 })
839 })?
840 .transpose()?;
841 Ok(())
842 }
843 }
844 })
845 .detach();
846
847 language_server
848 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
849 let this = lsp_store.clone();
850 move |(), cx| {
851 let this = this.clone();
852 let mut cx = cx.clone();
853 async move {
854 this.update(&mut cx, |lsp_store, _| {
855 lsp_store.pull_workspace_diagnostics(server_id);
856 lsp_store
857 .downstream_client
858 .as_ref()
859 .map(|(client, project_id)| {
860 client.send(proto::PullWorkspaceDiagnostics {
861 project_id: *project_id,
862 server_id: server_id.to_proto(),
863 })
864 })
865 })?
866 .transpose()?;
867 Ok(())
868 }
869 }
870 })
871 .detach();
872
873 language_server
874 .on_request::<lsp::request::ShowMessageRequest, _, _>({
875 let this = lsp_store.clone();
876 let name = name.to_string();
877 move |params, cx| {
878 let this = this.clone();
879 let name = name.to_string();
880 let mut cx = cx.clone();
881 async move {
882 let actions = params.actions.unwrap_or_default();
883 let (tx, rx) = smol::channel::bounded(1);
884 let request = LanguageServerPromptRequest {
885 level: match params.typ {
886 lsp::MessageType::ERROR => PromptLevel::Critical,
887 lsp::MessageType::WARNING => PromptLevel::Warning,
888 _ => PromptLevel::Info,
889 },
890 message: params.message,
891 actions,
892 response_channel: tx,
893 lsp_name: name.clone(),
894 };
895
896 let did_update = this
897 .update(&mut cx, |_, cx| {
898 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
899 })
900 .is_ok();
901 if did_update {
902 let response = rx.recv().await.ok();
903 Ok(response)
904 } else {
905 Ok(None)
906 }
907 }
908 }
909 })
910 .detach();
911 language_server
912 .on_notification::<lsp::notification::ShowMessage, _>({
913 let this = lsp_store.clone();
914 let name = name.to_string();
915 move |params, cx| {
916 let this = this.clone();
917 let name = name.to_string();
918 let mut cx = cx.clone();
919
920 let (tx, _) = smol::channel::bounded(1);
921 let request = LanguageServerPromptRequest {
922 level: match params.typ {
923 lsp::MessageType::ERROR => PromptLevel::Critical,
924 lsp::MessageType::WARNING => PromptLevel::Warning,
925 _ => PromptLevel::Info,
926 },
927 message: params.message,
928 actions: vec![],
929 response_channel: tx,
930 lsp_name: name,
931 };
932
933 let _ = this.update(&mut cx, |_, cx| {
934 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
935 });
936 }
937 })
938 .detach();
939
940 let disk_based_diagnostics_progress_token =
941 adapter.disk_based_diagnostics_progress_token.clone();
942
943 language_server
944 .on_notification::<lsp::notification::Progress, _>({
945 let this = lsp_store.clone();
946 move |params, cx| {
947 if let Some(this) = this.upgrade() {
948 this.update(cx, |this, cx| {
949 this.on_lsp_progress(
950 params,
951 server_id,
952 disk_based_diagnostics_progress_token.clone(),
953 cx,
954 );
955 })
956 .ok();
957 }
958 }
959 })
960 .detach();
961
962 language_server
963 .on_notification::<lsp::notification::LogMessage, _>({
964 let this = lsp_store.clone();
965 move |params, cx| {
966 if let Some(this) = this.upgrade() {
967 this.update(cx, |_, cx| {
968 cx.emit(LspStoreEvent::LanguageServerLog(
969 server_id,
970 LanguageServerLogType::Log(params.typ),
971 params.message,
972 ));
973 })
974 .ok();
975 }
976 }
977 })
978 .detach();
979
980 language_server
981 .on_notification::<lsp::notification::LogTrace, _>({
982 let this = lsp_store.clone();
983 move |params, cx| {
984 let mut cx = cx.clone();
985 if let Some(this) = this.upgrade() {
986 this.update(&mut cx, |_, cx| {
987 cx.emit(LspStoreEvent::LanguageServerLog(
988 server_id,
989 LanguageServerLogType::Trace {
990 verbose_info: params.verbose,
991 },
992 params.message,
993 ));
994 })
995 .ok();
996 }
997 }
998 })
999 .detach();
1000
1001 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1002 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1003 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1004 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1005 }
1006
1007 fn shutdown_language_servers_on_quit(
1008 &mut self,
1009 _: &mut Context<LspStore>,
1010 ) -> impl Future<Output = ()> + use<> {
1011 let shutdown_futures = self
1012 .language_servers
1013 .drain()
1014 .map(|(_, server_state)| Self::shutdown_server(server_state))
1015 .collect::<Vec<_>>();
1016
1017 async move {
1018 join_all(shutdown_futures).await;
1019 }
1020 }
1021
1022 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1023 match server_state {
1024 LanguageServerState::Running { server, .. } => {
1025 if let Some(shutdown) = server.shutdown() {
1026 shutdown.await;
1027 }
1028 }
1029 LanguageServerState::Starting { startup, .. } => {
1030 if let Some(server) = startup.await
1031 && let Some(shutdown) = server.shutdown()
1032 {
1033 shutdown.await;
1034 }
1035 }
1036 }
1037 Ok(())
1038 }
1039
1040 fn language_servers_for_worktree(
1041 &self,
1042 worktree_id: WorktreeId,
1043 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1044 self.language_server_ids
1045 .iter()
1046 .filter_map(move |(seed, state)| {
1047 if seed.worktree_id != worktree_id {
1048 return None;
1049 }
1050
1051 if let Some(LanguageServerState::Running { server, .. }) =
1052 self.language_servers.get(&state.id)
1053 {
1054 Some(server)
1055 } else {
1056 None
1057 }
1058 })
1059 }
1060
1061 fn language_server_ids_for_project_path(
1062 &self,
1063 project_path: ProjectPath,
1064 language: &Language,
1065 cx: &mut App,
1066 ) -> Vec<LanguageServerId> {
1067 let Some(worktree) = self
1068 .worktree_store
1069 .read(cx)
1070 .worktree_for_id(project_path.worktree_id, cx)
1071 else {
1072 return Vec::new();
1073 };
1074 let delegate: Arc<dyn ManifestDelegate> =
1075 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1076
1077 self.lsp_tree
1078 .get(
1079 project_path,
1080 language.name(),
1081 language.manifest(),
1082 &delegate,
1083 cx,
1084 )
1085 .collect::<Vec<_>>()
1086 }
1087
1088 fn language_server_ids_for_buffer(
1089 &self,
1090 buffer: &Buffer,
1091 cx: &mut App,
1092 ) -> Vec<LanguageServerId> {
1093 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1094 let worktree_id = file.worktree_id(cx);
1095
1096 let path: Arc<RelPath> = file
1097 .path()
1098 .parent()
1099 .map(Arc::from)
1100 .unwrap_or_else(|| file.path().clone());
1101 let worktree_path = ProjectPath { worktree_id, path };
1102 self.language_server_ids_for_project_path(worktree_path, language, cx)
1103 } else {
1104 Vec::new()
1105 }
1106 }
1107
1108 fn language_servers_for_buffer<'a>(
1109 &'a self,
1110 buffer: &'a Buffer,
1111 cx: &'a mut App,
1112 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1113 self.language_server_ids_for_buffer(buffer, cx)
1114 .into_iter()
1115 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1116 LanguageServerState::Running {
1117 adapter, server, ..
1118 } => Some((adapter, server)),
1119 _ => None,
1120 })
1121 }
1122
1123 async fn execute_code_action_kind_locally(
1124 lsp_store: WeakEntity<LspStore>,
1125 mut buffers: Vec<Entity<Buffer>>,
1126 kind: CodeActionKind,
1127 push_to_history: bool,
1128 cx: &mut AsyncApp,
1129 ) -> anyhow::Result<ProjectTransaction> {
1130 // Do not allow multiple concurrent code actions requests for the
1131 // same buffer.
1132 lsp_store.update(cx, |this, cx| {
1133 let this = this.as_local_mut().unwrap();
1134 buffers.retain(|buffer| {
1135 this.buffers_being_formatted
1136 .insert(buffer.read(cx).remote_id())
1137 });
1138 })?;
1139 let _cleanup = defer({
1140 let this = lsp_store.clone();
1141 let mut cx = cx.clone();
1142 let buffers = &buffers;
1143 move || {
1144 this.update(&mut cx, |this, cx| {
1145 let this = this.as_local_mut().unwrap();
1146 for buffer in buffers {
1147 this.buffers_being_formatted
1148 .remove(&buffer.read(cx).remote_id());
1149 }
1150 })
1151 .ok();
1152 }
1153 });
1154 let mut project_transaction = ProjectTransaction::default();
1155
1156 for buffer in &buffers {
1157 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1158 buffer.update(cx, |buffer, cx| {
1159 lsp_store
1160 .as_local()
1161 .unwrap()
1162 .language_servers_for_buffer(buffer, cx)
1163 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1164 .collect::<Vec<_>>()
1165 })
1166 })?;
1167 for (_, language_server) in adapters_and_servers.iter() {
1168 let actions = Self::get_server_code_actions_from_action_kinds(
1169 &lsp_store,
1170 language_server.server_id(),
1171 vec![kind.clone()],
1172 buffer,
1173 cx,
1174 )
1175 .await?;
1176 Self::execute_code_actions_on_server(
1177 &lsp_store,
1178 language_server,
1179 actions,
1180 push_to_history,
1181 &mut project_transaction,
1182 cx,
1183 )
1184 .await?;
1185 }
1186 }
1187 Ok(project_transaction)
1188 }
1189
1190 async fn format_locally(
1191 lsp_store: WeakEntity<LspStore>,
1192 mut buffers: Vec<FormattableBuffer>,
1193 push_to_history: bool,
1194 trigger: FormatTrigger,
1195 logger: zlog::Logger,
1196 cx: &mut AsyncApp,
1197 ) -> anyhow::Result<ProjectTransaction> {
1198 // Do not allow multiple concurrent formatting requests for the
1199 // same buffer.
1200 lsp_store.update(cx, |this, cx| {
1201 let this = this.as_local_mut().unwrap();
1202 buffers.retain(|buffer| {
1203 this.buffers_being_formatted
1204 .insert(buffer.handle.read(cx).remote_id())
1205 });
1206 })?;
1207
1208 let _cleanup = defer({
1209 let this = lsp_store.clone();
1210 let mut cx = cx.clone();
1211 let buffers = &buffers;
1212 move || {
1213 this.update(&mut cx, |this, cx| {
1214 let this = this.as_local_mut().unwrap();
1215 for buffer in buffers {
1216 this.buffers_being_formatted
1217 .remove(&buffer.handle.read(cx).remote_id());
1218 }
1219 })
1220 .ok();
1221 }
1222 });
1223
1224 let mut project_transaction = ProjectTransaction::default();
1225
1226 for buffer in &buffers {
1227 zlog::debug!(
1228 logger =>
1229 "formatting buffer '{:?}'",
1230 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1231 );
1232 // Create an empty transaction to hold all of the formatting edits.
1233 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1234 // ensure no transactions created while formatting are
1235 // grouped with the previous transaction in the history
1236 // based on the transaction group interval
1237 buffer.finalize_last_transaction();
1238 buffer
1239 .start_transaction()
1240 .context("transaction already open")?;
1241 buffer.end_transaction(cx);
1242 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1243 buffer.finalize_last_transaction();
1244 anyhow::Ok(transaction_id)
1245 })??;
1246
1247 let result = Self::format_buffer_locally(
1248 lsp_store.clone(),
1249 buffer,
1250 formatting_transaction_id,
1251 trigger,
1252 logger,
1253 cx,
1254 )
1255 .await;
1256
1257 buffer.handle.update(cx, |buffer, cx| {
1258 let Some(formatting_transaction) =
1259 buffer.get_transaction(formatting_transaction_id).cloned()
1260 else {
1261 zlog::warn!(logger => "no formatting transaction");
1262 return;
1263 };
1264 if formatting_transaction.edit_ids.is_empty() {
1265 zlog::debug!(logger => "no changes made while formatting");
1266 buffer.forget_transaction(formatting_transaction_id);
1267 return;
1268 }
1269 if !push_to_history {
1270 zlog::trace!(logger => "forgetting format transaction");
1271 buffer.forget_transaction(formatting_transaction.id);
1272 }
1273 project_transaction
1274 .0
1275 .insert(cx.entity(), formatting_transaction);
1276 })?;
1277
1278 result?;
1279 }
1280
1281 Ok(project_transaction)
1282 }
1283
1284 async fn format_buffer_locally(
1285 lsp_store: WeakEntity<LspStore>,
1286 buffer: &FormattableBuffer,
1287 formatting_transaction_id: clock::Lamport,
1288 trigger: FormatTrigger,
1289 logger: zlog::Logger,
1290 cx: &mut AsyncApp,
1291 ) -> Result<()> {
1292 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1293 buffer.handle.update(cx, |buffer, cx| {
1294 let adapters_and_servers = lsp_store
1295 .as_local()
1296 .unwrap()
1297 .language_servers_for_buffer(buffer, cx)
1298 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1299 .collect::<Vec<_>>();
1300 let settings =
1301 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1302 .into_owned();
1303 (adapters_and_servers, settings)
1304 })
1305 })?;
1306
1307 /// Apply edits to the buffer that will become part of the formatting transaction.
1308 /// Fails if the buffer has been edited since the start of that transaction.
1309 fn extend_formatting_transaction(
1310 buffer: &FormattableBuffer,
1311 formatting_transaction_id: text::TransactionId,
1312 cx: &mut AsyncApp,
1313 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1314 ) -> anyhow::Result<()> {
1315 buffer.handle.update(cx, |buffer, cx| {
1316 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1317 if last_transaction_id != Some(formatting_transaction_id) {
1318 anyhow::bail!("Buffer edited while formatting. Aborting")
1319 }
1320 buffer.start_transaction();
1321 operation(buffer, cx);
1322 if let Some(transaction_id) = buffer.end_transaction(cx) {
1323 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1324 }
1325 Ok(())
1326 })?
1327 }
1328
1329 // handle whitespace formatting
1330 if settings.remove_trailing_whitespace_on_save {
1331 zlog::trace!(logger => "removing trailing whitespace");
1332 let diff = buffer
1333 .handle
1334 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1335 .await;
1336 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1337 buffer.apply_diff(diff, cx);
1338 })?;
1339 }
1340
1341 if settings.ensure_final_newline_on_save {
1342 zlog::trace!(logger => "ensuring final newline");
1343 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1344 buffer.ensure_final_newline(cx);
1345 })?;
1346 }
1347
1348 // Formatter for `code_actions_on_format` that runs before
1349 // the rest of the formatters
1350 let mut code_actions_on_format_formatters = None;
1351 let should_run_code_actions_on_format = !matches!(
1352 (trigger, &settings.format_on_save),
1353 (FormatTrigger::Save, &FormatOnSave::Off)
1354 );
1355 if should_run_code_actions_on_format {
1356 let have_code_actions_to_run_on_format = settings
1357 .code_actions_on_format
1358 .values()
1359 .any(|enabled| *enabled);
1360 if have_code_actions_to_run_on_format {
1361 zlog::trace!(logger => "going to run code actions on format");
1362 code_actions_on_format_formatters = Some(
1363 settings
1364 .code_actions_on_format
1365 .iter()
1366 .filter_map(|(action, enabled)| enabled.then_some(action))
1367 .cloned()
1368 .map(Formatter::CodeAction)
1369 .collect::<Vec<_>>(),
1370 );
1371 }
1372 }
1373
1374 let formatters = match (trigger, &settings.format_on_save) {
1375 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1376 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1377 settings.formatter.as_ref()
1378 }
1379 };
1380
1381 let formatters = code_actions_on_format_formatters
1382 .iter()
1383 .flatten()
1384 .chain(formatters);
1385
1386 for formatter in formatters {
1387 let formatter = if formatter == &Formatter::Auto {
1388 if settings.prettier.allowed {
1389 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1390 &Formatter::Prettier
1391 } else {
1392 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1393 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1394 }
1395 } else {
1396 formatter
1397 };
1398 match formatter {
1399 Formatter::Auto => unreachable!("Auto resolved above"),
1400 Formatter::Prettier => {
1401 let logger = zlog::scoped!(logger => "prettier");
1402 zlog::trace!(logger => "formatting");
1403 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1404
1405 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1406 lsp_store.prettier_store().unwrap().downgrade()
1407 })?;
1408 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1409 .await
1410 .transpose()?;
1411 let Some(diff) = diff else {
1412 zlog::trace!(logger => "No changes");
1413 continue;
1414 };
1415
1416 extend_formatting_transaction(
1417 buffer,
1418 formatting_transaction_id,
1419 cx,
1420 |buffer, cx| {
1421 buffer.apply_diff(diff, cx);
1422 },
1423 )?;
1424 }
1425 Formatter::External { command, arguments } => {
1426 let logger = zlog::scoped!(logger => "command");
1427 zlog::trace!(logger => "formatting");
1428 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1429
1430 let diff = Self::format_via_external_command(
1431 buffer,
1432 command.as_ref(),
1433 arguments.as_deref(),
1434 cx,
1435 )
1436 .await
1437 .with_context(|| {
1438 format!("Failed to format buffer via external command: {}", command)
1439 })?;
1440 let Some(diff) = diff else {
1441 zlog::trace!(logger => "No changes");
1442 continue;
1443 };
1444
1445 extend_formatting_transaction(
1446 buffer,
1447 formatting_transaction_id,
1448 cx,
1449 |buffer, cx| {
1450 buffer.apply_diff(diff, cx);
1451 },
1452 )?;
1453 }
1454 Formatter::LanguageServer(specifier) => {
1455 let logger = zlog::scoped!(logger => "language-server");
1456 zlog::trace!(logger => "formatting");
1457 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1458
1459 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1460 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1461 continue;
1462 };
1463
1464 let language_server = match specifier {
1465 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1466 adapters_and_servers.iter().find_map(|(adapter, server)| {
1467 if adapter.name.0.as_ref() == name {
1468 Some(server.clone())
1469 } else {
1470 None
1471 }
1472 })
1473 }
1474 settings::LanguageServerFormatterSpecifier::Current => {
1475 adapters_and_servers.first().map(|e| e.1.clone())
1476 }
1477 };
1478
1479 let Some(language_server) = language_server else {
1480 log::debug!(
1481 "No language server found to format buffer '{:?}'. Skipping",
1482 buffer_path_abs.as_path().to_string_lossy()
1483 );
1484 continue;
1485 };
1486
1487 zlog::trace!(
1488 logger =>
1489 "Formatting buffer '{:?}' using language server '{:?}'",
1490 buffer_path_abs.as_path().to_string_lossy(),
1491 language_server.name()
1492 );
1493
1494 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1495 zlog::trace!(logger => "formatting ranges");
1496 Self::format_ranges_via_lsp(
1497 &lsp_store,
1498 &buffer.handle,
1499 ranges,
1500 buffer_path_abs,
1501 &language_server,
1502 &settings,
1503 cx,
1504 )
1505 .await
1506 .context("Failed to format ranges via language server")?
1507 } else {
1508 zlog::trace!(logger => "formatting full");
1509 Self::format_via_lsp(
1510 &lsp_store,
1511 &buffer.handle,
1512 buffer_path_abs,
1513 &language_server,
1514 &settings,
1515 cx,
1516 )
1517 .await
1518 .context("failed to format via language server")?
1519 };
1520
1521 if edits.is_empty() {
1522 zlog::trace!(logger => "No changes");
1523 continue;
1524 }
1525 extend_formatting_transaction(
1526 buffer,
1527 formatting_transaction_id,
1528 cx,
1529 |buffer, cx| {
1530 buffer.edit(edits, None, cx);
1531 },
1532 )?;
1533 }
1534 Formatter::CodeAction(code_action_name) => {
1535 let logger = zlog::scoped!(logger => "code-actions");
1536 zlog::trace!(logger => "formatting");
1537 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1538
1539 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1540 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1541 continue;
1542 };
1543
1544 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1545 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1546
1547 let mut actions_and_servers = Vec::new();
1548
1549 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1550 let actions_result = Self::get_server_code_actions_from_action_kinds(
1551 &lsp_store,
1552 language_server.server_id(),
1553 vec![code_action_kind.clone()],
1554 &buffer.handle,
1555 cx,
1556 )
1557 .await
1558 .with_context(|| {
1559 format!(
1560 "Failed to resolve code action {:?} with language server {}",
1561 code_action_kind,
1562 language_server.name()
1563 )
1564 });
1565 let Ok(actions) = actions_result else {
1566 // note: it may be better to set result to the error and break formatters here
1567 // but for now we try to execute the actions that we can resolve and skip the rest
1568 zlog::error!(
1569 logger =>
1570 "Failed to resolve code action {:?} with language server {}",
1571 code_action_kind,
1572 language_server.name()
1573 );
1574 continue;
1575 };
1576 for action in actions {
1577 actions_and_servers.push((action, index));
1578 }
1579 }
1580
1581 if actions_and_servers.is_empty() {
1582 zlog::warn!(logger => "No code actions were resolved, continuing");
1583 continue;
1584 }
1585
1586 'actions: for (mut action, server_index) in actions_and_servers {
1587 let server = &adapters_and_servers[server_index].1;
1588
1589 let describe_code_action = |action: &CodeAction| {
1590 format!(
1591 "code action '{}' with title \"{}\" on server {}",
1592 action
1593 .lsp_action
1594 .action_kind()
1595 .unwrap_or("unknown".into())
1596 .as_str(),
1597 action.lsp_action.title(),
1598 server.name(),
1599 )
1600 };
1601
1602 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1603
1604 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1605 zlog::error!(
1606 logger =>
1607 "Failed to resolve {}. Error: {}",
1608 describe_code_action(&action),
1609 err
1610 );
1611 continue;
1612 }
1613
1614 if let Some(edit) = action.lsp_action.edit().cloned() {
1615 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1616 // but filters out and logs warnings for code actions that require unreasonably
1617 // difficult handling on our part, such as:
1618 // - applying edits that call commands
1619 // which can result in arbitrary workspace edits being sent from the server that
1620 // have no way of being tied back to the command that initiated them (i.e. we
1621 // can't know which edits are part of the format request, or if the server is done sending
1622 // actions in response to the command)
1623 // - actions that create/delete/modify/rename files other than the one we are formatting
1624 // as we then would need to handle such changes correctly in the local history as well
1625 // as the remote history through the ProjectTransaction
1626 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1627 // Supporting these actions is not impossible, but not supported as of yet.
1628 if edit.changes.is_none() && edit.document_changes.is_none() {
1629 zlog::trace!(
1630 logger =>
1631 "No changes for code action. Skipping {}",
1632 describe_code_action(&action),
1633 );
1634 continue;
1635 }
1636
1637 let mut operations = Vec::new();
1638 if let Some(document_changes) = edit.document_changes {
1639 match document_changes {
1640 lsp::DocumentChanges::Edits(edits) => operations.extend(
1641 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1642 ),
1643 lsp::DocumentChanges::Operations(ops) => operations = ops,
1644 }
1645 } else if let Some(changes) = edit.changes {
1646 operations.extend(changes.into_iter().map(|(uri, edits)| {
1647 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1648 text_document:
1649 lsp::OptionalVersionedTextDocumentIdentifier {
1650 uri,
1651 version: None,
1652 },
1653 edits: edits.into_iter().map(Edit::Plain).collect(),
1654 })
1655 }));
1656 }
1657
1658 let mut edits = Vec::with_capacity(operations.len());
1659
1660 if operations.is_empty() {
1661 zlog::trace!(
1662 logger =>
1663 "No changes for code action. Skipping {}",
1664 describe_code_action(&action),
1665 );
1666 continue;
1667 }
1668 for operation in operations {
1669 let op = match operation {
1670 lsp::DocumentChangeOperation::Edit(op) => op,
1671 lsp::DocumentChangeOperation::Op(_) => {
1672 zlog::warn!(
1673 logger =>
1674 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1675 describe_code_action(&action),
1676 );
1677 continue 'actions;
1678 }
1679 };
1680 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1681 zlog::warn!(
1682 logger =>
1683 "Failed to convert URI '{:?}' to file path. Skipping {}",
1684 &op.text_document.uri,
1685 describe_code_action(&action),
1686 );
1687 continue 'actions;
1688 };
1689 if &file_path != buffer_path_abs {
1690 zlog::warn!(
1691 logger =>
1692 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1693 file_path,
1694 buffer_path_abs,
1695 describe_code_action(&action),
1696 );
1697 continue 'actions;
1698 }
1699
1700 let mut lsp_edits = Vec::new();
1701 for edit in op.edits {
1702 match edit {
1703 Edit::Plain(edit) => {
1704 if !lsp_edits.contains(&edit) {
1705 lsp_edits.push(edit);
1706 }
1707 }
1708 Edit::Annotated(edit) => {
1709 if !lsp_edits.contains(&edit.text_edit) {
1710 lsp_edits.push(edit.text_edit);
1711 }
1712 }
1713 Edit::Snippet(_) => {
1714 zlog::warn!(
1715 logger =>
1716 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1717 describe_code_action(&action),
1718 );
1719 continue 'actions;
1720 }
1721 }
1722 }
1723 let edits_result = lsp_store
1724 .update(cx, |lsp_store, cx| {
1725 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1726 &buffer.handle,
1727 lsp_edits,
1728 server.server_id(),
1729 op.text_document.version,
1730 cx,
1731 )
1732 })?
1733 .await;
1734 let Ok(resolved_edits) = edits_result else {
1735 zlog::warn!(
1736 logger =>
1737 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1738 buffer_path_abs.as_path(),
1739 describe_code_action(&action),
1740 );
1741 continue 'actions;
1742 };
1743 edits.extend(resolved_edits);
1744 }
1745
1746 if edits.is_empty() {
1747 zlog::warn!(logger => "No edits resolved from LSP");
1748 continue;
1749 }
1750
1751 extend_formatting_transaction(
1752 buffer,
1753 formatting_transaction_id,
1754 cx,
1755 |buffer, cx| {
1756 zlog::info!(
1757 "Applying edits {edits:?}. Content: {:?}",
1758 buffer.text()
1759 );
1760 buffer.edit(edits, None, cx);
1761 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1762 },
1763 )?;
1764 }
1765
1766 if let Some(command) = action.lsp_action.command() {
1767 zlog::warn!(
1768 logger =>
1769 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1770 &command.command,
1771 );
1772
1773 // bail early if command is invalid
1774 let server_capabilities = server.capabilities();
1775 let available_commands = server_capabilities
1776 .execute_command_provider
1777 .as_ref()
1778 .map(|options| options.commands.as_slice())
1779 .unwrap_or_default();
1780 if !available_commands.contains(&command.command) {
1781 zlog::warn!(
1782 logger =>
1783 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1784 command.command,
1785 server.name(),
1786 );
1787 continue;
1788 }
1789
1790 // noop so we just ensure buffer hasn't been edited since resolving code actions
1791 extend_formatting_transaction(
1792 buffer,
1793 formatting_transaction_id,
1794 cx,
1795 |_, _| {},
1796 )?;
1797 zlog::info!(logger => "Executing command {}", &command.command);
1798
1799 lsp_store.update(cx, |this, _| {
1800 this.as_local_mut()
1801 .unwrap()
1802 .last_workspace_edits_by_language_server
1803 .remove(&server.server_id());
1804 })?;
1805
1806 let execute_command_result = server
1807 .request::<lsp::request::ExecuteCommand>(
1808 lsp::ExecuteCommandParams {
1809 command: command.command.clone(),
1810 arguments: command.arguments.clone().unwrap_or_default(),
1811 ..Default::default()
1812 },
1813 )
1814 .await
1815 .into_response();
1816
1817 if execute_command_result.is_err() {
1818 zlog::error!(
1819 logger =>
1820 "Failed to execute command '{}' as part of {}",
1821 &command.command,
1822 describe_code_action(&action),
1823 );
1824 continue 'actions;
1825 }
1826
1827 let mut project_transaction_command =
1828 lsp_store.update(cx, |this, _| {
1829 this.as_local_mut()
1830 .unwrap()
1831 .last_workspace_edits_by_language_server
1832 .remove(&server.server_id())
1833 .unwrap_or_default()
1834 })?;
1835
1836 if let Some(transaction) =
1837 project_transaction_command.0.remove(&buffer.handle)
1838 {
1839 zlog::trace!(
1840 logger =>
1841 "Successfully captured {} edits that resulted from command {}",
1842 transaction.edit_ids.len(),
1843 &command.command,
1844 );
1845 let transaction_id_project_transaction = transaction.id;
1846 buffer.handle.update(cx, |buffer, _| {
1847 // it may have been removed from history if push_to_history was
1848 // false in deserialize_workspace_edit. If so push it so we
1849 // can merge it with the format transaction
1850 // and pop the combined transaction off the history stack
1851 // later if push_to_history is false
1852 if buffer.get_transaction(transaction.id).is_none() {
1853 buffer.push_transaction(transaction, Instant::now());
1854 }
1855 buffer.merge_transactions(
1856 transaction_id_project_transaction,
1857 formatting_transaction_id,
1858 );
1859 })?;
1860 }
1861
1862 if !project_transaction_command.0.is_empty() {
1863 let mut extra_buffers = String::new();
1864 for buffer in project_transaction_command.0.keys() {
1865 buffer
1866 .read_with(cx, |b, cx| {
1867 if let Some(path) = b.project_path(cx) {
1868 if !extra_buffers.is_empty() {
1869 extra_buffers.push_str(", ");
1870 }
1871 extra_buffers.push_str(path.path.as_unix_str());
1872 }
1873 })
1874 .ok();
1875 }
1876 zlog::warn!(
1877 logger =>
1878 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1879 &command.command,
1880 extra_buffers,
1881 );
1882 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1883 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1884 // add it so it's included, and merge it into the format transaction when its created later
1885 }
1886 }
1887 }
1888 }
1889 }
1890 }
1891
1892 Ok(())
1893 }
1894
1895 pub async fn format_ranges_via_lsp(
1896 this: &WeakEntity<LspStore>,
1897 buffer_handle: &Entity<Buffer>,
1898 ranges: &[Range<Anchor>],
1899 abs_path: &Path,
1900 language_server: &Arc<LanguageServer>,
1901 settings: &LanguageSettings,
1902 cx: &mut AsyncApp,
1903 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1904 let capabilities = &language_server.capabilities();
1905 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1906 if range_formatting_provider == Some(&OneOf::Left(false)) {
1907 anyhow::bail!(
1908 "{} language server does not support range formatting",
1909 language_server.name()
1910 );
1911 }
1912
1913 let uri = file_path_to_lsp_url(abs_path)?;
1914 let text_document = lsp::TextDocumentIdentifier::new(uri);
1915
1916 let lsp_edits = {
1917 let mut lsp_ranges = Vec::new();
1918 this.update(cx, |_this, cx| {
1919 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1920 // not have been sent to the language server. This seems like a fairly systemic
1921 // issue, though, the resolution probably is not specific to formatting.
1922 //
1923 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1924 // LSP.
1925 let snapshot = buffer_handle.read(cx).snapshot();
1926 for range in ranges {
1927 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1928 }
1929 anyhow::Ok(())
1930 })??;
1931
1932 let mut edits = None;
1933 for range in lsp_ranges {
1934 if let Some(mut edit) = language_server
1935 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1936 text_document: text_document.clone(),
1937 range,
1938 options: lsp_command::lsp_formatting_options(settings),
1939 work_done_progress_params: Default::default(),
1940 })
1941 .await
1942 .into_response()?
1943 {
1944 edits.get_or_insert_with(Vec::new).append(&mut edit);
1945 }
1946 }
1947 edits
1948 };
1949
1950 if let Some(lsp_edits) = lsp_edits {
1951 this.update(cx, |this, cx| {
1952 this.as_local_mut().unwrap().edits_from_lsp(
1953 buffer_handle,
1954 lsp_edits,
1955 language_server.server_id(),
1956 None,
1957 cx,
1958 )
1959 })?
1960 .await
1961 } else {
1962 Ok(Vec::with_capacity(0))
1963 }
1964 }
1965
1966 async fn format_via_lsp(
1967 this: &WeakEntity<LspStore>,
1968 buffer: &Entity<Buffer>,
1969 abs_path: &Path,
1970 language_server: &Arc<LanguageServer>,
1971 settings: &LanguageSettings,
1972 cx: &mut AsyncApp,
1973 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1974 let logger = zlog::scoped!("lsp_format");
1975 zlog::info!(logger => "Formatting via LSP");
1976
1977 let uri = file_path_to_lsp_url(abs_path)?;
1978 let text_document = lsp::TextDocumentIdentifier::new(uri);
1979 let capabilities = &language_server.capabilities();
1980
1981 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1982 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1983
1984 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1985 let _timer = zlog::time!(logger => "format-full");
1986 language_server
1987 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1988 text_document,
1989 options: lsp_command::lsp_formatting_options(settings),
1990 work_done_progress_params: Default::default(),
1991 })
1992 .await
1993 .into_response()?
1994 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1995 let _timer = zlog::time!(logger => "format-range");
1996 let buffer_start = lsp::Position::new(0, 0);
1997 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1998 language_server
1999 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2000 text_document: text_document.clone(),
2001 range: lsp::Range::new(buffer_start, buffer_end),
2002 options: lsp_command::lsp_formatting_options(settings),
2003 work_done_progress_params: Default::default(),
2004 })
2005 .await
2006 .into_response()?
2007 } else {
2008 None
2009 };
2010
2011 if let Some(lsp_edits) = lsp_edits {
2012 this.update(cx, |this, cx| {
2013 this.as_local_mut().unwrap().edits_from_lsp(
2014 buffer,
2015 lsp_edits,
2016 language_server.server_id(),
2017 None,
2018 cx,
2019 )
2020 })?
2021 .await
2022 } else {
2023 Ok(Vec::with_capacity(0))
2024 }
2025 }
2026
2027 async fn format_via_external_command(
2028 buffer: &FormattableBuffer,
2029 command: &str,
2030 arguments: Option<&[String]>,
2031 cx: &mut AsyncApp,
2032 ) -> Result<Option<Diff>> {
2033 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2034 let file = File::from_dyn(buffer.file())?;
2035 let worktree = file.worktree.read(cx);
2036 let mut worktree_path = worktree.abs_path().to_path_buf();
2037 if worktree.root_entry()?.is_file() {
2038 worktree_path.pop();
2039 }
2040 Some(worktree_path)
2041 })?;
2042
2043 let mut child = util::command::new_smol_command(command);
2044
2045 if let Some(buffer_env) = buffer.env.as_ref() {
2046 child.envs(buffer_env);
2047 }
2048
2049 if let Some(working_dir_path) = working_dir_path {
2050 child.current_dir(working_dir_path);
2051 }
2052
2053 if let Some(arguments) = arguments {
2054 child.args(arguments.iter().map(|arg| {
2055 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2056 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2057 } else {
2058 arg.replace("{buffer_path}", "Untitled")
2059 }
2060 }));
2061 }
2062
2063 let mut child = child
2064 .stdin(smol::process::Stdio::piped())
2065 .stdout(smol::process::Stdio::piped())
2066 .stderr(smol::process::Stdio::piped())
2067 .spawn()?;
2068
2069 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2070 let text = buffer
2071 .handle
2072 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2073 for chunk in text.chunks() {
2074 stdin.write_all(chunk.as_bytes()).await?;
2075 }
2076 stdin.flush().await?;
2077
2078 let output = child.output().await?;
2079 anyhow::ensure!(
2080 output.status.success(),
2081 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2082 output.status.code(),
2083 String::from_utf8_lossy(&output.stdout),
2084 String::from_utf8_lossy(&output.stderr),
2085 );
2086
2087 let stdout = String::from_utf8(output.stdout)?;
2088 Ok(Some(
2089 buffer
2090 .handle
2091 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2092 .await,
2093 ))
2094 }
2095
2096 async fn try_resolve_code_action(
2097 lang_server: &LanguageServer,
2098 action: &mut CodeAction,
2099 ) -> anyhow::Result<()> {
2100 match &mut action.lsp_action {
2101 LspAction::Action(lsp_action) => {
2102 if !action.resolved
2103 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2104 && lsp_action.data.is_some()
2105 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2106 {
2107 *lsp_action = Box::new(
2108 lang_server
2109 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2110 .await
2111 .into_response()?,
2112 );
2113 }
2114 }
2115 LspAction::CodeLens(lens) => {
2116 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2117 *lens = lang_server
2118 .request::<lsp::request::CodeLensResolve>(lens.clone())
2119 .await
2120 .into_response()?;
2121 }
2122 }
2123 LspAction::Command(_) => {}
2124 }
2125
2126 action.resolved = true;
2127 anyhow::Ok(())
2128 }
2129
2130 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2131 let buffer = buffer_handle.read(cx);
2132
2133 let file = buffer.file().cloned();
2134
2135 let Some(file) = File::from_dyn(file.as_ref()) else {
2136 return;
2137 };
2138 if !file.is_local() {
2139 return;
2140 }
2141 let path = ProjectPath::from_file(file, cx);
2142 let worktree_id = file.worktree_id(cx);
2143 let language = buffer.language().cloned();
2144
2145 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2146 for (server_id, diagnostics) in
2147 diagnostics.get(file.path()).cloned().unwrap_or_default()
2148 {
2149 self.update_buffer_diagnostics(
2150 buffer_handle,
2151 server_id,
2152 None,
2153 None,
2154 diagnostics,
2155 Vec::new(),
2156 cx,
2157 )
2158 .log_err();
2159 }
2160 }
2161 let Some(language) = language else {
2162 return;
2163 };
2164 let Some(snapshot) = self
2165 .worktree_store
2166 .read(cx)
2167 .worktree_for_id(worktree_id, cx)
2168 .map(|worktree| worktree.read(cx).snapshot())
2169 else {
2170 return;
2171 };
2172 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2173
2174 for server_id in
2175 self.lsp_tree
2176 .get(path, language.name(), language.manifest(), &delegate, cx)
2177 {
2178 let server = self
2179 .language_servers
2180 .get(&server_id)
2181 .and_then(|server_state| {
2182 if let LanguageServerState::Running { server, .. } = server_state {
2183 Some(server.clone())
2184 } else {
2185 None
2186 }
2187 });
2188 let server = match server {
2189 Some(server) => server,
2190 None => continue,
2191 };
2192
2193 buffer_handle.update(cx, |buffer, cx| {
2194 buffer.set_completion_triggers(
2195 server.server_id(),
2196 server
2197 .capabilities()
2198 .completion_provider
2199 .as_ref()
2200 .and_then(|provider| {
2201 provider
2202 .trigger_characters
2203 .as_ref()
2204 .map(|characters| characters.iter().cloned().collect())
2205 })
2206 .unwrap_or_default(),
2207 cx,
2208 );
2209 });
2210 }
2211 }
2212
2213 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2214 buffer.update(cx, |buffer, cx| {
2215 let Some(language) = buffer.language() else {
2216 return;
2217 };
2218 let path = ProjectPath {
2219 worktree_id: old_file.worktree_id(cx),
2220 path: old_file.path.clone(),
2221 };
2222 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2223 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2224 buffer.set_completion_triggers(server_id, Default::default(), cx);
2225 }
2226 });
2227 }
2228
2229 fn update_buffer_diagnostics(
2230 &mut self,
2231 buffer: &Entity<Buffer>,
2232 server_id: LanguageServerId,
2233 result_id: Option<String>,
2234 version: Option<i32>,
2235 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2236 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2237 cx: &mut Context<LspStore>,
2238 ) -> Result<()> {
2239 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2240 Ordering::Equal
2241 .then_with(|| b.is_primary.cmp(&a.is_primary))
2242 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2243 .then_with(|| a.severity.cmp(&b.severity))
2244 .then_with(|| a.message.cmp(&b.message))
2245 }
2246
2247 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2248 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2249 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2250
2251 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2252 Ordering::Equal
2253 .then_with(|| a.range.start.cmp(&b.range.start))
2254 .then_with(|| b.range.end.cmp(&a.range.end))
2255 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2256 });
2257
2258 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2259
2260 let edits_since_save = std::cell::LazyCell::new(|| {
2261 let saved_version = buffer.read(cx).saved_version();
2262 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2263 });
2264
2265 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2266
2267 for (new_diagnostic, entry) in diagnostics {
2268 let start;
2269 let end;
2270 if new_diagnostic && entry.diagnostic.is_disk_based {
2271 // Some diagnostics are based on files on disk instead of buffers'
2272 // current contents. Adjust these diagnostics' ranges to reflect
2273 // any unsaved edits.
2274 // Do not alter the reused ones though, as their coordinates were stored as anchors
2275 // and were properly adjusted on reuse.
2276 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2277 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2278 } else {
2279 start = entry.range.start;
2280 end = entry.range.end;
2281 }
2282
2283 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2284 ..snapshot.clip_point_utf16(end, Bias::Right);
2285
2286 // Expand empty ranges by one codepoint
2287 if range.start == range.end {
2288 // This will be go to the next boundary when being clipped
2289 range.end.column += 1;
2290 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2291 if range.start == range.end && range.end.column > 0 {
2292 range.start.column -= 1;
2293 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2294 }
2295 }
2296
2297 sanitized_diagnostics.push(DiagnosticEntry {
2298 range,
2299 diagnostic: entry.diagnostic,
2300 });
2301 }
2302 drop(edits_since_save);
2303
2304 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2305 buffer.update(cx, |buffer, cx| {
2306 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2307 self.buffer_pull_diagnostics_result_ids
2308 .entry(server_id)
2309 .or_default()
2310 .insert(abs_path, result_id);
2311 }
2312
2313 buffer.update_diagnostics(server_id, set, cx)
2314 });
2315
2316 Ok(())
2317 }
2318
2319 fn register_language_server_for_invisible_worktree(
2320 &mut self,
2321 worktree: &Entity<Worktree>,
2322 language_server_id: LanguageServerId,
2323 cx: &mut App,
2324 ) {
2325 let worktree = worktree.read(cx);
2326 let worktree_id = worktree.id();
2327 debug_assert!(!worktree.is_visible());
2328 let Some(mut origin_seed) = self
2329 .language_server_ids
2330 .iter()
2331 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2332 else {
2333 return;
2334 };
2335 origin_seed.worktree_id = worktree_id;
2336 self.language_server_ids
2337 .entry(origin_seed)
2338 .or_insert_with(|| UnifiedLanguageServer {
2339 id: language_server_id,
2340 project_roots: Default::default(),
2341 });
2342 }
2343
2344 fn register_buffer_with_language_servers(
2345 &mut self,
2346 buffer_handle: &Entity<Buffer>,
2347 only_register_servers: HashSet<LanguageServerSelector>,
2348 cx: &mut Context<LspStore>,
2349 ) {
2350 let buffer = buffer_handle.read(cx);
2351 let buffer_id = buffer.remote_id();
2352
2353 let Some(file) = File::from_dyn(buffer.file()) else {
2354 return;
2355 };
2356 if !file.is_local() {
2357 return;
2358 }
2359
2360 let abs_path = file.abs_path(cx);
2361 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2362 return;
2363 };
2364 let initial_snapshot = buffer.text_snapshot();
2365 let worktree_id = file.worktree_id(cx);
2366
2367 let Some(language) = buffer.language().cloned() else {
2368 return;
2369 };
2370 let path: Arc<RelPath> = file
2371 .path()
2372 .parent()
2373 .map(Arc::from)
2374 .unwrap_or_else(|| file.path().clone());
2375 let Some(worktree) = self
2376 .worktree_store
2377 .read(cx)
2378 .worktree_for_id(worktree_id, cx)
2379 else {
2380 return;
2381 };
2382 let language_name = language.name();
2383 let (reused, delegate, servers) = self
2384 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2385 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2386 .unwrap_or_else(|| {
2387 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2388 let delegate: Arc<dyn ManifestDelegate> =
2389 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2390
2391 let servers = self
2392 .lsp_tree
2393 .walk(
2394 ProjectPath { worktree_id, path },
2395 language.name(),
2396 language.manifest(),
2397 &delegate,
2398 cx,
2399 )
2400 .collect::<Vec<_>>();
2401 (false, lsp_delegate, servers)
2402 });
2403 let servers_and_adapters = servers
2404 .into_iter()
2405 .filter_map(|server_node| {
2406 if reused && server_node.server_id().is_none() {
2407 return None;
2408 }
2409 if !only_register_servers.is_empty() {
2410 if let Some(server_id) = server_node.server_id()
2411 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2412 {
2413 return None;
2414 }
2415 if let Some(name) = server_node.name()
2416 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2417 {
2418 return None;
2419 }
2420 }
2421
2422 let server_id = server_node.server_id_or_init(|disposition| {
2423 let path = &disposition.path;
2424
2425 {
2426 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2427
2428 let server_id = self.get_or_insert_language_server(
2429 &worktree,
2430 delegate.clone(),
2431 disposition,
2432 &language_name,
2433 cx,
2434 );
2435
2436 if let Some(state) = self.language_servers.get(&server_id)
2437 && let Ok(uri) = uri
2438 {
2439 state.add_workspace_folder(uri);
2440 };
2441 server_id
2442 }
2443 })?;
2444 let server_state = self.language_servers.get(&server_id)?;
2445 if let LanguageServerState::Running {
2446 server, adapter, ..
2447 } = server_state
2448 {
2449 Some((server.clone(), adapter.clone()))
2450 } else {
2451 None
2452 }
2453 })
2454 .collect::<Vec<_>>();
2455 for (server, adapter) in servers_and_adapters {
2456 buffer_handle.update(cx, |buffer, cx| {
2457 buffer.set_completion_triggers(
2458 server.server_id(),
2459 server
2460 .capabilities()
2461 .completion_provider
2462 .as_ref()
2463 .and_then(|provider| {
2464 provider
2465 .trigger_characters
2466 .as_ref()
2467 .map(|characters| characters.iter().cloned().collect())
2468 })
2469 .unwrap_or_default(),
2470 cx,
2471 );
2472 });
2473
2474 let snapshot = LspBufferSnapshot {
2475 version: 0,
2476 snapshot: initial_snapshot.clone(),
2477 };
2478
2479 let mut registered = false;
2480 self.buffer_snapshots
2481 .entry(buffer_id)
2482 .or_default()
2483 .entry(server.server_id())
2484 .or_insert_with(|| {
2485 registered = true;
2486 server.register_buffer(
2487 uri.clone(),
2488 adapter.language_id(&language.name()),
2489 0,
2490 initial_snapshot.text_with_original_line_endings(),
2491 );
2492
2493 vec![snapshot]
2494 });
2495
2496 self.buffers_opened_in_servers
2497 .entry(buffer_id)
2498 .or_default()
2499 .insert(server.server_id());
2500 if registered {
2501 cx.emit(LspStoreEvent::LanguageServerUpdate {
2502 language_server_id: server.server_id(),
2503 name: None,
2504 message: proto::update_language_server::Variant::RegisteredForBuffer(
2505 proto::RegisteredForBuffer {
2506 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2507 buffer_id: buffer_id.to_proto(),
2508 },
2509 ),
2510 });
2511 }
2512 }
2513 }
2514
2515 fn reuse_existing_language_server<'lang_name>(
2516 &self,
2517 server_tree: &LanguageServerTree,
2518 worktree: &Entity<Worktree>,
2519 language_name: &'lang_name LanguageName,
2520 cx: &mut App,
2521 ) -> Option<(
2522 Arc<LocalLspAdapterDelegate>,
2523 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2524 )> {
2525 if worktree.read(cx).is_visible() {
2526 return None;
2527 }
2528
2529 let worktree_store = self.worktree_store.read(cx);
2530 let servers = server_tree
2531 .instances
2532 .iter()
2533 .filter(|(worktree_id, _)| {
2534 worktree_store
2535 .worktree_for_id(**worktree_id, cx)
2536 .is_some_and(|worktree| worktree.read(cx).is_visible())
2537 })
2538 .flat_map(|(worktree_id, servers)| {
2539 servers
2540 .roots
2541 .iter()
2542 .flat_map(|(_, language_servers)| language_servers)
2543 .map(move |(_, (server_node, server_languages))| {
2544 (worktree_id, server_node, server_languages)
2545 })
2546 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2547 .map(|(worktree_id, server_node, _)| {
2548 (
2549 *worktree_id,
2550 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2551 )
2552 })
2553 })
2554 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2555 acc.entry(worktree_id)
2556 .or_insert_with(Vec::new)
2557 .push(server_node);
2558 acc
2559 })
2560 .into_values()
2561 .max_by_key(|servers| servers.len())?;
2562
2563 let worktree_id = worktree.read(cx).id();
2564 let apply = move |tree: &mut LanguageServerTree| {
2565 for server_node in &servers {
2566 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2567 }
2568 servers
2569 };
2570
2571 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2572 Some((delegate, apply))
2573 }
2574
2575 pub(crate) fn unregister_old_buffer_from_language_servers(
2576 &mut self,
2577 buffer: &Entity<Buffer>,
2578 old_file: &File,
2579 cx: &mut App,
2580 ) {
2581 let old_path = match old_file.as_local() {
2582 Some(local) => local.abs_path(cx),
2583 None => return,
2584 };
2585
2586 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2587 debug_panic!("{old_path:?} is not parseable as an URI");
2588 return;
2589 };
2590 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2591 }
2592
2593 pub(crate) fn unregister_buffer_from_language_servers(
2594 &mut self,
2595 buffer: &Entity<Buffer>,
2596 file_url: &lsp::Uri,
2597 cx: &mut App,
2598 ) {
2599 buffer.update(cx, |buffer, cx| {
2600 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2601
2602 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2603 language_server.unregister_buffer(file_url.clone());
2604 }
2605 });
2606 }
2607
2608 fn buffer_snapshot_for_lsp_version(
2609 &mut self,
2610 buffer: &Entity<Buffer>,
2611 server_id: LanguageServerId,
2612 version: Option<i32>,
2613 cx: &App,
2614 ) -> Result<TextBufferSnapshot> {
2615 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2616
2617 if let Some(version) = version {
2618 let buffer_id = buffer.read(cx).remote_id();
2619 let snapshots = if let Some(snapshots) = self
2620 .buffer_snapshots
2621 .get_mut(&buffer_id)
2622 .and_then(|m| m.get_mut(&server_id))
2623 {
2624 snapshots
2625 } else if version == 0 {
2626 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2627 // We detect this case and treat it as if the version was `None`.
2628 return Ok(buffer.read(cx).text_snapshot());
2629 } else {
2630 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2631 };
2632
2633 let found_snapshot = snapshots
2634 .binary_search_by_key(&version, |e| e.version)
2635 .map(|ix| snapshots[ix].snapshot.clone())
2636 .map_err(|_| {
2637 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2638 })?;
2639
2640 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2641 Ok(found_snapshot)
2642 } else {
2643 Ok((buffer.read(cx)).text_snapshot())
2644 }
2645 }
2646
2647 async fn get_server_code_actions_from_action_kinds(
2648 lsp_store: &WeakEntity<LspStore>,
2649 language_server_id: LanguageServerId,
2650 code_action_kinds: Vec<lsp::CodeActionKind>,
2651 buffer: &Entity<Buffer>,
2652 cx: &mut AsyncApp,
2653 ) -> Result<Vec<CodeAction>> {
2654 let actions = lsp_store
2655 .update(cx, move |this, cx| {
2656 let request = GetCodeActions {
2657 range: text::Anchor::MIN..text::Anchor::MAX,
2658 kinds: Some(code_action_kinds),
2659 };
2660 let server = LanguageServerToQuery::Other(language_server_id);
2661 this.request_lsp(buffer.clone(), server, request, cx)
2662 })?
2663 .await?;
2664 Ok(actions)
2665 }
2666
2667 pub async fn execute_code_actions_on_server(
2668 lsp_store: &WeakEntity<LspStore>,
2669 language_server: &Arc<LanguageServer>,
2670
2671 actions: Vec<CodeAction>,
2672 push_to_history: bool,
2673 project_transaction: &mut ProjectTransaction,
2674 cx: &mut AsyncApp,
2675 ) -> anyhow::Result<()> {
2676 for mut action in actions {
2677 Self::try_resolve_code_action(language_server, &mut action)
2678 .await
2679 .context("resolving a formatting code action")?;
2680
2681 if let Some(edit) = action.lsp_action.edit() {
2682 if edit.changes.is_none() && edit.document_changes.is_none() {
2683 continue;
2684 }
2685
2686 let new = Self::deserialize_workspace_edit(
2687 lsp_store.upgrade().context("project dropped")?,
2688 edit.clone(),
2689 push_to_history,
2690 language_server.clone(),
2691 cx,
2692 )
2693 .await?;
2694 project_transaction.0.extend(new.0);
2695 }
2696
2697 if let Some(command) = action.lsp_action.command() {
2698 let server_capabilities = language_server.capabilities();
2699 let available_commands = server_capabilities
2700 .execute_command_provider
2701 .as_ref()
2702 .map(|options| options.commands.as_slice())
2703 .unwrap_or_default();
2704 if available_commands.contains(&command.command) {
2705 lsp_store.update(cx, |lsp_store, _| {
2706 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2707 mode.last_workspace_edits_by_language_server
2708 .remove(&language_server.server_id());
2709 }
2710 })?;
2711
2712 language_server
2713 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2714 command: command.command.clone(),
2715 arguments: command.arguments.clone().unwrap_or_default(),
2716 ..Default::default()
2717 })
2718 .await
2719 .into_response()
2720 .context("execute command")?;
2721
2722 lsp_store.update(cx, |this, _| {
2723 if let LspStoreMode::Local(mode) = &mut this.mode {
2724 project_transaction.0.extend(
2725 mode.last_workspace_edits_by_language_server
2726 .remove(&language_server.server_id())
2727 .unwrap_or_default()
2728 .0,
2729 )
2730 }
2731 })?;
2732 } else {
2733 log::warn!(
2734 "Cannot execute a command {} not listed in the language server capabilities",
2735 command.command
2736 )
2737 }
2738 }
2739 }
2740 Ok(())
2741 }
2742
2743 pub async fn deserialize_text_edits(
2744 this: Entity<LspStore>,
2745 buffer_to_edit: Entity<Buffer>,
2746 edits: Vec<lsp::TextEdit>,
2747 push_to_history: bool,
2748 _: Arc<CachedLspAdapter>,
2749 language_server: Arc<LanguageServer>,
2750 cx: &mut AsyncApp,
2751 ) -> Result<Option<Transaction>> {
2752 let edits = this
2753 .update(cx, |this, cx| {
2754 this.as_local_mut().unwrap().edits_from_lsp(
2755 &buffer_to_edit,
2756 edits,
2757 language_server.server_id(),
2758 None,
2759 cx,
2760 )
2761 })?
2762 .await?;
2763
2764 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2765 buffer.finalize_last_transaction();
2766 buffer.start_transaction();
2767 for (range, text) in edits {
2768 buffer.edit([(range, text)], None, cx);
2769 }
2770
2771 if buffer.end_transaction(cx).is_some() {
2772 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2773 if !push_to_history {
2774 buffer.forget_transaction(transaction.id);
2775 }
2776 Some(transaction)
2777 } else {
2778 None
2779 }
2780 })?;
2781
2782 Ok(transaction)
2783 }
2784
2785 #[allow(clippy::type_complexity)]
2786 pub(crate) fn edits_from_lsp(
2787 &mut self,
2788 buffer: &Entity<Buffer>,
2789 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2790 server_id: LanguageServerId,
2791 version: Option<i32>,
2792 cx: &mut Context<LspStore>,
2793 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2794 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2795 cx.background_spawn(async move {
2796 let snapshot = snapshot?;
2797 let mut lsp_edits = lsp_edits
2798 .into_iter()
2799 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2800 .collect::<Vec<_>>();
2801
2802 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2803
2804 let mut lsp_edits = lsp_edits.into_iter().peekable();
2805 let mut edits = Vec::new();
2806 while let Some((range, mut new_text)) = lsp_edits.next() {
2807 // Clip invalid ranges provided by the language server.
2808 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2809 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2810
2811 // Combine any LSP edits that are adjacent.
2812 //
2813 // Also, combine LSP edits that are separated from each other by only
2814 // a newline. This is important because for some code actions,
2815 // Rust-analyzer rewrites the entire buffer via a series of edits that
2816 // are separated by unchanged newline characters.
2817 //
2818 // In order for the diffing logic below to work properly, any edits that
2819 // cancel each other out must be combined into one.
2820 while let Some((next_range, next_text)) = lsp_edits.peek() {
2821 if next_range.start.0 > range.end {
2822 if next_range.start.0.row > range.end.row + 1
2823 || next_range.start.0.column > 0
2824 || snapshot.clip_point_utf16(
2825 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2826 Bias::Left,
2827 ) > range.end
2828 {
2829 break;
2830 }
2831 new_text.push('\n');
2832 }
2833 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2834 new_text.push_str(next_text);
2835 lsp_edits.next();
2836 }
2837
2838 // For multiline edits, perform a diff of the old and new text so that
2839 // we can identify the changes more precisely, preserving the locations
2840 // of any anchors positioned in the unchanged regions.
2841 if range.end.row > range.start.row {
2842 let offset = range.start.to_offset(&snapshot);
2843 let old_text = snapshot.text_for_range(range).collect::<String>();
2844 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2845 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2846 (
2847 snapshot.anchor_after(offset + range.start)
2848 ..snapshot.anchor_before(offset + range.end),
2849 replacement,
2850 )
2851 }));
2852 } else if range.end == range.start {
2853 let anchor = snapshot.anchor_after(range.start);
2854 edits.push((anchor..anchor, new_text.into()));
2855 } else {
2856 let edit_start = snapshot.anchor_after(range.start);
2857 let edit_end = snapshot.anchor_before(range.end);
2858 edits.push((edit_start..edit_end, new_text.into()));
2859 }
2860 }
2861
2862 Ok(edits)
2863 })
2864 }
2865
2866 pub(crate) async fn deserialize_workspace_edit(
2867 this: Entity<LspStore>,
2868 edit: lsp::WorkspaceEdit,
2869 push_to_history: bool,
2870 language_server: Arc<LanguageServer>,
2871 cx: &mut AsyncApp,
2872 ) -> Result<ProjectTransaction> {
2873 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2874
2875 let mut operations = Vec::new();
2876 if let Some(document_changes) = edit.document_changes {
2877 match document_changes {
2878 lsp::DocumentChanges::Edits(edits) => {
2879 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2880 }
2881 lsp::DocumentChanges::Operations(ops) => operations = ops,
2882 }
2883 } else if let Some(changes) = edit.changes {
2884 operations.extend(changes.into_iter().map(|(uri, edits)| {
2885 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2886 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2887 uri,
2888 version: None,
2889 },
2890 edits: edits.into_iter().map(Edit::Plain).collect(),
2891 })
2892 }));
2893 }
2894
2895 let mut project_transaction = ProjectTransaction::default();
2896 for operation in operations {
2897 match operation {
2898 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2899 let abs_path = op
2900 .uri
2901 .to_file_path()
2902 .map_err(|()| anyhow!("can't convert URI to path"))?;
2903
2904 if let Some(parent_path) = abs_path.parent() {
2905 fs.create_dir(parent_path).await?;
2906 }
2907 if abs_path.ends_with("/") {
2908 fs.create_dir(&abs_path).await?;
2909 } else {
2910 fs.create_file(
2911 &abs_path,
2912 op.options
2913 .map(|options| fs::CreateOptions {
2914 overwrite: options.overwrite.unwrap_or(false),
2915 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2916 })
2917 .unwrap_or_default(),
2918 )
2919 .await?;
2920 }
2921 }
2922
2923 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2924 let source_abs_path = op
2925 .old_uri
2926 .to_file_path()
2927 .map_err(|()| anyhow!("can't convert URI to path"))?;
2928 let target_abs_path = op
2929 .new_uri
2930 .to_file_path()
2931 .map_err(|()| anyhow!("can't convert URI to path"))?;
2932 fs.rename(
2933 &source_abs_path,
2934 &target_abs_path,
2935 op.options
2936 .map(|options| fs::RenameOptions {
2937 overwrite: options.overwrite.unwrap_or(false),
2938 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2939 })
2940 .unwrap_or_default(),
2941 )
2942 .await?;
2943 }
2944
2945 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2946 let abs_path = op
2947 .uri
2948 .to_file_path()
2949 .map_err(|()| anyhow!("can't convert URI to path"))?;
2950 let options = op
2951 .options
2952 .map(|options| fs::RemoveOptions {
2953 recursive: options.recursive.unwrap_or(false),
2954 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
2955 })
2956 .unwrap_or_default();
2957 if abs_path.ends_with("/") {
2958 fs.remove_dir(&abs_path, options).await?;
2959 } else {
2960 fs.remove_file(&abs_path, options).await?;
2961 }
2962 }
2963
2964 lsp::DocumentChangeOperation::Edit(op) => {
2965 let buffer_to_edit = this
2966 .update(cx, |this, cx| {
2967 this.open_local_buffer_via_lsp(
2968 op.text_document.uri.clone(),
2969 language_server.server_id(),
2970 cx,
2971 )
2972 })?
2973 .await?;
2974
2975 let edits = this
2976 .update(cx, |this, cx| {
2977 let path = buffer_to_edit.read(cx).project_path(cx);
2978 let active_entry = this.active_entry;
2979 let is_active_entry = path.is_some_and(|project_path| {
2980 this.worktree_store
2981 .read(cx)
2982 .entry_for_path(&project_path, cx)
2983 .is_some_and(|entry| Some(entry.id) == active_entry)
2984 });
2985 let local = this.as_local_mut().unwrap();
2986
2987 let (mut edits, mut snippet_edits) = (vec![], vec![]);
2988 for edit in op.edits {
2989 match edit {
2990 Edit::Plain(edit) => {
2991 if !edits.contains(&edit) {
2992 edits.push(edit)
2993 }
2994 }
2995 Edit::Annotated(edit) => {
2996 if !edits.contains(&edit.text_edit) {
2997 edits.push(edit.text_edit)
2998 }
2999 }
3000 Edit::Snippet(edit) => {
3001 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3002 else {
3003 continue;
3004 };
3005
3006 if is_active_entry {
3007 snippet_edits.push((edit.range, snippet));
3008 } else {
3009 // Since this buffer is not focused, apply a normal edit.
3010 let new_edit = TextEdit {
3011 range: edit.range,
3012 new_text: snippet.text,
3013 };
3014 if !edits.contains(&new_edit) {
3015 edits.push(new_edit);
3016 }
3017 }
3018 }
3019 }
3020 }
3021 if !snippet_edits.is_empty() {
3022 let buffer_id = buffer_to_edit.read(cx).remote_id();
3023 let version = if let Some(buffer_version) = op.text_document.version
3024 {
3025 local
3026 .buffer_snapshot_for_lsp_version(
3027 &buffer_to_edit,
3028 language_server.server_id(),
3029 Some(buffer_version),
3030 cx,
3031 )
3032 .ok()
3033 .map(|snapshot| snapshot.version)
3034 } else {
3035 Some(buffer_to_edit.read(cx).saved_version().clone())
3036 };
3037
3038 let most_recent_edit =
3039 version.and_then(|version| version.most_recent());
3040 // Check if the edit that triggered that edit has been made by this participant.
3041
3042 if let Some(most_recent_edit) = most_recent_edit {
3043 cx.emit(LspStoreEvent::SnippetEdit {
3044 buffer_id,
3045 edits: snippet_edits,
3046 most_recent_edit,
3047 });
3048 }
3049 }
3050
3051 local.edits_from_lsp(
3052 &buffer_to_edit,
3053 edits,
3054 language_server.server_id(),
3055 op.text_document.version,
3056 cx,
3057 )
3058 })?
3059 .await?;
3060
3061 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3062 buffer.finalize_last_transaction();
3063 buffer.start_transaction();
3064 for (range, text) in edits {
3065 buffer.edit([(range, text)], None, cx);
3066 }
3067
3068 buffer.end_transaction(cx).and_then(|transaction_id| {
3069 if push_to_history {
3070 buffer.finalize_last_transaction();
3071 buffer.get_transaction(transaction_id).cloned()
3072 } else {
3073 buffer.forget_transaction(transaction_id)
3074 }
3075 })
3076 })?;
3077 if let Some(transaction) = transaction {
3078 project_transaction.0.insert(buffer_to_edit, transaction);
3079 }
3080 }
3081 }
3082 }
3083
3084 Ok(project_transaction)
3085 }
3086
3087 async fn on_lsp_workspace_edit(
3088 this: WeakEntity<LspStore>,
3089 params: lsp::ApplyWorkspaceEditParams,
3090 server_id: LanguageServerId,
3091 cx: &mut AsyncApp,
3092 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3093 let this = this.upgrade().context("project project closed")?;
3094 let language_server = this
3095 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3096 .context("language server not found")?;
3097 let transaction = Self::deserialize_workspace_edit(
3098 this.clone(),
3099 params.edit,
3100 true,
3101 language_server.clone(),
3102 cx,
3103 )
3104 .await
3105 .log_err();
3106 this.update(cx, |this, _| {
3107 if let Some(transaction) = transaction {
3108 this.as_local_mut()
3109 .unwrap()
3110 .last_workspace_edits_by_language_server
3111 .insert(server_id, transaction);
3112 }
3113 })?;
3114 Ok(lsp::ApplyWorkspaceEditResponse {
3115 applied: true,
3116 failed_change: None,
3117 failure_reason: None,
3118 })
3119 }
3120
3121 fn remove_worktree(
3122 &mut self,
3123 id_to_remove: WorktreeId,
3124 cx: &mut Context<LspStore>,
3125 ) -> Vec<LanguageServerId> {
3126 self.diagnostics.remove(&id_to_remove);
3127 self.prettier_store.update(cx, |prettier_store, cx| {
3128 prettier_store.remove_worktree(id_to_remove, cx);
3129 });
3130
3131 let mut servers_to_remove = BTreeSet::default();
3132 let mut servers_to_preserve = HashSet::default();
3133 for (seed, state) in &self.language_server_ids {
3134 if seed.worktree_id == id_to_remove {
3135 servers_to_remove.insert(state.id);
3136 } else {
3137 servers_to_preserve.insert(state.id);
3138 }
3139 }
3140 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3141 self.language_server_ids
3142 .retain(|_, state| !servers_to_remove.contains(&state.id));
3143 for server_id_to_remove in &servers_to_remove {
3144 self.language_server_watched_paths
3145 .remove(server_id_to_remove);
3146 self.language_server_paths_watched_for_rename
3147 .remove(server_id_to_remove);
3148 self.last_workspace_edits_by_language_server
3149 .remove(server_id_to_remove);
3150 self.language_servers.remove(server_id_to_remove);
3151 self.buffer_pull_diagnostics_result_ids
3152 .remove(server_id_to_remove);
3153 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3154 buffer_servers.remove(server_id_to_remove);
3155 }
3156 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3157 }
3158 servers_to_remove.into_iter().collect()
3159 }
3160
3161 fn rebuild_watched_paths_inner<'a>(
3162 &'a self,
3163 language_server_id: LanguageServerId,
3164 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3165 cx: &mut Context<LspStore>,
3166 ) -> LanguageServerWatchedPathsBuilder {
3167 let worktrees = self
3168 .worktree_store
3169 .read(cx)
3170 .worktrees()
3171 .filter_map(|worktree| {
3172 self.language_servers_for_worktree(worktree.read(cx).id())
3173 .find(|server| server.server_id() == language_server_id)
3174 .map(|_| worktree)
3175 })
3176 .collect::<Vec<_>>();
3177
3178 let mut worktree_globs = HashMap::default();
3179 let mut abs_globs = HashMap::default();
3180 log::trace!(
3181 "Processing new watcher paths for language server with id {}",
3182 language_server_id
3183 );
3184
3185 for watcher in watchers {
3186 if let Some((worktree, literal_prefix, pattern)) =
3187 self.worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3188 {
3189 worktree.update(cx, |worktree, _| {
3190 if let Some((tree, glob)) =
3191 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3192 {
3193 tree.add_path_prefix_to_scan(literal_prefix);
3194 worktree_globs
3195 .entry(tree.id())
3196 .or_insert_with(GlobSetBuilder::new)
3197 .add(glob);
3198 }
3199 });
3200 } else {
3201 let (path, pattern) = match &watcher.glob_pattern {
3202 lsp::GlobPattern::String(s) => {
3203 let watcher_path = SanitizedPath::new(s);
3204 let path = glob_literal_prefix(watcher_path.as_path());
3205 let pattern = watcher_path
3206 .as_path()
3207 .strip_prefix(&path)
3208 .map(|p| p.to_string_lossy().into_owned())
3209 .unwrap_or_else(|e| {
3210 debug_panic!(
3211 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3212 s,
3213 path.display(),
3214 e
3215 );
3216 watcher_path.as_path().to_string_lossy().into_owned()
3217 });
3218 (path, pattern)
3219 }
3220 lsp::GlobPattern::Relative(rp) => {
3221 let Ok(mut base_uri) = match &rp.base_uri {
3222 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3223 lsp::OneOf::Right(base_uri) => base_uri,
3224 }
3225 .to_file_path() else {
3226 continue;
3227 };
3228
3229 let path = glob_literal_prefix(Path::new(&rp.pattern));
3230 let pattern = Path::new(&rp.pattern)
3231 .strip_prefix(&path)
3232 .map(|p| p.to_string_lossy().into_owned())
3233 .unwrap_or_else(|e| {
3234 debug_panic!(
3235 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3236 rp.pattern,
3237 path.display(),
3238 e
3239 );
3240 rp.pattern.clone()
3241 });
3242 base_uri.push(path);
3243 (base_uri, pattern)
3244 }
3245 };
3246
3247 if let Some(glob) = Glob::new(&pattern).log_err() {
3248 if !path
3249 .components()
3250 .any(|c| matches!(c, path::Component::Normal(_)))
3251 {
3252 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3253 // rather than adding a new watcher for `/`.
3254 for worktree in &worktrees {
3255 worktree_globs
3256 .entry(worktree.read(cx).id())
3257 .or_insert_with(GlobSetBuilder::new)
3258 .add(glob.clone());
3259 }
3260 } else {
3261 abs_globs
3262 .entry(path.into())
3263 .or_insert_with(GlobSetBuilder::new)
3264 .add(glob);
3265 }
3266 }
3267 }
3268 }
3269
3270 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3271 for (worktree_id, builder) in worktree_globs {
3272 if let Ok(globset) = builder.build() {
3273 watch_builder.watch_worktree(worktree_id, globset);
3274 }
3275 }
3276 for (abs_path, builder) in abs_globs {
3277 if let Ok(globset) = builder.build() {
3278 watch_builder.watch_abs_path(abs_path, globset);
3279 }
3280 }
3281 watch_builder
3282 }
3283
3284 fn worktree_and_path_for_file_watcher(
3285 &self,
3286 worktrees: &[Entity<Worktree>],
3287 watcher: &FileSystemWatcher,
3288 cx: &App,
3289 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3290 worktrees.iter().find_map(|worktree| {
3291 let tree = worktree.read(cx);
3292 let worktree_root_path = tree.abs_path();
3293 let path_style = tree.path_style();
3294 match &watcher.glob_pattern {
3295 lsp::GlobPattern::String(s) => {
3296 let watcher_path = SanitizedPath::new(s);
3297 let relative = watcher_path
3298 .as_path()
3299 .strip_prefix(&worktree_root_path)
3300 .ok()?;
3301 let literal_prefix = glob_literal_prefix(relative);
3302 Some((
3303 worktree.clone(),
3304 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3305 relative.to_string_lossy().into_owned(),
3306 ))
3307 }
3308 lsp::GlobPattern::Relative(rp) => {
3309 let base_uri = match &rp.base_uri {
3310 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3311 lsp::OneOf::Right(base_uri) => base_uri,
3312 }
3313 .to_file_path()
3314 .ok()?;
3315 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3316 let mut literal_prefix = relative.to_owned();
3317 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3318 Some((
3319 worktree.clone(),
3320 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3321 rp.pattern.clone(),
3322 ))
3323 }
3324 }
3325 })
3326 }
3327
3328 fn rebuild_watched_paths(
3329 &mut self,
3330 language_server_id: LanguageServerId,
3331 cx: &mut Context<LspStore>,
3332 ) {
3333 let Some(watchers) = self
3334 .language_server_watcher_registrations
3335 .get(&language_server_id)
3336 else {
3337 return;
3338 };
3339
3340 let watch_builder =
3341 self.rebuild_watched_paths_inner(language_server_id, watchers.values().flatten(), cx);
3342 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3343 self.language_server_watched_paths
3344 .insert(language_server_id, watcher);
3345
3346 cx.notify();
3347 }
3348
3349 fn on_lsp_did_change_watched_files(
3350 &mut self,
3351 language_server_id: LanguageServerId,
3352 registration_id: &str,
3353 params: DidChangeWatchedFilesRegistrationOptions,
3354 cx: &mut Context<LspStore>,
3355 ) {
3356 let registrations = self
3357 .language_server_watcher_registrations
3358 .entry(language_server_id)
3359 .or_default();
3360
3361 registrations.insert(registration_id.to_string(), params.watchers);
3362
3363 self.rebuild_watched_paths(language_server_id, cx);
3364 }
3365
3366 fn on_lsp_unregister_did_change_watched_files(
3367 &mut self,
3368 language_server_id: LanguageServerId,
3369 registration_id: &str,
3370 cx: &mut Context<LspStore>,
3371 ) {
3372 let registrations = self
3373 .language_server_watcher_registrations
3374 .entry(language_server_id)
3375 .or_default();
3376
3377 if registrations.remove(registration_id).is_some() {
3378 log::info!(
3379 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3380 language_server_id,
3381 registration_id
3382 );
3383 } else {
3384 log::warn!(
3385 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3386 language_server_id,
3387 registration_id
3388 );
3389 }
3390
3391 self.rebuild_watched_paths(language_server_id, cx);
3392 }
3393
3394 async fn initialization_options_for_adapter(
3395 adapter: Arc<dyn LspAdapter>,
3396 delegate: &Arc<dyn LspAdapterDelegate>,
3397 ) -> Result<Option<serde_json::Value>> {
3398 let Some(mut initialization_config) =
3399 adapter.clone().initialization_options(delegate).await?
3400 else {
3401 return Ok(None);
3402 };
3403
3404 for other_adapter in delegate.registered_lsp_adapters() {
3405 if other_adapter.name() == adapter.name() {
3406 continue;
3407 }
3408 if let Ok(Some(target_config)) = other_adapter
3409 .clone()
3410 .additional_initialization_options(adapter.name(), delegate)
3411 .await
3412 {
3413 merge_json_value_into(target_config.clone(), &mut initialization_config);
3414 }
3415 }
3416
3417 Ok(Some(initialization_config))
3418 }
3419
3420 async fn workspace_configuration_for_adapter(
3421 adapter: Arc<dyn LspAdapter>,
3422 delegate: &Arc<dyn LspAdapterDelegate>,
3423 toolchain: Option<Toolchain>,
3424 cx: &mut AsyncApp,
3425 ) -> Result<serde_json::Value> {
3426 let mut workspace_config = adapter
3427 .clone()
3428 .workspace_configuration(delegate, toolchain, cx)
3429 .await?;
3430
3431 for other_adapter in delegate.registered_lsp_adapters() {
3432 if other_adapter.name() == adapter.name() {
3433 continue;
3434 }
3435 if let Ok(Some(target_config)) = other_adapter
3436 .clone()
3437 .additional_workspace_configuration(adapter.name(), delegate, cx)
3438 .await
3439 {
3440 merge_json_value_into(target_config.clone(), &mut workspace_config);
3441 }
3442 }
3443
3444 Ok(workspace_config)
3445 }
3446
3447 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3448 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3449 Some(server.clone())
3450 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3451 Some(Arc::clone(server))
3452 } else {
3453 None
3454 }
3455 }
3456}
3457
3458fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3459 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3460 cx.emit(LspStoreEvent::LanguageServerUpdate {
3461 language_server_id: server.server_id(),
3462 name: Some(server.name()),
3463 message: proto::update_language_server::Variant::MetadataUpdated(
3464 proto::ServerMetadataUpdated {
3465 capabilities: Some(capabilities),
3466 },
3467 ),
3468 });
3469 }
3470}
3471
3472#[derive(Debug)]
3473pub struct FormattableBuffer {
3474 handle: Entity<Buffer>,
3475 abs_path: Option<PathBuf>,
3476 env: Option<HashMap<String, String>>,
3477 ranges: Option<Vec<Range<Anchor>>>,
3478}
3479
3480pub struct RemoteLspStore {
3481 upstream_client: Option<AnyProtoClient>,
3482 upstream_project_id: u64,
3483}
3484
3485pub(crate) enum LspStoreMode {
3486 Local(LocalLspStore), // ssh host and collab host
3487 Remote(RemoteLspStore), // collab guest
3488}
3489
3490impl LspStoreMode {
3491 fn is_local(&self) -> bool {
3492 matches!(self, LspStoreMode::Local(_))
3493 }
3494}
3495
3496pub struct LspStore {
3497 mode: LspStoreMode,
3498 last_formatting_failure: Option<String>,
3499 downstream_client: Option<(AnyProtoClient, u64)>,
3500 nonce: u128,
3501 buffer_store: Entity<BufferStore>,
3502 worktree_store: Entity<WorktreeStore>,
3503 pub languages: Arc<LanguageRegistry>,
3504 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3505 active_entry: Option<ProjectEntryId>,
3506 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3507 _maintain_buffer_languages: Task<()>,
3508 diagnostic_summaries:
3509 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3510 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3511 lsp_data: HashMap<BufferId, BufferLspData>,
3512 next_hint_id: Arc<AtomicUsize>,
3513}
3514
3515#[derive(Debug)]
3516pub struct BufferLspData {
3517 buffer_version: Global,
3518 document_colors: Option<DocumentColorData>,
3519 code_lens: Option<CodeLensData>,
3520 inlay_hints: BufferInlayHints,
3521 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3522 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3523}
3524
3525#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3526struct LspKey {
3527 request_type: TypeId,
3528 server_queried: Option<LanguageServerId>,
3529}
3530
3531impl BufferLspData {
3532 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3533 Self {
3534 buffer_version: buffer.read(cx).version(),
3535 document_colors: None,
3536 code_lens: None,
3537 inlay_hints: BufferInlayHints::new(buffer, cx),
3538 lsp_requests: HashMap::default(),
3539 chunk_lsp_requests: HashMap::default(),
3540 }
3541 }
3542
3543 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3544 if let Some(document_colors) = &mut self.document_colors {
3545 document_colors.colors.remove(&for_server);
3546 document_colors.cache_version += 1;
3547 }
3548
3549 if let Some(code_lens) = &mut self.code_lens {
3550 code_lens.lens.remove(&for_server);
3551 }
3552
3553 self.inlay_hints.remove_server_data(for_server);
3554 }
3555
3556 #[cfg(any(test, feature = "test-support"))]
3557 pub fn inlay_hints(&self) -> &BufferInlayHints {
3558 &self.inlay_hints
3559 }
3560}
3561
3562#[derive(Debug, Default, Clone)]
3563pub struct DocumentColors {
3564 pub colors: HashSet<DocumentColor>,
3565 pub cache_version: Option<usize>,
3566}
3567
3568type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3569type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3570
3571#[derive(Debug, Default)]
3572struct DocumentColorData {
3573 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3574 cache_version: usize,
3575 colors_update: Option<(Global, DocumentColorTask)>,
3576}
3577
3578#[derive(Debug, Default)]
3579struct CodeLensData {
3580 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3581 update: Option<(Global, CodeLensTask)>,
3582}
3583
3584#[derive(Debug)]
3585pub enum LspStoreEvent {
3586 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3587 LanguageServerRemoved(LanguageServerId),
3588 LanguageServerUpdate {
3589 language_server_id: LanguageServerId,
3590 name: Option<LanguageServerName>,
3591 message: proto::update_language_server::Variant,
3592 },
3593 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3594 LanguageServerPrompt(LanguageServerPromptRequest),
3595 LanguageDetected {
3596 buffer: Entity<Buffer>,
3597 new_language: Option<Arc<Language>>,
3598 },
3599 Notification(String),
3600 RefreshInlayHints(LanguageServerId),
3601 RefreshCodeLens,
3602 DiagnosticsUpdated {
3603 server_id: LanguageServerId,
3604 paths: Vec<ProjectPath>,
3605 },
3606 DiskBasedDiagnosticsStarted {
3607 language_server_id: LanguageServerId,
3608 },
3609 DiskBasedDiagnosticsFinished {
3610 language_server_id: LanguageServerId,
3611 },
3612 SnippetEdit {
3613 buffer_id: BufferId,
3614 edits: Vec<(lsp::Range, Snippet)>,
3615 most_recent_edit: clock::Lamport,
3616 },
3617}
3618
3619#[derive(Clone, Debug, Serialize)]
3620pub struct LanguageServerStatus {
3621 pub name: LanguageServerName,
3622 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3623 pub has_pending_diagnostic_updates: bool,
3624 progress_tokens: HashSet<String>,
3625 pub worktree: Option<WorktreeId>,
3626}
3627
3628#[derive(Clone, Debug)]
3629struct CoreSymbol {
3630 pub language_server_name: LanguageServerName,
3631 pub source_worktree_id: WorktreeId,
3632 pub source_language_server_id: LanguageServerId,
3633 pub path: SymbolLocation,
3634 pub name: String,
3635 pub kind: lsp::SymbolKind,
3636 pub range: Range<Unclipped<PointUtf16>>,
3637}
3638
3639#[derive(Clone, Debug, PartialEq, Eq)]
3640pub enum SymbolLocation {
3641 InProject(ProjectPath),
3642 OutsideProject {
3643 abs_path: Arc<Path>,
3644 signature: [u8; 32],
3645 },
3646}
3647
3648impl SymbolLocation {
3649 fn file_name(&self) -> Option<&str> {
3650 match self {
3651 Self::InProject(path) => path.path.file_name(),
3652 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3653 }
3654 }
3655}
3656
3657impl LspStore {
3658 pub fn init(client: &AnyProtoClient) {
3659 client.add_entity_request_handler(Self::handle_lsp_query);
3660 client.add_entity_message_handler(Self::handle_lsp_query_response);
3661 client.add_entity_request_handler(Self::handle_restart_language_servers);
3662 client.add_entity_request_handler(Self::handle_stop_language_servers);
3663 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3664 client.add_entity_message_handler(Self::handle_start_language_server);
3665 client.add_entity_message_handler(Self::handle_update_language_server);
3666 client.add_entity_message_handler(Self::handle_language_server_log);
3667 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3668 client.add_entity_request_handler(Self::handle_format_buffers);
3669 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3670 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3671 client.add_entity_request_handler(Self::handle_apply_code_action);
3672 client.add_entity_request_handler(Self::handle_get_project_symbols);
3673 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3674 client.add_entity_request_handler(Self::handle_get_color_presentation);
3675 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3676 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3677 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3678 client.add_entity_request_handler(Self::handle_on_type_formatting);
3679 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3680 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3681 client.add_entity_request_handler(Self::handle_rename_project_entry);
3682 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3683 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3684 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3685 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3686 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3687 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3688 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3689
3690 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3691 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3692 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3693 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3694 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3695 client.add_entity_request_handler(
3696 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3697 );
3698 client.add_entity_request_handler(
3699 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3700 );
3701 client.add_entity_request_handler(
3702 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3703 );
3704 }
3705
3706 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3707 match &self.mode {
3708 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3709 _ => None,
3710 }
3711 }
3712
3713 pub fn as_local(&self) -> Option<&LocalLspStore> {
3714 match &self.mode {
3715 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3716 _ => None,
3717 }
3718 }
3719
3720 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3721 match &mut self.mode {
3722 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3723 _ => None,
3724 }
3725 }
3726
3727 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3728 match &self.mode {
3729 LspStoreMode::Remote(RemoteLspStore {
3730 upstream_client: Some(upstream_client),
3731 upstream_project_id,
3732 ..
3733 }) => Some((upstream_client.clone(), *upstream_project_id)),
3734
3735 LspStoreMode::Remote(RemoteLspStore {
3736 upstream_client: None,
3737 ..
3738 }) => None,
3739 LspStoreMode::Local(_) => None,
3740 }
3741 }
3742
3743 pub fn new_local(
3744 buffer_store: Entity<BufferStore>,
3745 worktree_store: Entity<WorktreeStore>,
3746 prettier_store: Entity<PrettierStore>,
3747 toolchain_store: Entity<LocalToolchainStore>,
3748 environment: Entity<ProjectEnvironment>,
3749 manifest_tree: Entity<ManifestTree>,
3750 languages: Arc<LanguageRegistry>,
3751 http_client: Arc<dyn HttpClient>,
3752 fs: Arc<dyn Fs>,
3753 cx: &mut Context<Self>,
3754 ) -> Self {
3755 let yarn = YarnPathStore::new(fs.clone(), cx);
3756 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3757 .detach();
3758 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3759 .detach();
3760 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3761 .detach();
3762 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3763 .detach();
3764 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3765 .detach();
3766 subscribe_to_binary_statuses(&languages, cx).detach();
3767
3768 let _maintain_workspace_config = {
3769 let (sender, receiver) = watch::channel();
3770 (Self::maintain_workspace_config(receiver, cx), sender)
3771 };
3772
3773 Self {
3774 mode: LspStoreMode::Local(LocalLspStore {
3775 weak: cx.weak_entity(),
3776 worktree_store: worktree_store.clone(),
3777
3778 supplementary_language_servers: Default::default(),
3779 languages: languages.clone(),
3780 language_server_ids: Default::default(),
3781 language_servers: Default::default(),
3782 last_workspace_edits_by_language_server: Default::default(),
3783 language_server_watched_paths: Default::default(),
3784 language_server_paths_watched_for_rename: Default::default(),
3785 language_server_watcher_registrations: Default::default(),
3786 buffers_being_formatted: Default::default(),
3787 buffer_snapshots: Default::default(),
3788 prettier_store,
3789 environment,
3790 http_client,
3791 fs,
3792 yarn,
3793 next_diagnostic_group_id: Default::default(),
3794 diagnostics: Default::default(),
3795 _subscription: cx.on_app_quit(|this, cx| {
3796 this.as_local_mut()
3797 .unwrap()
3798 .shutdown_language_servers_on_quit(cx)
3799 }),
3800 lsp_tree: LanguageServerTree::new(
3801 manifest_tree,
3802 languages.clone(),
3803 toolchain_store.clone(),
3804 ),
3805 toolchain_store,
3806 registered_buffers: HashMap::default(),
3807 buffers_opened_in_servers: HashMap::default(),
3808 buffer_pull_diagnostics_result_ids: HashMap::default(),
3809 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3810 .manifest_file_names(),
3811 }),
3812 last_formatting_failure: None,
3813 downstream_client: None,
3814 buffer_store,
3815 worktree_store,
3816 languages: languages.clone(),
3817 language_server_statuses: Default::default(),
3818 nonce: StdRng::from_os_rng().random(),
3819 diagnostic_summaries: HashMap::default(),
3820 lsp_server_capabilities: HashMap::default(),
3821 lsp_data: HashMap::default(),
3822 next_hint_id: Arc::default(),
3823 active_entry: None,
3824 _maintain_workspace_config,
3825 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3826 }
3827 }
3828
3829 fn send_lsp_proto_request<R: LspCommand>(
3830 &self,
3831 buffer: Entity<Buffer>,
3832 client: AnyProtoClient,
3833 upstream_project_id: u64,
3834 request: R,
3835 cx: &mut Context<LspStore>,
3836 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3837 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3838 return Task::ready(Ok(R::Response::default()));
3839 }
3840 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3841 cx.spawn(async move |this, cx| {
3842 let response = client.request(message).await?;
3843 let this = this.upgrade().context("project dropped")?;
3844 request
3845 .response_from_proto(response, this, buffer, cx.clone())
3846 .await
3847 })
3848 }
3849
3850 pub(super) fn new_remote(
3851 buffer_store: Entity<BufferStore>,
3852 worktree_store: Entity<WorktreeStore>,
3853 languages: Arc<LanguageRegistry>,
3854 upstream_client: AnyProtoClient,
3855 project_id: u64,
3856 cx: &mut Context<Self>,
3857 ) -> Self {
3858 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3859 .detach();
3860 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3861 .detach();
3862 subscribe_to_binary_statuses(&languages, cx).detach();
3863 let _maintain_workspace_config = {
3864 let (sender, receiver) = watch::channel();
3865 (Self::maintain_workspace_config(receiver, cx), sender)
3866 };
3867 Self {
3868 mode: LspStoreMode::Remote(RemoteLspStore {
3869 upstream_client: Some(upstream_client),
3870 upstream_project_id: project_id,
3871 }),
3872 downstream_client: None,
3873 last_formatting_failure: None,
3874 buffer_store,
3875 worktree_store,
3876 languages: languages.clone(),
3877 language_server_statuses: Default::default(),
3878 nonce: StdRng::from_os_rng().random(),
3879 diagnostic_summaries: HashMap::default(),
3880 lsp_server_capabilities: HashMap::default(),
3881 next_hint_id: Arc::default(),
3882 lsp_data: HashMap::default(),
3883 active_entry: None,
3884
3885 _maintain_workspace_config,
3886 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3887 }
3888 }
3889
3890 fn on_buffer_store_event(
3891 &mut self,
3892 _: Entity<BufferStore>,
3893 event: &BufferStoreEvent,
3894 cx: &mut Context<Self>,
3895 ) {
3896 match event {
3897 BufferStoreEvent::BufferAdded(buffer) => {
3898 self.on_buffer_added(buffer, cx).log_err();
3899 }
3900 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3901 let buffer_id = buffer.read(cx).remote_id();
3902 if let Some(local) = self.as_local_mut()
3903 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3904 {
3905 local.reset_buffer(buffer, old_file, cx);
3906
3907 if local.registered_buffers.contains_key(&buffer_id) {
3908 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3909 }
3910 }
3911
3912 self.detect_language_for_buffer(buffer, cx);
3913 if let Some(local) = self.as_local_mut() {
3914 local.initialize_buffer(buffer, cx);
3915 if local.registered_buffers.contains_key(&buffer_id) {
3916 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3917 }
3918 }
3919 }
3920 _ => {}
3921 }
3922 }
3923
3924 fn on_worktree_store_event(
3925 &mut self,
3926 _: Entity<WorktreeStore>,
3927 event: &WorktreeStoreEvent,
3928 cx: &mut Context<Self>,
3929 ) {
3930 match event {
3931 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3932 if !worktree.read(cx).is_local() {
3933 return;
3934 }
3935 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3936 worktree::Event::UpdatedEntries(changes) => {
3937 this.update_local_worktree_language_servers(&worktree, changes, cx);
3938 }
3939 worktree::Event::UpdatedGitRepositories(_)
3940 | worktree::Event::DeletedEntry(_) => {}
3941 })
3942 .detach()
3943 }
3944 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3945 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3946 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3947 }
3948 WorktreeStoreEvent::WorktreeReleased(..)
3949 | WorktreeStoreEvent::WorktreeOrderChanged
3950 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3951 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3952 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3953 }
3954 }
3955
3956 fn on_prettier_store_event(
3957 &mut self,
3958 _: Entity<PrettierStore>,
3959 event: &PrettierStoreEvent,
3960 cx: &mut Context<Self>,
3961 ) {
3962 match event {
3963 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3964 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3965 }
3966 PrettierStoreEvent::LanguageServerAdded {
3967 new_server_id,
3968 name,
3969 prettier_server,
3970 } => {
3971 self.register_supplementary_language_server(
3972 *new_server_id,
3973 name.clone(),
3974 prettier_server.clone(),
3975 cx,
3976 );
3977 }
3978 }
3979 }
3980
3981 fn on_toolchain_store_event(
3982 &mut self,
3983 _: Entity<LocalToolchainStore>,
3984 event: &ToolchainStoreEvent,
3985 _: &mut Context<Self>,
3986 ) {
3987 if let ToolchainStoreEvent::ToolchainActivated = event {
3988 self.request_workspace_config_refresh()
3989 }
3990 }
3991
3992 fn request_workspace_config_refresh(&mut self) {
3993 *self._maintain_workspace_config.1.borrow_mut() = ();
3994 }
3995
3996 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
3997 self.as_local().map(|local| local.prettier_store.clone())
3998 }
3999
4000 fn on_buffer_event(
4001 &mut self,
4002 buffer: Entity<Buffer>,
4003 event: &language::BufferEvent,
4004 cx: &mut Context<Self>,
4005 ) {
4006 match event {
4007 language::BufferEvent::Edited => {
4008 self.on_buffer_edited(buffer, cx);
4009 }
4010
4011 language::BufferEvent::Saved => {
4012 self.on_buffer_saved(buffer, cx);
4013 }
4014
4015 _ => {}
4016 }
4017 }
4018
4019 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4020 buffer
4021 .read(cx)
4022 .set_language_registry(self.languages.clone());
4023
4024 cx.subscribe(buffer, |this, buffer, event, cx| {
4025 this.on_buffer_event(buffer, event, cx);
4026 })
4027 .detach();
4028
4029 self.detect_language_for_buffer(buffer, cx);
4030 if let Some(local) = self.as_local_mut() {
4031 local.initialize_buffer(buffer, cx);
4032 }
4033
4034 Ok(())
4035 }
4036
4037 pub(crate) fn register_buffer_with_language_servers(
4038 &mut self,
4039 buffer: &Entity<Buffer>,
4040 only_register_servers: HashSet<LanguageServerSelector>,
4041 ignore_refcounts: bool,
4042 cx: &mut Context<Self>,
4043 ) -> OpenLspBufferHandle {
4044 let buffer_id = buffer.read(cx).remote_id();
4045 let handle = cx.new(|_| buffer.clone());
4046 if let Some(local) = self.as_local_mut() {
4047 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4048 if !ignore_refcounts {
4049 *refcount += 1;
4050 }
4051
4052 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4053 // 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
4054 // 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
4055 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4056 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4057 return handle;
4058 };
4059 if !file.is_local() {
4060 return handle;
4061 }
4062
4063 if ignore_refcounts || *refcount == 1 {
4064 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4065 }
4066 if !ignore_refcounts {
4067 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4068 let refcount = {
4069 let local = lsp_store.as_local_mut().unwrap();
4070 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4071 debug_panic!("bad refcounting");
4072 return;
4073 };
4074
4075 *refcount -= 1;
4076 *refcount
4077 };
4078 if refcount == 0 {
4079 lsp_store.lsp_data.remove(&buffer_id);
4080 let local = lsp_store.as_local_mut().unwrap();
4081 local.registered_buffers.remove(&buffer_id);
4082 local.buffers_opened_in_servers.remove(&buffer_id);
4083 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4084 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4085 }
4086 }
4087 })
4088 .detach();
4089 }
4090 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4091 let buffer_id = buffer.read(cx).remote_id().to_proto();
4092 cx.background_spawn(async move {
4093 upstream_client
4094 .request(proto::RegisterBufferWithLanguageServers {
4095 project_id: upstream_project_id,
4096 buffer_id,
4097 only_servers: only_register_servers
4098 .into_iter()
4099 .map(|selector| {
4100 let selector = match selector {
4101 LanguageServerSelector::Id(language_server_id) => {
4102 proto::language_server_selector::Selector::ServerId(
4103 language_server_id.to_proto(),
4104 )
4105 }
4106 LanguageServerSelector::Name(language_server_name) => {
4107 proto::language_server_selector::Selector::Name(
4108 language_server_name.to_string(),
4109 )
4110 }
4111 };
4112 proto::LanguageServerSelector {
4113 selector: Some(selector),
4114 }
4115 })
4116 .collect(),
4117 })
4118 .await
4119 })
4120 .detach();
4121 } else {
4122 panic!("oops!");
4123 }
4124 handle
4125 }
4126
4127 fn maintain_buffer_languages(
4128 languages: Arc<LanguageRegistry>,
4129 cx: &mut Context<Self>,
4130 ) -> Task<()> {
4131 let mut subscription = languages.subscribe();
4132 let mut prev_reload_count = languages.reload_count();
4133 cx.spawn(async move |this, cx| {
4134 while let Some(()) = subscription.next().await {
4135 if let Some(this) = this.upgrade() {
4136 // If the language registry has been reloaded, then remove and
4137 // re-assign the languages on all open buffers.
4138 let reload_count = languages.reload_count();
4139 if reload_count > prev_reload_count {
4140 prev_reload_count = reload_count;
4141 this.update(cx, |this, cx| {
4142 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4143 for buffer in buffer_store.buffers() {
4144 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4145 {
4146 buffer
4147 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4148 if let Some(local) = this.as_local_mut() {
4149 local.reset_buffer(&buffer, &f, cx);
4150
4151 if local
4152 .registered_buffers
4153 .contains_key(&buffer.read(cx).remote_id())
4154 && let Some(file_url) =
4155 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4156 {
4157 local.unregister_buffer_from_language_servers(
4158 &buffer, &file_url, cx,
4159 );
4160 }
4161 }
4162 }
4163 }
4164 });
4165 })
4166 .ok();
4167 }
4168
4169 this.update(cx, |this, cx| {
4170 let mut plain_text_buffers = Vec::new();
4171 let mut buffers_with_unknown_injections = Vec::new();
4172 for handle in this.buffer_store.read(cx).buffers() {
4173 let buffer = handle.read(cx);
4174 if buffer.language().is_none()
4175 || buffer.language() == Some(&*language::PLAIN_TEXT)
4176 {
4177 plain_text_buffers.push(handle);
4178 } else if buffer.contains_unknown_injections() {
4179 buffers_with_unknown_injections.push(handle);
4180 }
4181 }
4182
4183 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4184 // and reused later in the invisible worktrees.
4185 plain_text_buffers.sort_by_key(|buffer| {
4186 Reverse(
4187 File::from_dyn(buffer.read(cx).file())
4188 .map(|file| file.worktree.read(cx).is_visible()),
4189 )
4190 });
4191
4192 for buffer in plain_text_buffers {
4193 this.detect_language_for_buffer(&buffer, cx);
4194 if let Some(local) = this.as_local_mut() {
4195 local.initialize_buffer(&buffer, cx);
4196 if local
4197 .registered_buffers
4198 .contains_key(&buffer.read(cx).remote_id())
4199 {
4200 local.register_buffer_with_language_servers(
4201 &buffer,
4202 HashSet::default(),
4203 cx,
4204 );
4205 }
4206 }
4207 }
4208
4209 for buffer in buffers_with_unknown_injections {
4210 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4211 }
4212 })
4213 .ok();
4214 }
4215 }
4216 })
4217 }
4218
4219 fn detect_language_for_buffer(
4220 &mut self,
4221 buffer_handle: &Entity<Buffer>,
4222 cx: &mut Context<Self>,
4223 ) -> Option<language::AvailableLanguage> {
4224 // If the buffer has a language, set it and start the language server if we haven't already.
4225 let buffer = buffer_handle.read(cx);
4226 let file = buffer.file()?;
4227
4228 let content = buffer.as_rope();
4229 let available_language = self.languages.language_for_file(file, Some(content), cx);
4230 if let Some(available_language) = &available_language {
4231 if let Some(Ok(Ok(new_language))) = self
4232 .languages
4233 .load_language(available_language)
4234 .now_or_never()
4235 {
4236 self.set_language_for_buffer(buffer_handle, new_language, cx);
4237 }
4238 } else {
4239 cx.emit(LspStoreEvent::LanguageDetected {
4240 buffer: buffer_handle.clone(),
4241 new_language: None,
4242 });
4243 }
4244
4245 available_language
4246 }
4247
4248 pub(crate) fn set_language_for_buffer(
4249 &mut self,
4250 buffer_entity: &Entity<Buffer>,
4251 new_language: Arc<Language>,
4252 cx: &mut Context<Self>,
4253 ) {
4254 let buffer = buffer_entity.read(cx);
4255 let buffer_file = buffer.file().cloned();
4256 let buffer_id = buffer.remote_id();
4257 if let Some(local_store) = self.as_local_mut()
4258 && local_store.registered_buffers.contains_key(&buffer_id)
4259 && let Some(abs_path) =
4260 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4261 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4262 {
4263 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4264 }
4265 buffer_entity.update(cx, |buffer, cx| {
4266 if buffer
4267 .language()
4268 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4269 {
4270 buffer.set_language(Some(new_language.clone()), cx);
4271 }
4272 });
4273
4274 let settings =
4275 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4276 let buffer_file = File::from_dyn(buffer_file.as_ref());
4277
4278 let worktree_id = if let Some(file) = buffer_file {
4279 let worktree = file.worktree.clone();
4280
4281 if let Some(local) = self.as_local_mut()
4282 && local.registered_buffers.contains_key(&buffer_id)
4283 {
4284 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4285 }
4286 Some(worktree.read(cx).id())
4287 } else {
4288 None
4289 };
4290
4291 if settings.prettier.allowed
4292 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4293 {
4294 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4295 if let Some(prettier_store) = prettier_store {
4296 prettier_store.update(cx, |prettier_store, cx| {
4297 prettier_store.install_default_prettier(
4298 worktree_id,
4299 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4300 cx,
4301 )
4302 })
4303 }
4304 }
4305
4306 cx.emit(LspStoreEvent::LanguageDetected {
4307 buffer: buffer_entity.clone(),
4308 new_language: Some(new_language),
4309 })
4310 }
4311
4312 pub fn buffer_store(&self) -> Entity<BufferStore> {
4313 self.buffer_store.clone()
4314 }
4315
4316 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4317 self.active_entry = active_entry;
4318 }
4319
4320 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4321 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4322 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4323 {
4324 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4325 summaries
4326 .iter()
4327 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4328 });
4329 if let Some(summary) = summaries.next() {
4330 client
4331 .send(proto::UpdateDiagnosticSummary {
4332 project_id: downstream_project_id,
4333 worktree_id: worktree.id().to_proto(),
4334 summary: Some(summary),
4335 more_summaries: summaries.collect(),
4336 })
4337 .log_err();
4338 }
4339 }
4340 }
4341
4342 fn is_capable_for_proto_request<R>(
4343 &self,
4344 buffer: &Entity<Buffer>,
4345 request: &R,
4346 cx: &App,
4347 ) -> bool
4348 where
4349 R: LspCommand,
4350 {
4351 self.check_if_capable_for_proto_request(
4352 buffer,
4353 |capabilities| {
4354 request.check_capabilities(AdapterServerCapabilities {
4355 server_capabilities: capabilities.clone(),
4356 code_action_kinds: None,
4357 })
4358 },
4359 cx,
4360 )
4361 }
4362
4363 fn check_if_capable_for_proto_request<F>(
4364 &self,
4365 buffer: &Entity<Buffer>,
4366 check: F,
4367 cx: &App,
4368 ) -> bool
4369 where
4370 F: Fn(&lsp::ServerCapabilities) -> bool,
4371 {
4372 let Some(language) = buffer.read(cx).language().cloned() else {
4373 return false;
4374 };
4375 let relevant_language_servers = self
4376 .languages
4377 .lsp_adapters(&language.name())
4378 .into_iter()
4379 .map(|lsp_adapter| lsp_adapter.name())
4380 .collect::<HashSet<_>>();
4381 self.language_server_statuses
4382 .iter()
4383 .filter_map(|(server_id, server_status)| {
4384 relevant_language_servers
4385 .contains(&server_status.name)
4386 .then_some(server_id)
4387 })
4388 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4389 .any(check)
4390 }
4391
4392 pub fn request_lsp<R>(
4393 &mut self,
4394 buffer: Entity<Buffer>,
4395 server: LanguageServerToQuery,
4396 request: R,
4397 cx: &mut Context<Self>,
4398 ) -> Task<Result<R::Response>>
4399 where
4400 R: LspCommand,
4401 <R::LspRequest as lsp::request::Request>::Result: Send,
4402 <R::LspRequest as lsp::request::Request>::Params: Send,
4403 {
4404 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4405 return self.send_lsp_proto_request(
4406 buffer,
4407 upstream_client,
4408 upstream_project_id,
4409 request,
4410 cx,
4411 );
4412 }
4413
4414 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4415 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4416 local
4417 .language_servers_for_buffer(buffer, cx)
4418 .find(|(_, server)| {
4419 request.check_capabilities(server.adapter_server_capabilities())
4420 })
4421 .map(|(_, server)| server.clone())
4422 }),
4423 LanguageServerToQuery::Other(id) => self
4424 .language_server_for_local_buffer(buffer, id, cx)
4425 .and_then(|(_, server)| {
4426 request
4427 .check_capabilities(server.adapter_server_capabilities())
4428 .then(|| Arc::clone(server))
4429 }),
4430 }) else {
4431 return Task::ready(Ok(Default::default()));
4432 };
4433
4434 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4435
4436 let Some(file) = file else {
4437 return Task::ready(Ok(Default::default()));
4438 };
4439
4440 let lsp_params = match request.to_lsp_params_or_response(
4441 &file.abs_path(cx),
4442 buffer.read(cx),
4443 &language_server,
4444 cx,
4445 ) {
4446 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4447 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4448
4449 Err(err) => {
4450 let message = format!(
4451 "{} via {} failed: {}",
4452 request.display_name(),
4453 language_server.name(),
4454 err
4455 );
4456 log::warn!("{message}");
4457 return Task::ready(Err(anyhow!(message)));
4458 }
4459 };
4460
4461 let status = request.status();
4462 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4463 return Task::ready(Ok(Default::default()));
4464 }
4465 cx.spawn(async move |this, cx| {
4466 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4467
4468 let id = lsp_request.id();
4469 let _cleanup = if status.is_some() {
4470 cx.update(|cx| {
4471 this.update(cx, |this, cx| {
4472 this.on_lsp_work_start(
4473 language_server.server_id(),
4474 id.to_string(),
4475 LanguageServerProgress {
4476 is_disk_based_diagnostics_progress: false,
4477 is_cancellable: false,
4478 title: None,
4479 message: status.clone(),
4480 percentage: None,
4481 last_update_at: cx.background_executor().now(),
4482 },
4483 cx,
4484 );
4485 })
4486 })
4487 .log_err();
4488
4489 Some(defer(|| {
4490 cx.update(|cx| {
4491 this.update(cx, |this, cx| {
4492 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4493 })
4494 })
4495 .log_err();
4496 }))
4497 } else {
4498 None
4499 };
4500
4501 let result = lsp_request.await.into_response();
4502
4503 let response = result.map_err(|err| {
4504 let message = format!(
4505 "{} via {} failed: {}",
4506 request.display_name(),
4507 language_server.name(),
4508 err
4509 );
4510 log::warn!("{message}");
4511 anyhow::anyhow!(message)
4512 })?;
4513
4514 request
4515 .response_from_lsp(
4516 response,
4517 this.upgrade().context("no app context")?,
4518 buffer,
4519 language_server.server_id(),
4520 cx.clone(),
4521 )
4522 .await
4523 })
4524 }
4525
4526 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4527 let mut language_formatters_to_check = Vec::new();
4528 for buffer in self.buffer_store.read(cx).buffers() {
4529 let buffer = buffer.read(cx);
4530 let buffer_file = File::from_dyn(buffer.file());
4531 let buffer_language = buffer.language();
4532 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4533 if buffer_language.is_some() {
4534 language_formatters_to_check.push((
4535 buffer_file.map(|f| f.worktree_id(cx)),
4536 settings.into_owned(),
4537 ));
4538 }
4539 }
4540
4541 self.request_workspace_config_refresh();
4542
4543 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4544 prettier_store.update(cx, |prettier_store, cx| {
4545 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4546 })
4547 }
4548
4549 cx.notify();
4550 }
4551
4552 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4553 let buffer_store = self.buffer_store.clone();
4554 let Some(local) = self.as_local_mut() else {
4555 return;
4556 };
4557 let mut adapters = BTreeMap::default();
4558 let get_adapter = {
4559 let languages = local.languages.clone();
4560 let environment = local.environment.clone();
4561 let weak = local.weak.clone();
4562 let worktree_store = local.worktree_store.clone();
4563 let http_client = local.http_client.clone();
4564 let fs = local.fs.clone();
4565 move |worktree_id, cx: &mut App| {
4566 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4567 Some(LocalLspAdapterDelegate::new(
4568 languages.clone(),
4569 &environment,
4570 weak.clone(),
4571 &worktree,
4572 http_client.clone(),
4573 fs.clone(),
4574 cx,
4575 ))
4576 }
4577 };
4578
4579 let mut messages_to_report = Vec::new();
4580 let (new_tree, to_stop) = {
4581 let mut rebase = local.lsp_tree.rebase();
4582 let buffers = buffer_store
4583 .read(cx)
4584 .buffers()
4585 .filter_map(|buffer| {
4586 let raw_buffer = buffer.read(cx);
4587 if !local
4588 .registered_buffers
4589 .contains_key(&raw_buffer.remote_id())
4590 {
4591 return None;
4592 }
4593 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4594 let language = raw_buffer.language().cloned()?;
4595 Some((file, language, raw_buffer.remote_id()))
4596 })
4597 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4598 for (file, language, buffer_id) in buffers {
4599 let worktree_id = file.worktree_id(cx);
4600 let Some(worktree) = local
4601 .worktree_store
4602 .read(cx)
4603 .worktree_for_id(worktree_id, cx)
4604 else {
4605 continue;
4606 };
4607
4608 if let Some((_, apply)) = local.reuse_existing_language_server(
4609 rebase.server_tree(),
4610 &worktree,
4611 &language.name(),
4612 cx,
4613 ) {
4614 (apply)(rebase.server_tree());
4615 } else if let Some(lsp_delegate) = adapters
4616 .entry(worktree_id)
4617 .or_insert_with(|| get_adapter(worktree_id, cx))
4618 .clone()
4619 {
4620 let delegate =
4621 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4622 let path = file
4623 .path()
4624 .parent()
4625 .map(Arc::from)
4626 .unwrap_or_else(|| file.path().clone());
4627 let worktree_path = ProjectPath { worktree_id, path };
4628 let abs_path = file.abs_path(cx);
4629 let nodes = rebase
4630 .walk(
4631 worktree_path,
4632 language.name(),
4633 language.manifest(),
4634 delegate.clone(),
4635 cx,
4636 )
4637 .collect::<Vec<_>>();
4638 for node in nodes {
4639 let server_id = node.server_id_or_init(|disposition| {
4640 let path = &disposition.path;
4641 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4642 let key = LanguageServerSeed {
4643 worktree_id,
4644 name: disposition.server_name.clone(),
4645 settings: disposition.settings.clone(),
4646 toolchain: local.toolchain_store.read(cx).active_toolchain(
4647 path.worktree_id,
4648 &path.path,
4649 language.name(),
4650 ),
4651 };
4652 local.language_server_ids.remove(&key);
4653
4654 let server_id = local.get_or_insert_language_server(
4655 &worktree,
4656 lsp_delegate.clone(),
4657 disposition,
4658 &language.name(),
4659 cx,
4660 );
4661 if let Some(state) = local.language_servers.get(&server_id)
4662 && let Ok(uri) = uri
4663 {
4664 state.add_workspace_folder(uri);
4665 };
4666 server_id
4667 });
4668
4669 if let Some(language_server_id) = server_id {
4670 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4671 language_server_id,
4672 name: node.name(),
4673 message:
4674 proto::update_language_server::Variant::RegisteredForBuffer(
4675 proto::RegisteredForBuffer {
4676 buffer_abs_path: abs_path
4677 .to_string_lossy()
4678 .into_owned(),
4679 buffer_id: buffer_id.to_proto(),
4680 },
4681 ),
4682 });
4683 }
4684 }
4685 } else {
4686 continue;
4687 }
4688 }
4689 rebase.finish()
4690 };
4691 for message in messages_to_report {
4692 cx.emit(message);
4693 }
4694 local.lsp_tree = new_tree;
4695 for (id, _) in to_stop {
4696 self.stop_local_language_server(id, cx).detach();
4697 }
4698 }
4699
4700 pub fn apply_code_action(
4701 &self,
4702 buffer_handle: Entity<Buffer>,
4703 mut action: CodeAction,
4704 push_to_history: bool,
4705 cx: &mut Context<Self>,
4706 ) -> Task<Result<ProjectTransaction>> {
4707 if let Some((upstream_client, project_id)) = self.upstream_client() {
4708 let request = proto::ApplyCodeAction {
4709 project_id,
4710 buffer_id: buffer_handle.read(cx).remote_id().into(),
4711 action: Some(Self::serialize_code_action(&action)),
4712 };
4713 let buffer_store = self.buffer_store();
4714 cx.spawn(async move |_, cx| {
4715 let response = upstream_client
4716 .request(request)
4717 .await?
4718 .transaction
4719 .context("missing transaction")?;
4720
4721 buffer_store
4722 .update(cx, |buffer_store, cx| {
4723 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4724 })?
4725 .await
4726 })
4727 } else if self.mode.is_local() {
4728 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4729 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4730 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4731 }) else {
4732 return Task::ready(Ok(ProjectTransaction::default()));
4733 };
4734 cx.spawn(async move |this, cx| {
4735 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4736 .await
4737 .context("resolving a code action")?;
4738 if let Some(edit) = action.lsp_action.edit()
4739 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4740 return LocalLspStore::deserialize_workspace_edit(
4741 this.upgrade().context("no app present")?,
4742 edit.clone(),
4743 push_to_history,
4744
4745 lang_server.clone(),
4746 cx,
4747 )
4748 .await;
4749 }
4750
4751 if let Some(command) = action.lsp_action.command() {
4752 let server_capabilities = lang_server.capabilities();
4753 let available_commands = server_capabilities
4754 .execute_command_provider
4755 .as_ref()
4756 .map(|options| options.commands.as_slice())
4757 .unwrap_or_default();
4758 if available_commands.contains(&command.command) {
4759 this.update(cx, |this, _| {
4760 this.as_local_mut()
4761 .unwrap()
4762 .last_workspace_edits_by_language_server
4763 .remove(&lang_server.server_id());
4764 })?;
4765
4766 let _result = lang_server
4767 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4768 command: command.command.clone(),
4769 arguments: command.arguments.clone().unwrap_or_default(),
4770 ..lsp::ExecuteCommandParams::default()
4771 })
4772 .await.into_response()
4773 .context("execute command")?;
4774
4775 return this.update(cx, |this, _| {
4776 this.as_local_mut()
4777 .unwrap()
4778 .last_workspace_edits_by_language_server
4779 .remove(&lang_server.server_id())
4780 .unwrap_or_default()
4781 });
4782 } else {
4783 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4784 }
4785 }
4786
4787 Ok(ProjectTransaction::default())
4788 })
4789 } else {
4790 Task::ready(Err(anyhow!("no upstream client and not local")))
4791 }
4792 }
4793
4794 pub fn apply_code_action_kind(
4795 &mut self,
4796 buffers: HashSet<Entity<Buffer>>,
4797 kind: CodeActionKind,
4798 push_to_history: bool,
4799 cx: &mut Context<Self>,
4800 ) -> Task<anyhow::Result<ProjectTransaction>> {
4801 if self.as_local().is_some() {
4802 cx.spawn(async move |lsp_store, cx| {
4803 let buffers = buffers.into_iter().collect::<Vec<_>>();
4804 let result = LocalLspStore::execute_code_action_kind_locally(
4805 lsp_store.clone(),
4806 buffers,
4807 kind,
4808 push_to_history,
4809 cx,
4810 )
4811 .await;
4812 lsp_store.update(cx, |lsp_store, _| {
4813 lsp_store.update_last_formatting_failure(&result);
4814 })?;
4815 result
4816 })
4817 } else if let Some((client, project_id)) = self.upstream_client() {
4818 let buffer_store = self.buffer_store();
4819 cx.spawn(async move |lsp_store, cx| {
4820 let result = client
4821 .request(proto::ApplyCodeActionKind {
4822 project_id,
4823 kind: kind.as_str().to_owned(),
4824 buffer_ids: buffers
4825 .iter()
4826 .map(|buffer| {
4827 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4828 })
4829 .collect::<Result<_>>()?,
4830 })
4831 .await
4832 .and_then(|result| result.transaction.context("missing transaction"));
4833 lsp_store.update(cx, |lsp_store, _| {
4834 lsp_store.update_last_formatting_failure(&result);
4835 })?;
4836
4837 let transaction_response = result?;
4838 buffer_store
4839 .update(cx, |buffer_store, cx| {
4840 buffer_store.deserialize_project_transaction(
4841 transaction_response,
4842 push_to_history,
4843 cx,
4844 )
4845 })?
4846 .await
4847 })
4848 } else {
4849 Task::ready(Ok(ProjectTransaction::default()))
4850 }
4851 }
4852
4853 pub fn resolved_hint(
4854 &mut self,
4855 buffer_id: BufferId,
4856 id: InlayId,
4857 cx: &mut Context<Self>,
4858 ) -> Option<ResolvedHint> {
4859 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4860
4861 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4862 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4863 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4864 let (server_id, resolve_data) = match &hint.resolve_state {
4865 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4866 ResolveState::Resolving => {
4867 return Some(ResolvedHint::Resolving(
4868 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4869 ));
4870 }
4871 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4872 };
4873
4874 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4875 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4876 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4877 id,
4878 cx.spawn(async move |lsp_store, cx| {
4879 let resolved_hint = resolve_task.await;
4880 lsp_store
4881 .update(cx, |lsp_store, _| {
4882 if let Some(old_inlay_hint) = lsp_store
4883 .lsp_data
4884 .get_mut(&buffer_id)
4885 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4886 {
4887 match resolved_hint {
4888 Ok(resolved_hint) => {
4889 *old_inlay_hint = resolved_hint;
4890 }
4891 Err(e) => {
4892 old_inlay_hint.resolve_state =
4893 ResolveState::CanResolve(server_id, resolve_data);
4894 log::error!("Inlay hint resolve failed: {e:#}");
4895 }
4896 }
4897 }
4898 })
4899 .ok();
4900 })
4901 .shared(),
4902 );
4903 debug_assert!(
4904 previous_task.is_none(),
4905 "Did not change hint's resolve state after spawning its resolve"
4906 );
4907 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4908 None
4909 }
4910
4911 fn resolve_inlay_hint(
4912 &self,
4913 mut hint: InlayHint,
4914 buffer: Entity<Buffer>,
4915 server_id: LanguageServerId,
4916 cx: &mut Context<Self>,
4917 ) -> Task<anyhow::Result<InlayHint>> {
4918 if let Some((upstream_client, project_id)) = self.upstream_client() {
4919 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4920 {
4921 hint.resolve_state = ResolveState::Resolved;
4922 return Task::ready(Ok(hint));
4923 }
4924 let request = proto::ResolveInlayHint {
4925 project_id,
4926 buffer_id: buffer.read(cx).remote_id().into(),
4927 language_server_id: server_id.0 as u64,
4928 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4929 };
4930 cx.background_spawn(async move {
4931 let response = upstream_client
4932 .request(request)
4933 .await
4934 .context("inlay hints proto request")?;
4935 match response.hint {
4936 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4937 .context("inlay hints proto resolve response conversion"),
4938 None => Ok(hint),
4939 }
4940 })
4941 } else {
4942 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4943 self.language_server_for_local_buffer(buffer, server_id, cx)
4944 .map(|(_, server)| server.clone())
4945 }) else {
4946 return Task::ready(Ok(hint));
4947 };
4948 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4949 return Task::ready(Ok(hint));
4950 }
4951 let buffer_snapshot = buffer.read(cx).snapshot();
4952 cx.spawn(async move |_, cx| {
4953 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4954 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4955 );
4956 let resolved_hint = resolve_task
4957 .await
4958 .into_response()
4959 .context("inlay hint resolve LSP request")?;
4960 let resolved_hint = InlayHints::lsp_to_project_hint(
4961 resolved_hint,
4962 &buffer,
4963 server_id,
4964 ResolveState::Resolved,
4965 false,
4966 cx,
4967 )
4968 .await?;
4969 Ok(resolved_hint)
4970 })
4971 }
4972 }
4973
4974 pub fn resolve_color_presentation(
4975 &mut self,
4976 mut color: DocumentColor,
4977 buffer: Entity<Buffer>,
4978 server_id: LanguageServerId,
4979 cx: &mut Context<Self>,
4980 ) -> Task<Result<DocumentColor>> {
4981 if color.resolved {
4982 return Task::ready(Ok(color));
4983 }
4984
4985 if let Some((upstream_client, project_id)) = self.upstream_client() {
4986 let start = color.lsp_range.start;
4987 let end = color.lsp_range.end;
4988 let request = proto::GetColorPresentation {
4989 project_id,
4990 server_id: server_id.to_proto(),
4991 buffer_id: buffer.read(cx).remote_id().into(),
4992 color: Some(proto::ColorInformation {
4993 red: color.color.red,
4994 green: color.color.green,
4995 blue: color.color.blue,
4996 alpha: color.color.alpha,
4997 lsp_range_start: Some(proto::PointUtf16 {
4998 row: start.line,
4999 column: start.character,
5000 }),
5001 lsp_range_end: Some(proto::PointUtf16 {
5002 row: end.line,
5003 column: end.character,
5004 }),
5005 }),
5006 };
5007 cx.background_spawn(async move {
5008 let response = upstream_client
5009 .request(request)
5010 .await
5011 .context("color presentation proto request")?;
5012 color.resolved = true;
5013 color.color_presentations = response
5014 .presentations
5015 .into_iter()
5016 .map(|presentation| ColorPresentation {
5017 label: SharedString::from(presentation.label),
5018 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5019 additional_text_edits: presentation
5020 .additional_text_edits
5021 .into_iter()
5022 .filter_map(deserialize_lsp_edit)
5023 .collect(),
5024 })
5025 .collect();
5026 Ok(color)
5027 })
5028 } else {
5029 let path = match buffer
5030 .update(cx, |buffer, cx| {
5031 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5032 })
5033 .context("buffer with the missing path")
5034 {
5035 Ok(path) => path,
5036 Err(e) => return Task::ready(Err(e)),
5037 };
5038 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5039 self.language_server_for_local_buffer(buffer, server_id, cx)
5040 .map(|(_, server)| server.clone())
5041 }) else {
5042 return Task::ready(Ok(color));
5043 };
5044 cx.background_spawn(async move {
5045 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5046 lsp::ColorPresentationParams {
5047 text_document: make_text_document_identifier(&path)?,
5048 color: color.color,
5049 range: color.lsp_range,
5050 work_done_progress_params: Default::default(),
5051 partial_result_params: Default::default(),
5052 },
5053 );
5054 color.color_presentations = resolve_task
5055 .await
5056 .into_response()
5057 .context("color presentation resolve LSP request")?
5058 .into_iter()
5059 .map(|presentation| ColorPresentation {
5060 label: SharedString::from(presentation.label),
5061 text_edit: presentation.text_edit,
5062 additional_text_edits: presentation
5063 .additional_text_edits
5064 .unwrap_or_default(),
5065 })
5066 .collect();
5067 color.resolved = true;
5068 Ok(color)
5069 })
5070 }
5071 }
5072
5073 pub(crate) fn linked_edits(
5074 &mut self,
5075 buffer: &Entity<Buffer>,
5076 position: Anchor,
5077 cx: &mut Context<Self>,
5078 ) -> Task<Result<Vec<Range<Anchor>>>> {
5079 let snapshot = buffer.read(cx).snapshot();
5080 let scope = snapshot.language_scope_at(position);
5081 let Some(server_id) = self
5082 .as_local()
5083 .and_then(|local| {
5084 buffer.update(cx, |buffer, cx| {
5085 local
5086 .language_servers_for_buffer(buffer, cx)
5087 .filter(|(_, server)| {
5088 LinkedEditingRange::check_server_capabilities(server.capabilities())
5089 })
5090 .filter(|(adapter, _)| {
5091 scope
5092 .as_ref()
5093 .map(|scope| scope.language_allowed(&adapter.name))
5094 .unwrap_or(true)
5095 })
5096 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5097 .next()
5098 })
5099 })
5100 .or_else(|| {
5101 self.upstream_client()
5102 .is_some()
5103 .then_some(LanguageServerToQuery::FirstCapable)
5104 })
5105 .filter(|_| {
5106 maybe!({
5107 let language = buffer.read(cx).language_at(position)?;
5108 Some(
5109 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5110 .linked_edits,
5111 )
5112 }) == Some(true)
5113 })
5114 else {
5115 return Task::ready(Ok(Vec::new()));
5116 };
5117
5118 self.request_lsp(
5119 buffer.clone(),
5120 server_id,
5121 LinkedEditingRange { position },
5122 cx,
5123 )
5124 }
5125
5126 fn apply_on_type_formatting(
5127 &mut self,
5128 buffer: Entity<Buffer>,
5129 position: Anchor,
5130 trigger: String,
5131 cx: &mut Context<Self>,
5132 ) -> Task<Result<Option<Transaction>>> {
5133 if let Some((client, project_id)) = self.upstream_client() {
5134 if !self.check_if_capable_for_proto_request(
5135 &buffer,
5136 |capabilities| {
5137 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5138 },
5139 cx,
5140 ) {
5141 return Task::ready(Ok(None));
5142 }
5143 let request = proto::OnTypeFormatting {
5144 project_id,
5145 buffer_id: buffer.read(cx).remote_id().into(),
5146 position: Some(serialize_anchor(&position)),
5147 trigger,
5148 version: serialize_version(&buffer.read(cx).version()),
5149 };
5150 cx.background_spawn(async move {
5151 client
5152 .request(request)
5153 .await?
5154 .transaction
5155 .map(language::proto::deserialize_transaction)
5156 .transpose()
5157 })
5158 } else if let Some(local) = self.as_local_mut() {
5159 let buffer_id = buffer.read(cx).remote_id();
5160 local.buffers_being_formatted.insert(buffer_id);
5161 cx.spawn(async move |this, cx| {
5162 let _cleanup = defer({
5163 let this = this.clone();
5164 let mut cx = cx.clone();
5165 move || {
5166 this.update(&mut cx, |this, _| {
5167 if let Some(local) = this.as_local_mut() {
5168 local.buffers_being_formatted.remove(&buffer_id);
5169 }
5170 })
5171 .ok();
5172 }
5173 });
5174
5175 buffer
5176 .update(cx, |buffer, _| {
5177 buffer.wait_for_edits(Some(position.timestamp))
5178 })?
5179 .await?;
5180 this.update(cx, |this, cx| {
5181 let position = position.to_point_utf16(buffer.read(cx));
5182 this.on_type_format(buffer, position, trigger, false, cx)
5183 })?
5184 .await
5185 })
5186 } else {
5187 Task::ready(Err(anyhow!("No upstream client or local language server")))
5188 }
5189 }
5190
5191 pub fn on_type_format<T: ToPointUtf16>(
5192 &mut self,
5193 buffer: Entity<Buffer>,
5194 position: T,
5195 trigger: String,
5196 push_to_history: bool,
5197 cx: &mut Context<Self>,
5198 ) -> Task<Result<Option<Transaction>>> {
5199 let position = position.to_point_utf16(buffer.read(cx));
5200 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5201 }
5202
5203 fn on_type_format_impl(
5204 &mut self,
5205 buffer: Entity<Buffer>,
5206 position: PointUtf16,
5207 trigger: String,
5208 push_to_history: bool,
5209 cx: &mut Context<Self>,
5210 ) -> Task<Result<Option<Transaction>>> {
5211 let options = buffer.update(cx, |buffer, cx| {
5212 lsp_command::lsp_formatting_options(
5213 language_settings(
5214 buffer.language_at(position).map(|l| l.name()),
5215 buffer.file(),
5216 cx,
5217 )
5218 .as_ref(),
5219 )
5220 });
5221
5222 cx.spawn(async move |this, cx| {
5223 if let Some(waiter) =
5224 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5225 {
5226 waiter.await?;
5227 }
5228 cx.update(|cx| {
5229 this.update(cx, |this, cx| {
5230 this.request_lsp(
5231 buffer.clone(),
5232 LanguageServerToQuery::FirstCapable,
5233 OnTypeFormatting {
5234 position,
5235 trigger,
5236 options,
5237 push_to_history,
5238 },
5239 cx,
5240 )
5241 })
5242 })??
5243 .await
5244 })
5245 }
5246
5247 pub fn definitions(
5248 &mut self,
5249 buffer: &Entity<Buffer>,
5250 position: PointUtf16,
5251 cx: &mut Context<Self>,
5252 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5253 if let Some((upstream_client, project_id)) = self.upstream_client() {
5254 let request = GetDefinitions { position };
5255 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5256 return Task::ready(Ok(None));
5257 }
5258 let request_task = upstream_client.request_lsp(
5259 project_id,
5260 None,
5261 LSP_REQUEST_TIMEOUT,
5262 cx.background_executor().clone(),
5263 request.to_proto(project_id, buffer.read(cx)),
5264 );
5265 let buffer = buffer.clone();
5266 cx.spawn(async move |weak_project, cx| {
5267 let Some(project) = weak_project.upgrade() else {
5268 return Ok(None);
5269 };
5270 let Some(responses) = request_task.await? else {
5271 return Ok(None);
5272 };
5273 let actions = join_all(responses.payload.into_iter().map(|response| {
5274 GetDefinitions { position }.response_from_proto(
5275 response.response,
5276 project.clone(),
5277 buffer.clone(),
5278 cx.clone(),
5279 )
5280 }))
5281 .await;
5282
5283 Ok(Some(
5284 actions
5285 .into_iter()
5286 .collect::<Result<Vec<Vec<_>>>>()?
5287 .into_iter()
5288 .flatten()
5289 .dedup()
5290 .collect(),
5291 ))
5292 })
5293 } else {
5294 let definitions_task = self.request_multiple_lsp_locally(
5295 buffer,
5296 Some(position),
5297 GetDefinitions { position },
5298 cx,
5299 );
5300 cx.background_spawn(async move {
5301 Ok(Some(
5302 definitions_task
5303 .await
5304 .into_iter()
5305 .flat_map(|(_, definitions)| definitions)
5306 .dedup()
5307 .collect(),
5308 ))
5309 })
5310 }
5311 }
5312
5313 pub fn declarations(
5314 &mut self,
5315 buffer: &Entity<Buffer>,
5316 position: PointUtf16,
5317 cx: &mut Context<Self>,
5318 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5319 if let Some((upstream_client, project_id)) = self.upstream_client() {
5320 let request = GetDeclarations { position };
5321 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5322 return Task::ready(Ok(None));
5323 }
5324 let request_task = upstream_client.request_lsp(
5325 project_id,
5326 None,
5327 LSP_REQUEST_TIMEOUT,
5328 cx.background_executor().clone(),
5329 request.to_proto(project_id, buffer.read(cx)),
5330 );
5331 let buffer = buffer.clone();
5332 cx.spawn(async move |weak_project, cx| {
5333 let Some(project) = weak_project.upgrade() else {
5334 return Ok(None);
5335 };
5336 let Some(responses) = request_task.await? else {
5337 return Ok(None);
5338 };
5339 let actions = join_all(responses.payload.into_iter().map(|response| {
5340 GetDeclarations { position }.response_from_proto(
5341 response.response,
5342 project.clone(),
5343 buffer.clone(),
5344 cx.clone(),
5345 )
5346 }))
5347 .await;
5348
5349 Ok(Some(
5350 actions
5351 .into_iter()
5352 .collect::<Result<Vec<Vec<_>>>>()?
5353 .into_iter()
5354 .flatten()
5355 .dedup()
5356 .collect(),
5357 ))
5358 })
5359 } else {
5360 let declarations_task = self.request_multiple_lsp_locally(
5361 buffer,
5362 Some(position),
5363 GetDeclarations { position },
5364 cx,
5365 );
5366 cx.background_spawn(async move {
5367 Ok(Some(
5368 declarations_task
5369 .await
5370 .into_iter()
5371 .flat_map(|(_, declarations)| declarations)
5372 .dedup()
5373 .collect(),
5374 ))
5375 })
5376 }
5377 }
5378
5379 pub fn type_definitions(
5380 &mut self,
5381 buffer: &Entity<Buffer>,
5382 position: PointUtf16,
5383 cx: &mut Context<Self>,
5384 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5385 if let Some((upstream_client, project_id)) = self.upstream_client() {
5386 let request = GetTypeDefinitions { position };
5387 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5388 return Task::ready(Ok(None));
5389 }
5390 let request_task = upstream_client.request_lsp(
5391 project_id,
5392 None,
5393 LSP_REQUEST_TIMEOUT,
5394 cx.background_executor().clone(),
5395 request.to_proto(project_id, buffer.read(cx)),
5396 );
5397 let buffer = buffer.clone();
5398 cx.spawn(async move |weak_project, cx| {
5399 let Some(project) = weak_project.upgrade() else {
5400 return Ok(None);
5401 };
5402 let Some(responses) = request_task.await? else {
5403 return Ok(None);
5404 };
5405 let actions = join_all(responses.payload.into_iter().map(|response| {
5406 GetTypeDefinitions { position }.response_from_proto(
5407 response.response,
5408 project.clone(),
5409 buffer.clone(),
5410 cx.clone(),
5411 )
5412 }))
5413 .await;
5414
5415 Ok(Some(
5416 actions
5417 .into_iter()
5418 .collect::<Result<Vec<Vec<_>>>>()?
5419 .into_iter()
5420 .flatten()
5421 .dedup()
5422 .collect(),
5423 ))
5424 })
5425 } else {
5426 let type_definitions_task = self.request_multiple_lsp_locally(
5427 buffer,
5428 Some(position),
5429 GetTypeDefinitions { position },
5430 cx,
5431 );
5432 cx.background_spawn(async move {
5433 Ok(Some(
5434 type_definitions_task
5435 .await
5436 .into_iter()
5437 .flat_map(|(_, type_definitions)| type_definitions)
5438 .dedup()
5439 .collect(),
5440 ))
5441 })
5442 }
5443 }
5444
5445 pub fn implementations(
5446 &mut self,
5447 buffer: &Entity<Buffer>,
5448 position: PointUtf16,
5449 cx: &mut Context<Self>,
5450 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5451 if let Some((upstream_client, project_id)) = self.upstream_client() {
5452 let request = GetImplementations { position };
5453 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5454 return Task::ready(Ok(None));
5455 }
5456 let request_task = upstream_client.request_lsp(
5457 project_id,
5458 None,
5459 LSP_REQUEST_TIMEOUT,
5460 cx.background_executor().clone(),
5461 request.to_proto(project_id, buffer.read(cx)),
5462 );
5463 let buffer = buffer.clone();
5464 cx.spawn(async move |weak_project, cx| {
5465 let Some(project) = weak_project.upgrade() else {
5466 return Ok(None);
5467 };
5468 let Some(responses) = request_task.await? else {
5469 return Ok(None);
5470 };
5471 let actions = join_all(responses.payload.into_iter().map(|response| {
5472 GetImplementations { position }.response_from_proto(
5473 response.response,
5474 project.clone(),
5475 buffer.clone(),
5476 cx.clone(),
5477 )
5478 }))
5479 .await;
5480
5481 Ok(Some(
5482 actions
5483 .into_iter()
5484 .collect::<Result<Vec<Vec<_>>>>()?
5485 .into_iter()
5486 .flatten()
5487 .dedup()
5488 .collect(),
5489 ))
5490 })
5491 } else {
5492 let implementations_task = self.request_multiple_lsp_locally(
5493 buffer,
5494 Some(position),
5495 GetImplementations { position },
5496 cx,
5497 );
5498 cx.background_spawn(async move {
5499 Ok(Some(
5500 implementations_task
5501 .await
5502 .into_iter()
5503 .flat_map(|(_, implementations)| implementations)
5504 .dedup()
5505 .collect(),
5506 ))
5507 })
5508 }
5509 }
5510
5511 pub fn references(
5512 &mut self,
5513 buffer: &Entity<Buffer>,
5514 position: PointUtf16,
5515 cx: &mut Context<Self>,
5516 ) -> Task<Result<Option<Vec<Location>>>> {
5517 if let Some((upstream_client, project_id)) = self.upstream_client() {
5518 let request = GetReferences { position };
5519 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5520 return Task::ready(Ok(None));
5521 }
5522
5523 let request_task = upstream_client.request_lsp(
5524 project_id,
5525 None,
5526 LSP_REQUEST_TIMEOUT,
5527 cx.background_executor().clone(),
5528 request.to_proto(project_id, buffer.read(cx)),
5529 );
5530 let buffer = buffer.clone();
5531 cx.spawn(async move |weak_project, cx| {
5532 let Some(project) = weak_project.upgrade() else {
5533 return Ok(None);
5534 };
5535 let Some(responses) = request_task.await? else {
5536 return Ok(None);
5537 };
5538
5539 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5540 GetReferences { position }.response_from_proto(
5541 lsp_response.response,
5542 project.clone(),
5543 buffer.clone(),
5544 cx.clone(),
5545 )
5546 }))
5547 .await
5548 .into_iter()
5549 .collect::<Result<Vec<Vec<_>>>>()?
5550 .into_iter()
5551 .flatten()
5552 .dedup()
5553 .collect();
5554 Ok(Some(locations))
5555 })
5556 } else {
5557 let references_task = self.request_multiple_lsp_locally(
5558 buffer,
5559 Some(position),
5560 GetReferences { position },
5561 cx,
5562 );
5563 cx.background_spawn(async move {
5564 Ok(Some(
5565 references_task
5566 .await
5567 .into_iter()
5568 .flat_map(|(_, references)| references)
5569 .dedup()
5570 .collect(),
5571 ))
5572 })
5573 }
5574 }
5575
5576 pub fn code_actions(
5577 &mut self,
5578 buffer: &Entity<Buffer>,
5579 range: Range<Anchor>,
5580 kinds: Option<Vec<CodeActionKind>>,
5581 cx: &mut Context<Self>,
5582 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5583 if let Some((upstream_client, project_id)) = self.upstream_client() {
5584 let request = GetCodeActions {
5585 range: range.clone(),
5586 kinds: kinds.clone(),
5587 };
5588 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5589 return Task::ready(Ok(None));
5590 }
5591 let request_task = upstream_client.request_lsp(
5592 project_id,
5593 None,
5594 LSP_REQUEST_TIMEOUT,
5595 cx.background_executor().clone(),
5596 request.to_proto(project_id, buffer.read(cx)),
5597 );
5598 let buffer = buffer.clone();
5599 cx.spawn(async move |weak_project, cx| {
5600 let Some(project) = weak_project.upgrade() else {
5601 return Ok(None);
5602 };
5603 let Some(responses) = request_task.await? else {
5604 return Ok(None);
5605 };
5606 let actions = join_all(responses.payload.into_iter().map(|response| {
5607 GetCodeActions {
5608 range: range.clone(),
5609 kinds: kinds.clone(),
5610 }
5611 .response_from_proto(
5612 response.response,
5613 project.clone(),
5614 buffer.clone(),
5615 cx.clone(),
5616 )
5617 }))
5618 .await;
5619
5620 Ok(Some(
5621 actions
5622 .into_iter()
5623 .collect::<Result<Vec<Vec<_>>>>()?
5624 .into_iter()
5625 .flatten()
5626 .collect(),
5627 ))
5628 })
5629 } else {
5630 let all_actions_task = self.request_multiple_lsp_locally(
5631 buffer,
5632 Some(range.start),
5633 GetCodeActions { range, kinds },
5634 cx,
5635 );
5636 cx.background_spawn(async move {
5637 Ok(Some(
5638 all_actions_task
5639 .await
5640 .into_iter()
5641 .flat_map(|(_, actions)| actions)
5642 .collect(),
5643 ))
5644 })
5645 }
5646 }
5647
5648 pub fn code_lens_actions(
5649 &mut self,
5650 buffer: &Entity<Buffer>,
5651 cx: &mut Context<Self>,
5652 ) -> CodeLensTask {
5653 let version_queried_for = buffer.read(cx).version();
5654 let buffer_id = buffer.read(cx).remote_id();
5655 let existing_servers = self.as_local().map(|local| {
5656 local
5657 .buffers_opened_in_servers
5658 .get(&buffer_id)
5659 .cloned()
5660 .unwrap_or_default()
5661 });
5662
5663 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5664 if let Some(cached_lens) = &lsp_data.code_lens {
5665 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5666 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5667 existing_servers != cached_lens.lens.keys().copied().collect()
5668 });
5669 if !has_different_servers {
5670 return Task::ready(Ok(Some(
5671 cached_lens.lens.values().flatten().cloned().collect(),
5672 )))
5673 .shared();
5674 }
5675 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5676 if !version_queried_for.changed_since(updating_for) {
5677 return running_update.clone();
5678 }
5679 }
5680 }
5681 }
5682
5683 let lens_lsp_data = self
5684 .latest_lsp_data(buffer, cx)
5685 .code_lens
5686 .get_or_insert_default();
5687 let buffer = buffer.clone();
5688 let query_version_queried_for = version_queried_for.clone();
5689 let new_task = cx
5690 .spawn(async move |lsp_store, cx| {
5691 cx.background_executor()
5692 .timer(Duration::from_millis(30))
5693 .await;
5694 let fetched_lens = lsp_store
5695 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5696 .map_err(Arc::new)?
5697 .await
5698 .context("fetching code lens")
5699 .map_err(Arc::new);
5700 let fetched_lens = match fetched_lens {
5701 Ok(fetched_lens) => fetched_lens,
5702 Err(e) => {
5703 lsp_store
5704 .update(cx, |lsp_store, _| {
5705 if let Some(lens_lsp_data) = lsp_store
5706 .lsp_data
5707 .get_mut(&buffer_id)
5708 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5709 {
5710 lens_lsp_data.update = None;
5711 }
5712 })
5713 .ok();
5714 return Err(e);
5715 }
5716 };
5717
5718 lsp_store
5719 .update(cx, |lsp_store, _| {
5720 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5721 let code_lens = lsp_data.code_lens.as_mut()?;
5722 if let Some(fetched_lens) = fetched_lens {
5723 if lsp_data.buffer_version == query_version_queried_for {
5724 code_lens.lens.extend(fetched_lens);
5725 } else if !lsp_data
5726 .buffer_version
5727 .changed_since(&query_version_queried_for)
5728 {
5729 lsp_data.buffer_version = query_version_queried_for;
5730 code_lens.lens = fetched_lens;
5731 }
5732 }
5733 code_lens.update = None;
5734 Some(code_lens.lens.values().flatten().cloned().collect())
5735 })
5736 .map_err(Arc::new)
5737 })
5738 .shared();
5739 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5740 new_task
5741 }
5742
5743 fn fetch_code_lens(
5744 &mut self,
5745 buffer: &Entity<Buffer>,
5746 cx: &mut Context<Self>,
5747 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5748 if let Some((upstream_client, project_id)) = self.upstream_client() {
5749 let request = GetCodeLens;
5750 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5751 return Task::ready(Ok(None));
5752 }
5753 let request_task = upstream_client.request_lsp(
5754 project_id,
5755 None,
5756 LSP_REQUEST_TIMEOUT,
5757 cx.background_executor().clone(),
5758 request.to_proto(project_id, buffer.read(cx)),
5759 );
5760 let buffer = buffer.clone();
5761 cx.spawn(async move |weak_lsp_store, cx| {
5762 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5763 return Ok(None);
5764 };
5765 let Some(responses) = request_task.await? else {
5766 return Ok(None);
5767 };
5768
5769 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5770 let lsp_store = lsp_store.clone();
5771 let buffer = buffer.clone();
5772 let cx = cx.clone();
5773 async move {
5774 (
5775 LanguageServerId::from_proto(response.server_id),
5776 GetCodeLens
5777 .response_from_proto(response.response, lsp_store, buffer, cx)
5778 .await,
5779 )
5780 }
5781 }))
5782 .await;
5783
5784 let mut has_errors = false;
5785 let code_lens_actions = code_lens_actions
5786 .into_iter()
5787 .filter_map(|(server_id, code_lens)| match code_lens {
5788 Ok(code_lens) => Some((server_id, code_lens)),
5789 Err(e) => {
5790 has_errors = true;
5791 log::error!("{e:#}");
5792 None
5793 }
5794 })
5795 .collect::<HashMap<_, _>>();
5796 anyhow::ensure!(
5797 !has_errors || !code_lens_actions.is_empty(),
5798 "Failed to fetch code lens"
5799 );
5800 Ok(Some(code_lens_actions))
5801 })
5802 } else {
5803 let code_lens_actions_task =
5804 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5805 cx.background_spawn(async move {
5806 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5807 })
5808 }
5809 }
5810
5811 #[inline(never)]
5812 pub fn completions(
5813 &self,
5814 buffer: &Entity<Buffer>,
5815 position: PointUtf16,
5816 context: CompletionContext,
5817 cx: &mut Context<Self>,
5818 ) -> Task<Result<Vec<CompletionResponse>>> {
5819 let language_registry = self.languages.clone();
5820
5821 if let Some((upstream_client, project_id)) = self.upstream_client() {
5822 let request = GetCompletions { position, context };
5823 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5824 return Task::ready(Ok(Vec::new()));
5825 }
5826 let task = self.send_lsp_proto_request(
5827 buffer.clone(),
5828 upstream_client,
5829 project_id,
5830 request,
5831 cx,
5832 );
5833 let language = buffer.read(cx).language().cloned();
5834
5835 // In the future, we should provide project guests with the names of LSP adapters,
5836 // so that they can use the correct LSP adapter when computing labels. For now,
5837 // guests just use the first LSP adapter associated with the buffer's language.
5838 let lsp_adapter = language.as_ref().and_then(|language| {
5839 language_registry
5840 .lsp_adapters(&language.name())
5841 .first()
5842 .cloned()
5843 });
5844
5845 cx.foreground_executor().spawn(async move {
5846 let completion_response = task.await?;
5847 let completions = populate_labels_for_completions(
5848 completion_response.completions,
5849 language,
5850 lsp_adapter,
5851 )
5852 .await;
5853 Ok(vec![CompletionResponse {
5854 completions,
5855 display_options: CompletionDisplayOptions::default(),
5856 is_incomplete: completion_response.is_incomplete,
5857 }])
5858 })
5859 } else if let Some(local) = self.as_local() {
5860 let snapshot = buffer.read(cx).snapshot();
5861 let offset = position.to_offset(&snapshot);
5862 let scope = snapshot.language_scope_at(offset);
5863 let language = snapshot.language().cloned();
5864 let completion_settings = language_settings(
5865 language.as_ref().map(|language| language.name()),
5866 buffer.read(cx).file(),
5867 cx,
5868 )
5869 .completions
5870 .clone();
5871 if !completion_settings.lsp {
5872 return Task::ready(Ok(Vec::new()));
5873 }
5874
5875 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5876 local
5877 .language_servers_for_buffer(buffer, cx)
5878 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5879 .filter(|(adapter, _)| {
5880 scope
5881 .as_ref()
5882 .map(|scope| scope.language_allowed(&adapter.name))
5883 .unwrap_or(true)
5884 })
5885 .map(|(_, server)| server.server_id())
5886 .collect()
5887 });
5888
5889 let buffer = buffer.clone();
5890 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5891 let lsp_timeout = if lsp_timeout > 0 {
5892 Some(Duration::from_millis(lsp_timeout))
5893 } else {
5894 None
5895 };
5896 cx.spawn(async move |this, cx| {
5897 let mut tasks = Vec::with_capacity(server_ids.len());
5898 this.update(cx, |lsp_store, cx| {
5899 for server_id in server_ids {
5900 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5901 let lsp_timeout = lsp_timeout
5902 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5903 let mut timeout = cx.background_spawn(async move {
5904 match lsp_timeout {
5905 Some(lsp_timeout) => {
5906 lsp_timeout.await;
5907 true
5908 },
5909 None => false,
5910 }
5911 }).fuse();
5912 let mut lsp_request = lsp_store.request_lsp(
5913 buffer.clone(),
5914 LanguageServerToQuery::Other(server_id),
5915 GetCompletions {
5916 position,
5917 context: context.clone(),
5918 },
5919 cx,
5920 ).fuse();
5921 let new_task = cx.background_spawn(async move {
5922 select_biased! {
5923 response = lsp_request => anyhow::Ok(Some(response?)),
5924 timeout_happened = timeout => {
5925 if timeout_happened {
5926 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5927 Ok(None)
5928 } else {
5929 let completions = lsp_request.await?;
5930 Ok(Some(completions))
5931 }
5932 },
5933 }
5934 });
5935 tasks.push((lsp_adapter, new_task));
5936 }
5937 })?;
5938
5939 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5940 let completion_response = task.await.ok()??;
5941 let completions = populate_labels_for_completions(
5942 completion_response.completions,
5943 language.clone(),
5944 lsp_adapter,
5945 )
5946 .await;
5947 Some(CompletionResponse {
5948 completions,
5949 display_options: CompletionDisplayOptions::default(),
5950 is_incomplete: completion_response.is_incomplete,
5951 })
5952 });
5953
5954 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5955
5956 Ok(responses.into_iter().flatten().collect())
5957 })
5958 } else {
5959 Task::ready(Err(anyhow!("No upstream client or local language server")))
5960 }
5961 }
5962
5963 pub fn resolve_completions(
5964 &self,
5965 buffer: Entity<Buffer>,
5966 completion_indices: Vec<usize>,
5967 completions: Rc<RefCell<Box<[Completion]>>>,
5968 cx: &mut Context<Self>,
5969 ) -> Task<Result<bool>> {
5970 let client = self.upstream_client();
5971 let buffer_id = buffer.read(cx).remote_id();
5972 let buffer_snapshot = buffer.read(cx).snapshot();
5973
5974 if !self.check_if_capable_for_proto_request(
5975 &buffer,
5976 GetCompletions::can_resolve_completions,
5977 cx,
5978 ) {
5979 return Task::ready(Ok(false));
5980 }
5981 cx.spawn(async move |lsp_store, cx| {
5982 let mut did_resolve = false;
5983 if let Some((client, project_id)) = client {
5984 for completion_index in completion_indices {
5985 let server_id = {
5986 let completion = &completions.borrow()[completion_index];
5987 completion.source.server_id()
5988 };
5989 if let Some(server_id) = server_id {
5990 if Self::resolve_completion_remote(
5991 project_id,
5992 server_id,
5993 buffer_id,
5994 completions.clone(),
5995 completion_index,
5996 client.clone(),
5997 )
5998 .await
5999 .log_err()
6000 .is_some()
6001 {
6002 did_resolve = true;
6003 }
6004 } else {
6005 resolve_word_completion(
6006 &buffer_snapshot,
6007 &mut completions.borrow_mut()[completion_index],
6008 );
6009 }
6010 }
6011 } else {
6012 for completion_index in completion_indices {
6013 let server_id = {
6014 let completion = &completions.borrow()[completion_index];
6015 completion.source.server_id()
6016 };
6017 if let Some(server_id) = server_id {
6018 let server_and_adapter = lsp_store
6019 .read_with(cx, |lsp_store, _| {
6020 let server = lsp_store.language_server_for_id(server_id)?;
6021 let adapter =
6022 lsp_store.language_server_adapter_for_id(server.server_id())?;
6023 Some((server, adapter))
6024 })
6025 .ok()
6026 .flatten();
6027 let Some((server, adapter)) = server_and_adapter else {
6028 continue;
6029 };
6030
6031 let resolved = Self::resolve_completion_local(
6032 server,
6033 completions.clone(),
6034 completion_index,
6035 )
6036 .await
6037 .log_err()
6038 .is_some();
6039 if resolved {
6040 Self::regenerate_completion_labels(
6041 adapter,
6042 &buffer_snapshot,
6043 completions.clone(),
6044 completion_index,
6045 )
6046 .await
6047 .log_err();
6048 did_resolve = true;
6049 }
6050 } else {
6051 resolve_word_completion(
6052 &buffer_snapshot,
6053 &mut completions.borrow_mut()[completion_index],
6054 );
6055 }
6056 }
6057 }
6058
6059 Ok(did_resolve)
6060 })
6061 }
6062
6063 async fn resolve_completion_local(
6064 server: Arc<lsp::LanguageServer>,
6065 completions: Rc<RefCell<Box<[Completion]>>>,
6066 completion_index: usize,
6067 ) -> Result<()> {
6068 let server_id = server.server_id();
6069 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6070 return Ok(());
6071 }
6072
6073 let request = {
6074 let completion = &completions.borrow()[completion_index];
6075 match &completion.source {
6076 CompletionSource::Lsp {
6077 lsp_completion,
6078 resolved,
6079 server_id: completion_server_id,
6080 ..
6081 } => {
6082 if *resolved {
6083 return Ok(());
6084 }
6085 anyhow::ensure!(
6086 server_id == *completion_server_id,
6087 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6088 );
6089 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6090 }
6091 CompletionSource::BufferWord { .. }
6092 | CompletionSource::Dap { .. }
6093 | CompletionSource::Custom => {
6094 return Ok(());
6095 }
6096 }
6097 };
6098 let resolved_completion = request
6099 .await
6100 .into_response()
6101 .context("resolve completion")?;
6102
6103 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6104 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6105
6106 let mut completions = completions.borrow_mut();
6107 let completion = &mut completions[completion_index];
6108 if let CompletionSource::Lsp {
6109 lsp_completion,
6110 resolved,
6111 server_id: completion_server_id,
6112 ..
6113 } = &mut completion.source
6114 {
6115 if *resolved {
6116 return Ok(());
6117 }
6118 anyhow::ensure!(
6119 server_id == *completion_server_id,
6120 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6121 );
6122 *lsp_completion = Box::new(resolved_completion);
6123 *resolved = true;
6124 }
6125 Ok(())
6126 }
6127
6128 async fn regenerate_completion_labels(
6129 adapter: Arc<CachedLspAdapter>,
6130 snapshot: &BufferSnapshot,
6131 completions: Rc<RefCell<Box<[Completion]>>>,
6132 completion_index: usize,
6133 ) -> Result<()> {
6134 let completion_item = completions.borrow()[completion_index]
6135 .source
6136 .lsp_completion(true)
6137 .map(Cow::into_owned);
6138 if let Some(lsp_documentation) = completion_item
6139 .as_ref()
6140 .and_then(|completion_item| completion_item.documentation.clone())
6141 {
6142 let mut completions = completions.borrow_mut();
6143 let completion = &mut completions[completion_index];
6144 completion.documentation = Some(lsp_documentation.into());
6145 } else {
6146 let mut completions = completions.borrow_mut();
6147 let completion = &mut completions[completion_index];
6148 completion.documentation = Some(CompletionDocumentation::Undocumented);
6149 }
6150
6151 let mut new_label = match completion_item {
6152 Some(completion_item) => {
6153 // 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
6154 // So we have to update the label here anyway...
6155 let language = snapshot.language();
6156 match language {
6157 Some(language) => {
6158 adapter
6159 .labels_for_completions(
6160 std::slice::from_ref(&completion_item),
6161 language,
6162 )
6163 .await?
6164 }
6165 None => Vec::new(),
6166 }
6167 .pop()
6168 .flatten()
6169 .unwrap_or_else(|| {
6170 CodeLabel::fallback_for_completion(
6171 &completion_item,
6172 language.map(|language| language.as_ref()),
6173 )
6174 })
6175 }
6176 None => CodeLabel::plain(
6177 completions.borrow()[completion_index].new_text.clone(),
6178 None,
6179 ),
6180 };
6181 ensure_uniform_list_compatible_label(&mut new_label);
6182
6183 let mut completions = completions.borrow_mut();
6184 let completion = &mut completions[completion_index];
6185 if completion.label.filter_text() == new_label.filter_text() {
6186 completion.label = new_label;
6187 } else {
6188 log::error!(
6189 "Resolved completion changed display label from {} to {}. \
6190 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6191 completion.label.text(),
6192 new_label.text(),
6193 completion.label.filter_text(),
6194 new_label.filter_text()
6195 );
6196 }
6197
6198 Ok(())
6199 }
6200
6201 async fn resolve_completion_remote(
6202 project_id: u64,
6203 server_id: LanguageServerId,
6204 buffer_id: BufferId,
6205 completions: Rc<RefCell<Box<[Completion]>>>,
6206 completion_index: usize,
6207 client: AnyProtoClient,
6208 ) -> Result<()> {
6209 let lsp_completion = {
6210 let completion = &completions.borrow()[completion_index];
6211 match &completion.source {
6212 CompletionSource::Lsp {
6213 lsp_completion,
6214 resolved,
6215 server_id: completion_server_id,
6216 ..
6217 } => {
6218 anyhow::ensure!(
6219 server_id == *completion_server_id,
6220 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6221 );
6222 if *resolved {
6223 return Ok(());
6224 }
6225 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6226 }
6227 CompletionSource::Custom
6228 | CompletionSource::Dap { .. }
6229 | CompletionSource::BufferWord { .. } => {
6230 return Ok(());
6231 }
6232 }
6233 };
6234 let request = proto::ResolveCompletionDocumentation {
6235 project_id,
6236 language_server_id: server_id.0 as u64,
6237 lsp_completion,
6238 buffer_id: buffer_id.into(),
6239 };
6240
6241 let response = client
6242 .request(request)
6243 .await
6244 .context("completion documentation resolve proto request")?;
6245 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6246
6247 let documentation = if response.documentation.is_empty() {
6248 CompletionDocumentation::Undocumented
6249 } else if response.documentation_is_markdown {
6250 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6251 } else if response.documentation.lines().count() <= 1 {
6252 CompletionDocumentation::SingleLine(response.documentation.into())
6253 } else {
6254 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6255 };
6256
6257 let mut completions = completions.borrow_mut();
6258 let completion = &mut completions[completion_index];
6259 completion.documentation = Some(documentation);
6260 if let CompletionSource::Lsp {
6261 insert_range,
6262 lsp_completion,
6263 resolved,
6264 server_id: completion_server_id,
6265 lsp_defaults: _,
6266 } = &mut completion.source
6267 {
6268 let completion_insert_range = response
6269 .old_insert_start
6270 .and_then(deserialize_anchor)
6271 .zip(response.old_insert_end.and_then(deserialize_anchor));
6272 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6273
6274 if *resolved {
6275 return Ok(());
6276 }
6277 anyhow::ensure!(
6278 server_id == *completion_server_id,
6279 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6280 );
6281 *lsp_completion = Box::new(resolved_lsp_completion);
6282 *resolved = true;
6283 }
6284
6285 let replace_range = response
6286 .old_replace_start
6287 .and_then(deserialize_anchor)
6288 .zip(response.old_replace_end.and_then(deserialize_anchor));
6289 if let Some((old_replace_start, old_replace_end)) = replace_range
6290 && !response.new_text.is_empty()
6291 {
6292 completion.new_text = response.new_text;
6293 completion.replace_range = old_replace_start..old_replace_end;
6294 }
6295
6296 Ok(())
6297 }
6298
6299 pub fn apply_additional_edits_for_completion(
6300 &self,
6301 buffer_handle: Entity<Buffer>,
6302 completions: Rc<RefCell<Box<[Completion]>>>,
6303 completion_index: usize,
6304 push_to_history: bool,
6305 cx: &mut Context<Self>,
6306 ) -> Task<Result<Option<Transaction>>> {
6307 if let Some((client, project_id)) = self.upstream_client() {
6308 let buffer = buffer_handle.read(cx);
6309 let buffer_id = buffer.remote_id();
6310 cx.spawn(async move |_, cx| {
6311 let request = {
6312 let completion = completions.borrow()[completion_index].clone();
6313 proto::ApplyCompletionAdditionalEdits {
6314 project_id,
6315 buffer_id: buffer_id.into(),
6316 completion: Some(Self::serialize_completion(&CoreCompletion {
6317 replace_range: completion.replace_range,
6318 new_text: completion.new_text,
6319 source: completion.source,
6320 })),
6321 }
6322 };
6323
6324 if let Some(transaction) = client.request(request).await?.transaction {
6325 let transaction = language::proto::deserialize_transaction(transaction)?;
6326 buffer_handle
6327 .update(cx, |buffer, _| {
6328 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6329 })?
6330 .await?;
6331 if push_to_history {
6332 buffer_handle.update(cx, |buffer, _| {
6333 buffer.push_transaction(transaction.clone(), Instant::now());
6334 buffer.finalize_last_transaction();
6335 })?;
6336 }
6337 Ok(Some(transaction))
6338 } else {
6339 Ok(None)
6340 }
6341 })
6342 } else {
6343 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6344 let completion = &completions.borrow()[completion_index];
6345 let server_id = completion.source.server_id()?;
6346 Some(
6347 self.language_server_for_local_buffer(buffer, server_id, cx)?
6348 .1
6349 .clone(),
6350 )
6351 }) else {
6352 return Task::ready(Ok(None));
6353 };
6354
6355 cx.spawn(async move |this, cx| {
6356 Self::resolve_completion_local(
6357 server.clone(),
6358 completions.clone(),
6359 completion_index,
6360 )
6361 .await
6362 .context("resolving completion")?;
6363 let completion = completions.borrow()[completion_index].clone();
6364 let additional_text_edits = completion
6365 .source
6366 .lsp_completion(true)
6367 .as_ref()
6368 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6369 if let Some(edits) = additional_text_edits {
6370 let edits = this
6371 .update(cx, |this, cx| {
6372 this.as_local_mut().unwrap().edits_from_lsp(
6373 &buffer_handle,
6374 edits,
6375 server.server_id(),
6376 None,
6377 cx,
6378 )
6379 })?
6380 .await?;
6381
6382 buffer_handle.update(cx, |buffer, cx| {
6383 buffer.finalize_last_transaction();
6384 buffer.start_transaction();
6385
6386 for (range, text) in edits {
6387 let primary = &completion.replace_range;
6388
6389 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6390 // and the primary completion is just an insertion (empty range), then this is likely
6391 // an auto-import scenario and should not be considered overlapping
6392 // https://github.com/zed-industries/zed/issues/26136
6393 let is_file_start_auto_import = {
6394 let snapshot = buffer.snapshot();
6395 let primary_start_point = primary.start.to_point(&snapshot);
6396 let range_start_point = range.start.to_point(&snapshot);
6397
6398 let result = primary_start_point.row == 0
6399 && primary_start_point.column == 0
6400 && range_start_point.row == 0
6401 && range_start_point.column == 0;
6402
6403 result
6404 };
6405
6406 let has_overlap = if is_file_start_auto_import {
6407 false
6408 } else {
6409 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6410 && primary.end.cmp(&range.start, buffer).is_ge();
6411 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6412 && range.end.cmp(&primary.end, buffer).is_ge();
6413 let result = start_within || end_within;
6414 result
6415 };
6416
6417 //Skip additional edits which overlap with the primary completion edit
6418 //https://github.com/zed-industries/zed/pull/1871
6419 if !has_overlap {
6420 buffer.edit([(range, text)], None, cx);
6421 }
6422 }
6423
6424 let transaction = if buffer.end_transaction(cx).is_some() {
6425 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6426 if !push_to_history {
6427 buffer.forget_transaction(transaction.id);
6428 }
6429 Some(transaction)
6430 } else {
6431 None
6432 };
6433 Ok(transaction)
6434 })?
6435 } else {
6436 Ok(None)
6437 }
6438 })
6439 }
6440 }
6441
6442 pub fn pull_diagnostics(
6443 &mut self,
6444 buffer: Entity<Buffer>,
6445 cx: &mut Context<Self>,
6446 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6447 let buffer_id = buffer.read(cx).remote_id();
6448
6449 if let Some((client, upstream_project_id)) = self.upstream_client() {
6450 let request = GetDocumentDiagnostics {
6451 previous_result_id: None,
6452 };
6453 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6454 return Task::ready(Ok(None));
6455 }
6456 let request_task = client.request_lsp(
6457 upstream_project_id,
6458 None,
6459 LSP_REQUEST_TIMEOUT,
6460 cx.background_executor().clone(),
6461 request.to_proto(upstream_project_id, buffer.read(cx)),
6462 );
6463 cx.background_spawn(async move {
6464 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6465 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6466 // Do not attempt to further process the dummy responses here.
6467 let _response = request_task.await?;
6468 Ok(None)
6469 })
6470 } else {
6471 let server_ids = buffer.update(cx, |buffer, cx| {
6472 self.language_servers_for_local_buffer(buffer, cx)
6473 .map(|(_, server)| server.server_id())
6474 .collect::<Vec<_>>()
6475 });
6476 let pull_diagnostics = server_ids
6477 .into_iter()
6478 .map(|server_id| {
6479 let result_id = self.result_id(server_id, buffer_id, cx);
6480 self.request_lsp(
6481 buffer.clone(),
6482 LanguageServerToQuery::Other(server_id),
6483 GetDocumentDiagnostics {
6484 previous_result_id: result_id,
6485 },
6486 cx,
6487 )
6488 })
6489 .collect::<Vec<_>>();
6490
6491 cx.background_spawn(async move {
6492 let mut responses = Vec::new();
6493 for diagnostics in join_all(pull_diagnostics).await {
6494 responses.extend(diagnostics?);
6495 }
6496 Ok(Some(responses))
6497 })
6498 }
6499 }
6500
6501 pub fn applicable_inlay_chunks(
6502 &mut self,
6503 buffer: &Entity<Buffer>,
6504 ranges: &[Range<text::Anchor>],
6505 cx: &mut Context<Self>,
6506 ) -> Vec<Range<BufferRow>> {
6507 self.latest_lsp_data(buffer, cx)
6508 .inlay_hints
6509 .applicable_chunks(ranges)
6510 .map(|chunk| chunk.start..chunk.end)
6511 .collect()
6512 }
6513
6514 pub fn invalidate_inlay_hints<'a>(
6515 &'a mut self,
6516 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6517 ) {
6518 for buffer_id in for_buffers {
6519 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6520 lsp_data.inlay_hints.clear();
6521 }
6522 }
6523 }
6524
6525 pub fn inlay_hints(
6526 &mut self,
6527 invalidate: InvalidationStrategy,
6528 buffer: Entity<Buffer>,
6529 ranges: Vec<Range<text::Anchor>>,
6530 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6531 cx: &mut Context<Self>,
6532 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6533 let buffer_snapshot = buffer.read(cx).snapshot();
6534 let for_server = if let InvalidationStrategy::RefreshRequested(server_id) = invalidate {
6535 Some(server_id)
6536 } else {
6537 None
6538 };
6539 let invalidate_cache = invalidate.should_invalidate();
6540 let next_hint_id = self.next_hint_id.clone();
6541 let lsp_data = self.latest_lsp_data(&buffer, cx);
6542 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6543 let known_chunks = known_chunks
6544 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6545 .map(|(_, known_chunks)| known_chunks)
6546 .unwrap_or_default();
6547
6548 let mut hint_fetch_tasks = Vec::new();
6549 let mut cached_inlay_hints = HashMap::default();
6550 let mut ranges_to_query = Vec::new();
6551 let applicable_chunks = existing_inlay_hints
6552 .applicable_chunks(ranges.as_slice())
6553 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6554 .collect::<Vec<_>>();
6555 if applicable_chunks.is_empty() {
6556 return HashMap::default();
6557 }
6558
6559 let last_chunk_number = applicable_chunks.len() - 1;
6560
6561 for (i, row_chunk) in applicable_chunks.into_iter().enumerate() {
6562 match (
6563 existing_inlay_hints
6564 .cached_hints(&row_chunk)
6565 .filter(|_| !invalidate_cache)
6566 .cloned(),
6567 existing_inlay_hints
6568 .fetched_hints(&row_chunk)
6569 .as_ref()
6570 .filter(|_| !invalidate_cache)
6571 .cloned(),
6572 ) {
6573 (None, None) => {
6574 let end = if last_chunk_number == i {
6575 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6576 } else {
6577 Point::new(row_chunk.end, 0)
6578 };
6579 ranges_to_query.push((
6580 row_chunk,
6581 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6582 ..buffer_snapshot.anchor_after(end),
6583 ));
6584 }
6585 (None, Some(fetched_hints)) => {
6586 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()))
6587 }
6588 (Some(cached_hints), None) => {
6589 for (server_id, cached_hints) in cached_hints {
6590 if for_server.is_none_or(|for_server| for_server == server_id) {
6591 cached_inlay_hints
6592 .entry(row_chunk.start..row_chunk.end)
6593 .or_insert_with(HashMap::default)
6594 .entry(server_id)
6595 .or_insert_with(Vec::new)
6596 .extend(cached_hints);
6597 }
6598 }
6599 }
6600 (Some(cached_hints), Some(fetched_hints)) => {
6601 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()));
6602 for (server_id, cached_hints) in cached_hints {
6603 if for_server.is_none_or(|for_server| for_server == server_id) {
6604 cached_inlay_hints
6605 .entry(row_chunk.start..row_chunk.end)
6606 .or_insert_with(HashMap::default)
6607 .entry(server_id)
6608 .or_insert_with(Vec::new)
6609 .extend(cached_hints);
6610 }
6611 }
6612 }
6613 }
6614 }
6615
6616 let cached_chunk_data = cached_inlay_hints
6617 .into_iter()
6618 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6619 .collect();
6620 if hint_fetch_tasks.is_empty() && ranges_to_query.is_empty() {
6621 cached_chunk_data
6622 } else {
6623 if invalidate_cache {
6624 lsp_data.inlay_hints.clear();
6625 }
6626
6627 for (chunk, range_to_query) in ranges_to_query {
6628 let next_hint_id = next_hint_id.clone();
6629 let buffer = buffer.clone();
6630 let new_inlay_hints = cx
6631 .spawn(async move |lsp_store, cx| {
6632 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6633 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6634 })?;
6635 new_fetch_task
6636 .await
6637 .and_then(|new_hints_by_server| {
6638 lsp_store.update(cx, |lsp_store, cx| {
6639 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6640 let update_cache = !lsp_data
6641 .buffer_version
6642 .changed_since(&buffer.read(cx).version());
6643 new_hints_by_server
6644 .into_iter()
6645 .map(|(server_id, new_hints)| {
6646 let new_hints = new_hints
6647 .into_iter()
6648 .map(|new_hint| {
6649 (
6650 InlayId::Hint(next_hint_id.fetch_add(
6651 1,
6652 atomic::Ordering::AcqRel,
6653 )),
6654 new_hint,
6655 )
6656 })
6657 .collect::<Vec<_>>();
6658 if update_cache {
6659 lsp_data.inlay_hints.insert_new_hints(
6660 chunk,
6661 server_id,
6662 new_hints.clone(),
6663 );
6664 }
6665 (server_id, new_hints)
6666 })
6667 .collect()
6668 })
6669 })
6670 .map_err(Arc::new)
6671 })
6672 .shared();
6673
6674 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6675 *fetch_task = Some(new_inlay_hints.clone());
6676 hint_fetch_tasks.push((chunk, new_inlay_hints));
6677 }
6678
6679 let mut combined_data = cached_chunk_data;
6680 combined_data.extend(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6681 (
6682 chunk.start..chunk.end,
6683 cx.spawn(async move |_, _| {
6684 hints_fetch.await.map_err(|e| {
6685 if e.error_code() != ErrorCode::Internal {
6686 anyhow!(e.error_code())
6687 } else {
6688 anyhow!("{e:#}")
6689 }
6690 })
6691 }),
6692 )
6693 }));
6694 combined_data
6695 }
6696 }
6697
6698 fn fetch_inlay_hints(
6699 &mut self,
6700 for_server: Option<LanguageServerId>,
6701 buffer: &Entity<Buffer>,
6702 range: Range<Anchor>,
6703 cx: &mut Context<Self>,
6704 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6705 let request = InlayHints {
6706 range: range.clone(),
6707 };
6708 if let Some((upstream_client, project_id)) = self.upstream_client() {
6709 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6710 return Task::ready(Ok(HashMap::default()));
6711 }
6712 let request_task = upstream_client.request_lsp(
6713 project_id,
6714 for_server.map(|id| id.to_proto()),
6715 LSP_REQUEST_TIMEOUT,
6716 cx.background_executor().clone(),
6717 request.to_proto(project_id, buffer.read(cx)),
6718 );
6719 let buffer = buffer.clone();
6720 cx.spawn(async move |weak_lsp_store, cx| {
6721 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6722 return Ok(HashMap::default());
6723 };
6724 let Some(responses) = request_task.await? else {
6725 return Ok(HashMap::default());
6726 };
6727
6728 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6729 let lsp_store = lsp_store.clone();
6730 let buffer = buffer.clone();
6731 let cx = cx.clone();
6732 let request = request.clone();
6733 async move {
6734 (
6735 LanguageServerId::from_proto(response.server_id),
6736 request
6737 .response_from_proto(response.response, lsp_store, buffer, cx)
6738 .await,
6739 )
6740 }
6741 }))
6742 .await;
6743
6744 let mut has_errors = false;
6745 let inlay_hints = inlay_hints
6746 .into_iter()
6747 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6748 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6749 Err(e) => {
6750 has_errors = true;
6751 log::error!("{e:#}");
6752 None
6753 }
6754 })
6755 .collect::<HashMap<_, _>>();
6756 anyhow::ensure!(
6757 !has_errors || !inlay_hints.is_empty(),
6758 "Failed to fetch inlay hints"
6759 );
6760 Ok(inlay_hints)
6761 })
6762 } else {
6763 let inlay_hints_task = match for_server {
6764 Some(server_id) => {
6765 let server_task = self.request_lsp(
6766 buffer.clone(),
6767 LanguageServerToQuery::Other(server_id),
6768 request,
6769 cx,
6770 );
6771 cx.background_spawn(async move {
6772 let mut responses = Vec::new();
6773 match server_task.await {
6774 Ok(response) => responses.push((server_id, response)),
6775 Err(e) => log::error!(
6776 "Error handling response for inlay hints request: {e:#}"
6777 ),
6778 }
6779 responses
6780 })
6781 }
6782 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6783 };
6784 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6785 cx.background_spawn(async move {
6786 Ok(inlay_hints_task
6787 .await
6788 .into_iter()
6789 .map(|(server_id, mut new_hints)| {
6790 new_hints.retain(|hint| {
6791 hint.position.is_valid(&buffer_snapshot)
6792 && range.start.is_valid(&buffer_snapshot)
6793 && range.end.is_valid(&buffer_snapshot)
6794 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6795 && hint.position.cmp(&range.end, &buffer_snapshot).is_le()
6796 });
6797 (server_id, new_hints)
6798 })
6799 .collect())
6800 })
6801 }
6802 }
6803
6804 pub fn pull_diagnostics_for_buffer(
6805 &mut self,
6806 buffer: Entity<Buffer>,
6807 cx: &mut Context<Self>,
6808 ) -> Task<anyhow::Result<()>> {
6809 let diagnostics = self.pull_diagnostics(buffer, cx);
6810 cx.spawn(async move |lsp_store, cx| {
6811 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6812 return Ok(());
6813 };
6814 lsp_store.update(cx, |lsp_store, cx| {
6815 if lsp_store.as_local().is_none() {
6816 return;
6817 }
6818
6819 let mut unchanged_buffers = HashSet::default();
6820 let mut changed_buffers = HashSet::default();
6821 let server_diagnostics_updates = diagnostics
6822 .into_iter()
6823 .filter_map(|diagnostics_set| match diagnostics_set {
6824 LspPullDiagnostics::Response {
6825 server_id,
6826 uri,
6827 diagnostics,
6828 } => Some((server_id, uri, diagnostics)),
6829 LspPullDiagnostics::Default => None,
6830 })
6831 .fold(
6832 HashMap::default(),
6833 |mut acc, (server_id, uri, diagnostics)| {
6834 let (result_id, diagnostics) = match diagnostics {
6835 PulledDiagnostics::Unchanged { result_id } => {
6836 unchanged_buffers.insert(uri.clone());
6837 (Some(result_id), Vec::new())
6838 }
6839 PulledDiagnostics::Changed {
6840 result_id,
6841 diagnostics,
6842 } => {
6843 changed_buffers.insert(uri.clone());
6844 (result_id, diagnostics)
6845 }
6846 };
6847 let disk_based_sources = Cow::Owned(
6848 lsp_store
6849 .language_server_adapter_for_id(server_id)
6850 .as_ref()
6851 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6852 .unwrap_or(&[])
6853 .to_vec(),
6854 );
6855 acc.entry(server_id).or_insert_with(Vec::new).push(
6856 DocumentDiagnosticsUpdate {
6857 server_id,
6858 diagnostics: lsp::PublishDiagnosticsParams {
6859 uri,
6860 diagnostics,
6861 version: None,
6862 },
6863 result_id,
6864 disk_based_sources,
6865 },
6866 );
6867 acc
6868 },
6869 );
6870
6871 for diagnostic_updates in server_diagnostics_updates.into_values() {
6872 lsp_store
6873 .merge_lsp_diagnostics(
6874 DiagnosticSourceKind::Pulled,
6875 diagnostic_updates,
6876 |buffer, old_diagnostic, cx| {
6877 File::from_dyn(buffer.file())
6878 .and_then(|file| {
6879 let abs_path = file.as_local()?.abs_path(cx);
6880 lsp::Uri::from_file_path(abs_path).ok()
6881 })
6882 .is_none_or(|buffer_uri| {
6883 unchanged_buffers.contains(&buffer_uri)
6884 || match old_diagnostic.source_kind {
6885 DiagnosticSourceKind::Pulled => {
6886 !changed_buffers.contains(&buffer_uri)
6887 }
6888 DiagnosticSourceKind::Other
6889 | DiagnosticSourceKind::Pushed => true,
6890 }
6891 })
6892 },
6893 cx,
6894 )
6895 .log_err();
6896 }
6897 })
6898 })
6899 }
6900
6901 pub fn document_colors(
6902 &mut self,
6903 known_cache_version: Option<usize>,
6904 buffer: Entity<Buffer>,
6905 cx: &mut Context<Self>,
6906 ) -> Option<DocumentColorTask> {
6907 let version_queried_for = buffer.read(cx).version();
6908 let buffer_id = buffer.read(cx).remote_id();
6909
6910 let current_language_servers = self.as_local().map(|local| {
6911 local
6912 .buffers_opened_in_servers
6913 .get(&buffer_id)
6914 .cloned()
6915 .unwrap_or_default()
6916 });
6917
6918 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6919 if let Some(cached_colors) = &lsp_data.document_colors {
6920 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6921 let has_different_servers =
6922 current_language_servers.is_some_and(|current_language_servers| {
6923 current_language_servers
6924 != cached_colors.colors.keys().copied().collect()
6925 });
6926 if !has_different_servers {
6927 let cache_version = cached_colors.cache_version;
6928 if Some(cache_version) == known_cache_version {
6929 return None;
6930 } else {
6931 return Some(
6932 Task::ready(Ok(DocumentColors {
6933 colors: cached_colors
6934 .colors
6935 .values()
6936 .flatten()
6937 .cloned()
6938 .collect(),
6939 cache_version: Some(cache_version),
6940 }))
6941 .shared(),
6942 );
6943 }
6944 }
6945 }
6946 }
6947 }
6948
6949 let color_lsp_data = self
6950 .latest_lsp_data(&buffer, cx)
6951 .document_colors
6952 .get_or_insert_default();
6953 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
6954 && !version_queried_for.changed_since(updating_for)
6955 {
6956 return Some(running_update.clone());
6957 }
6958 let buffer_version_queried_for = version_queried_for.clone();
6959 let new_task = cx
6960 .spawn(async move |lsp_store, cx| {
6961 cx.background_executor()
6962 .timer(Duration::from_millis(30))
6963 .await;
6964 let fetched_colors = lsp_store
6965 .update(cx, |lsp_store, cx| {
6966 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6967 })?
6968 .await
6969 .context("fetching document colors")
6970 .map_err(Arc::new);
6971 let fetched_colors = match fetched_colors {
6972 Ok(fetched_colors) => {
6973 if Some(true)
6974 == buffer
6975 .update(cx, |buffer, _| {
6976 buffer.version() != buffer_version_queried_for
6977 })
6978 .ok()
6979 {
6980 return Ok(DocumentColors::default());
6981 }
6982 fetched_colors
6983 }
6984 Err(e) => {
6985 lsp_store
6986 .update(cx, |lsp_store, _| {
6987 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
6988 if let Some(document_colors) = &mut lsp_data.document_colors {
6989 document_colors.colors_update = None;
6990 }
6991 }
6992 })
6993 .ok();
6994 return Err(e);
6995 }
6996 };
6997
6998 lsp_store
6999 .update(cx, |lsp_store, cx| {
7000 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7001 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7002
7003 if let Some(fetched_colors) = fetched_colors {
7004 if lsp_data.buffer_version == buffer_version_queried_for {
7005 lsp_colors.colors.extend(fetched_colors);
7006 lsp_colors.cache_version += 1;
7007 } else if !lsp_data
7008 .buffer_version
7009 .changed_since(&buffer_version_queried_for)
7010 {
7011 lsp_data.buffer_version = buffer_version_queried_for;
7012 lsp_colors.colors = fetched_colors;
7013 lsp_colors.cache_version += 1;
7014 }
7015 }
7016 lsp_colors.colors_update = None;
7017 let colors = lsp_colors
7018 .colors
7019 .values()
7020 .flatten()
7021 .cloned()
7022 .collect::<HashSet<_>>();
7023 DocumentColors {
7024 colors,
7025 cache_version: Some(lsp_colors.cache_version),
7026 }
7027 })
7028 .map_err(Arc::new)
7029 })
7030 .shared();
7031 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7032 Some(new_task)
7033 }
7034
7035 fn fetch_document_colors_for_buffer(
7036 &mut self,
7037 buffer: &Entity<Buffer>,
7038 cx: &mut Context<Self>,
7039 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7040 if let Some((client, project_id)) = self.upstream_client() {
7041 let request = GetDocumentColor {};
7042 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7043 return Task::ready(Ok(None));
7044 }
7045
7046 let request_task = client.request_lsp(
7047 project_id,
7048 None,
7049 LSP_REQUEST_TIMEOUT,
7050 cx.background_executor().clone(),
7051 request.to_proto(project_id, buffer.read(cx)),
7052 );
7053 let buffer = buffer.clone();
7054 cx.spawn(async move |lsp_store, cx| {
7055 let Some(project) = lsp_store.upgrade() else {
7056 return Ok(None);
7057 };
7058 let colors = join_all(
7059 request_task
7060 .await
7061 .log_err()
7062 .flatten()
7063 .map(|response| response.payload)
7064 .unwrap_or_default()
7065 .into_iter()
7066 .map(|color_response| {
7067 let response = request.response_from_proto(
7068 color_response.response,
7069 project.clone(),
7070 buffer.clone(),
7071 cx.clone(),
7072 );
7073 async move {
7074 (
7075 LanguageServerId::from_proto(color_response.server_id),
7076 response.await.log_err().unwrap_or_default(),
7077 )
7078 }
7079 }),
7080 )
7081 .await
7082 .into_iter()
7083 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7084 acc.entry(server_id)
7085 .or_insert_with(HashSet::default)
7086 .extend(colors);
7087 acc
7088 });
7089 Ok(Some(colors))
7090 })
7091 } else {
7092 let document_colors_task =
7093 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7094 cx.background_spawn(async move {
7095 Ok(Some(
7096 document_colors_task
7097 .await
7098 .into_iter()
7099 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7100 acc.entry(server_id)
7101 .or_insert_with(HashSet::default)
7102 .extend(colors);
7103 acc
7104 })
7105 .into_iter()
7106 .collect(),
7107 ))
7108 })
7109 }
7110 }
7111
7112 pub fn signature_help<T: ToPointUtf16>(
7113 &mut self,
7114 buffer: &Entity<Buffer>,
7115 position: T,
7116 cx: &mut Context<Self>,
7117 ) -> Task<Option<Vec<SignatureHelp>>> {
7118 let position = position.to_point_utf16(buffer.read(cx));
7119
7120 if let Some((client, upstream_project_id)) = self.upstream_client() {
7121 let request = GetSignatureHelp { position };
7122 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7123 return Task::ready(None);
7124 }
7125 let request_task = client.request_lsp(
7126 upstream_project_id,
7127 None,
7128 LSP_REQUEST_TIMEOUT,
7129 cx.background_executor().clone(),
7130 request.to_proto(upstream_project_id, buffer.read(cx)),
7131 );
7132 let buffer = buffer.clone();
7133 cx.spawn(async move |weak_project, cx| {
7134 let project = weak_project.upgrade()?;
7135 let signatures = join_all(
7136 request_task
7137 .await
7138 .log_err()
7139 .flatten()
7140 .map(|response| response.payload)
7141 .unwrap_or_default()
7142 .into_iter()
7143 .map(|response| {
7144 let response = GetSignatureHelp { position }.response_from_proto(
7145 response.response,
7146 project.clone(),
7147 buffer.clone(),
7148 cx.clone(),
7149 );
7150 async move { response.await.log_err().flatten() }
7151 }),
7152 )
7153 .await
7154 .into_iter()
7155 .flatten()
7156 .collect();
7157 Some(signatures)
7158 })
7159 } else {
7160 let all_actions_task = self.request_multiple_lsp_locally(
7161 buffer,
7162 Some(position),
7163 GetSignatureHelp { position },
7164 cx,
7165 );
7166 cx.background_spawn(async move {
7167 Some(
7168 all_actions_task
7169 .await
7170 .into_iter()
7171 .flat_map(|(_, actions)| actions)
7172 .collect::<Vec<_>>(),
7173 )
7174 })
7175 }
7176 }
7177
7178 pub fn hover(
7179 &mut self,
7180 buffer: &Entity<Buffer>,
7181 position: PointUtf16,
7182 cx: &mut Context<Self>,
7183 ) -> Task<Option<Vec<Hover>>> {
7184 if let Some((client, upstream_project_id)) = self.upstream_client() {
7185 let request = GetHover { position };
7186 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7187 return Task::ready(None);
7188 }
7189 let request_task = client.request_lsp(
7190 upstream_project_id,
7191 None,
7192 LSP_REQUEST_TIMEOUT,
7193 cx.background_executor().clone(),
7194 request.to_proto(upstream_project_id, buffer.read(cx)),
7195 );
7196 let buffer = buffer.clone();
7197 cx.spawn(async move |weak_project, cx| {
7198 let project = weak_project.upgrade()?;
7199 let hovers = join_all(
7200 request_task
7201 .await
7202 .log_err()
7203 .flatten()
7204 .map(|response| response.payload)
7205 .unwrap_or_default()
7206 .into_iter()
7207 .map(|response| {
7208 let response = GetHover { position }.response_from_proto(
7209 response.response,
7210 project.clone(),
7211 buffer.clone(),
7212 cx.clone(),
7213 );
7214 async move {
7215 response
7216 .await
7217 .log_err()
7218 .flatten()
7219 .and_then(remove_empty_hover_blocks)
7220 }
7221 }),
7222 )
7223 .await
7224 .into_iter()
7225 .flatten()
7226 .collect();
7227 Some(hovers)
7228 })
7229 } else {
7230 let all_actions_task = self.request_multiple_lsp_locally(
7231 buffer,
7232 Some(position),
7233 GetHover { position },
7234 cx,
7235 );
7236 cx.background_spawn(async move {
7237 Some(
7238 all_actions_task
7239 .await
7240 .into_iter()
7241 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7242 .collect::<Vec<Hover>>(),
7243 )
7244 })
7245 }
7246 }
7247
7248 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7249 let language_registry = self.languages.clone();
7250
7251 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7252 let request = upstream_client.request(proto::GetProjectSymbols {
7253 project_id: *project_id,
7254 query: query.to_string(),
7255 });
7256 cx.foreground_executor().spawn(async move {
7257 let response = request.await?;
7258 let mut symbols = Vec::new();
7259 let core_symbols = response
7260 .symbols
7261 .into_iter()
7262 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7263 .collect::<Vec<_>>();
7264 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7265 .await;
7266 Ok(symbols)
7267 })
7268 } else if let Some(local) = self.as_local() {
7269 struct WorkspaceSymbolsResult {
7270 server_id: LanguageServerId,
7271 lsp_adapter: Arc<CachedLspAdapter>,
7272 worktree: WeakEntity<Worktree>,
7273 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7274 }
7275
7276 let mut requests = Vec::new();
7277 let mut requested_servers = BTreeSet::new();
7278 for (seed, state) in local.language_server_ids.iter() {
7279 let Some(worktree_handle) = self
7280 .worktree_store
7281 .read(cx)
7282 .worktree_for_id(seed.worktree_id, cx)
7283 else {
7284 continue;
7285 };
7286 let worktree = worktree_handle.read(cx);
7287 if !worktree.is_visible() {
7288 continue;
7289 }
7290
7291 if !requested_servers.insert(state.id) {
7292 continue;
7293 }
7294
7295 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7296 Some(LanguageServerState::Running {
7297 adapter, server, ..
7298 }) => (adapter.clone(), server),
7299
7300 _ => continue,
7301 };
7302 let supports_workspace_symbol_request =
7303 match server.capabilities().workspace_symbol_provider {
7304 Some(OneOf::Left(supported)) => supported,
7305 Some(OneOf::Right(_)) => true,
7306 None => false,
7307 };
7308 if !supports_workspace_symbol_request {
7309 continue;
7310 }
7311 let worktree_handle = worktree_handle.clone();
7312 let server_id = server.server_id();
7313 requests.push(
7314 server
7315 .request::<lsp::request::WorkspaceSymbolRequest>(
7316 lsp::WorkspaceSymbolParams {
7317 query: query.to_string(),
7318 ..Default::default()
7319 },
7320 )
7321 .map(move |response| {
7322 let lsp_symbols = response.into_response()
7323 .context("workspace symbols request")
7324 .log_err()
7325 .flatten()
7326 .map(|symbol_response| match symbol_response {
7327 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7328 flat_responses.into_iter().map(|lsp_symbol| {
7329 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7330 }).collect::<Vec<_>>()
7331 }
7332 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7333 nested_responses.into_iter().filter_map(|lsp_symbol| {
7334 let location = match lsp_symbol.location {
7335 OneOf::Left(location) => location,
7336 OneOf::Right(_) => {
7337 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7338 return None
7339 }
7340 };
7341 Some((lsp_symbol.name, lsp_symbol.kind, location))
7342 }).collect::<Vec<_>>()
7343 }
7344 }).unwrap_or_default();
7345
7346 WorkspaceSymbolsResult {
7347 server_id,
7348 lsp_adapter,
7349 worktree: worktree_handle.downgrade(),
7350 lsp_symbols,
7351 }
7352 }),
7353 );
7354 }
7355
7356 cx.spawn(async move |this, cx| {
7357 let responses = futures::future::join_all(requests).await;
7358 let this = match this.upgrade() {
7359 Some(this) => this,
7360 None => return Ok(Vec::new()),
7361 };
7362
7363 let mut symbols = Vec::new();
7364 for result in responses {
7365 let core_symbols = this.update(cx, |this, cx| {
7366 result
7367 .lsp_symbols
7368 .into_iter()
7369 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7370 let abs_path = symbol_location.uri.to_file_path().ok()?;
7371 let source_worktree = result.worktree.upgrade()?;
7372 let source_worktree_id = source_worktree.read(cx).id();
7373
7374 let path = if let Some((tree, rel_path)) =
7375 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7376 {
7377 let worktree_id = tree.read(cx).id();
7378 SymbolLocation::InProject(ProjectPath {
7379 worktree_id,
7380 path: rel_path,
7381 })
7382 } else {
7383 SymbolLocation::OutsideProject {
7384 signature: this.symbol_signature(&abs_path),
7385 abs_path: abs_path.into(),
7386 }
7387 };
7388
7389 Some(CoreSymbol {
7390 source_language_server_id: result.server_id,
7391 language_server_name: result.lsp_adapter.name.clone(),
7392 source_worktree_id,
7393 path,
7394 kind: symbol_kind,
7395 name: symbol_name,
7396 range: range_from_lsp(symbol_location.range),
7397 })
7398 })
7399 .collect()
7400 })?;
7401
7402 populate_labels_for_symbols(
7403 core_symbols,
7404 &language_registry,
7405 Some(result.lsp_adapter),
7406 &mut symbols,
7407 )
7408 .await;
7409 }
7410
7411 Ok(symbols)
7412 })
7413 } else {
7414 Task::ready(Err(anyhow!("No upstream client or local language server")))
7415 }
7416 }
7417
7418 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7419 let mut summary = DiagnosticSummary::default();
7420 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7421 summary.error_count += path_summary.error_count;
7422 summary.warning_count += path_summary.warning_count;
7423 }
7424 summary
7425 }
7426
7427 /// Returns the diagnostic summary for a specific project path.
7428 pub fn diagnostic_summary_for_path(
7429 &self,
7430 project_path: &ProjectPath,
7431 _: &App,
7432 ) -> DiagnosticSummary {
7433 if let Some(summaries) = self
7434 .diagnostic_summaries
7435 .get(&project_path.worktree_id)
7436 .and_then(|map| map.get(&project_path.path))
7437 {
7438 let (error_count, warning_count) = summaries.iter().fold(
7439 (0, 0),
7440 |(error_count, warning_count), (_language_server_id, summary)| {
7441 (
7442 error_count + summary.error_count,
7443 warning_count + summary.warning_count,
7444 )
7445 },
7446 );
7447
7448 DiagnosticSummary {
7449 error_count,
7450 warning_count,
7451 }
7452 } else {
7453 DiagnosticSummary::default()
7454 }
7455 }
7456
7457 pub fn diagnostic_summaries<'a>(
7458 &'a self,
7459 include_ignored: bool,
7460 cx: &'a App,
7461 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7462 self.worktree_store
7463 .read(cx)
7464 .visible_worktrees(cx)
7465 .filter_map(|worktree| {
7466 let worktree = worktree.read(cx);
7467 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7468 })
7469 .flat_map(move |(worktree, summaries)| {
7470 let worktree_id = worktree.id();
7471 summaries
7472 .iter()
7473 .filter(move |(path, _)| {
7474 include_ignored
7475 || worktree
7476 .entry_for_path(path.as_ref())
7477 .is_some_and(|entry| !entry.is_ignored)
7478 })
7479 .flat_map(move |(path, summaries)| {
7480 summaries.iter().map(move |(server_id, summary)| {
7481 (
7482 ProjectPath {
7483 worktree_id,
7484 path: path.clone(),
7485 },
7486 *server_id,
7487 *summary,
7488 )
7489 })
7490 })
7491 })
7492 }
7493
7494 pub fn on_buffer_edited(
7495 &mut self,
7496 buffer: Entity<Buffer>,
7497 cx: &mut Context<Self>,
7498 ) -> Option<()> {
7499 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7500 Some(
7501 self.as_local()?
7502 .language_servers_for_buffer(buffer, cx)
7503 .map(|i| i.1.clone())
7504 .collect(),
7505 )
7506 })?;
7507
7508 let buffer = buffer.read(cx);
7509 let file = File::from_dyn(buffer.file())?;
7510 let abs_path = file.as_local()?.abs_path(cx);
7511 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7512 let next_snapshot = buffer.text_snapshot();
7513 for language_server in language_servers {
7514 let language_server = language_server.clone();
7515
7516 let buffer_snapshots = self
7517 .as_local_mut()
7518 .unwrap()
7519 .buffer_snapshots
7520 .get_mut(&buffer.remote_id())
7521 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7522 let previous_snapshot = buffer_snapshots.last()?;
7523
7524 let build_incremental_change = || {
7525 let line_ending = next_snapshot.line_ending();
7526 buffer
7527 .edits_since::<Dimensions<PointUtf16, usize>>(
7528 previous_snapshot.snapshot.version(),
7529 )
7530 .map(|edit| {
7531 let edit_start = edit.new.start.0;
7532 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7533 lsp::TextDocumentContentChangeEvent {
7534 range: Some(lsp::Range::new(
7535 point_to_lsp(edit_start),
7536 point_to_lsp(edit_end),
7537 )),
7538 range_length: None,
7539 // Collect changed text and preserve line endings.
7540 // text_for_range returns chunks with normalized \n, so we need to
7541 // convert to the buffer's actual line ending for LSP.
7542 text: line_ending.into_string(
7543 next_snapshot.text_for_range(edit.new.start.1..edit.new.end.1),
7544 ),
7545 }
7546 })
7547 .collect()
7548 };
7549
7550 let document_sync_kind = language_server
7551 .capabilities()
7552 .text_document_sync
7553 .as_ref()
7554 .and_then(|sync| match sync {
7555 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7556 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7557 });
7558
7559 let content_changes: Vec<_> = match document_sync_kind {
7560 Some(lsp::TextDocumentSyncKind::FULL) => {
7561 vec![lsp::TextDocumentContentChangeEvent {
7562 range: None,
7563 range_length: None,
7564 text: next_snapshot.text_with_original_line_endings(),
7565 }]
7566 }
7567 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7568 _ => {
7569 #[cfg(any(test, feature = "test-support"))]
7570 {
7571 build_incremental_change()
7572 }
7573
7574 #[cfg(not(any(test, feature = "test-support")))]
7575 {
7576 continue;
7577 }
7578 }
7579 };
7580
7581 let next_version = previous_snapshot.version + 1;
7582 buffer_snapshots.push(LspBufferSnapshot {
7583 version: next_version,
7584 snapshot: next_snapshot.clone(),
7585 });
7586
7587 language_server
7588 .notify::<lsp::notification::DidChangeTextDocument>(
7589 lsp::DidChangeTextDocumentParams {
7590 text_document: lsp::VersionedTextDocumentIdentifier::new(
7591 uri.clone(),
7592 next_version,
7593 ),
7594 content_changes,
7595 },
7596 )
7597 .ok();
7598 self.pull_workspace_diagnostics(language_server.server_id());
7599 }
7600
7601 None
7602 }
7603
7604 pub fn on_buffer_saved(
7605 &mut self,
7606 buffer: Entity<Buffer>,
7607 cx: &mut Context<Self>,
7608 ) -> Option<()> {
7609 let file = File::from_dyn(buffer.read(cx).file())?;
7610 let worktree_id = file.worktree_id(cx);
7611 let abs_path = file.as_local()?.abs_path(cx);
7612 let text_document = lsp::TextDocumentIdentifier {
7613 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7614 };
7615 let local = self.as_local()?;
7616
7617 for server in local.language_servers_for_worktree(worktree_id) {
7618 if let Some(include_text) = include_text(server.as_ref()) {
7619 let text = if include_text {
7620 Some(buffer.read(cx).text())
7621 } else {
7622 None
7623 };
7624 server
7625 .notify::<lsp::notification::DidSaveTextDocument>(
7626 lsp::DidSaveTextDocumentParams {
7627 text_document: text_document.clone(),
7628 text,
7629 },
7630 )
7631 .ok();
7632 }
7633 }
7634
7635 let language_servers = buffer.update(cx, |buffer, cx| {
7636 local.language_server_ids_for_buffer(buffer, cx)
7637 });
7638 for language_server_id in language_servers {
7639 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7640 }
7641
7642 None
7643 }
7644
7645 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7646 maybe!(async move {
7647 let mut refreshed_servers = HashSet::default();
7648 let servers = lsp_store
7649 .update(cx, |lsp_store, cx| {
7650 let local = lsp_store.as_local()?;
7651
7652 let servers = local
7653 .language_server_ids
7654 .iter()
7655 .filter_map(|(seed, state)| {
7656 let worktree = lsp_store
7657 .worktree_store
7658 .read(cx)
7659 .worktree_for_id(seed.worktree_id, cx);
7660 let delegate: Arc<dyn LspAdapterDelegate> =
7661 worktree.map(|worktree| {
7662 LocalLspAdapterDelegate::new(
7663 local.languages.clone(),
7664 &local.environment,
7665 cx.weak_entity(),
7666 &worktree,
7667 local.http_client.clone(),
7668 local.fs.clone(),
7669 cx,
7670 )
7671 })?;
7672 let server_id = state.id;
7673
7674 let states = local.language_servers.get(&server_id)?;
7675
7676 match states {
7677 LanguageServerState::Starting { .. } => None,
7678 LanguageServerState::Running {
7679 adapter, server, ..
7680 } => {
7681 let adapter = adapter.clone();
7682 let server = server.clone();
7683 refreshed_servers.insert(server.name());
7684 let toolchain = seed.toolchain.clone();
7685 Some(cx.spawn(async move |_, cx| {
7686 let settings =
7687 LocalLspStore::workspace_configuration_for_adapter(
7688 adapter.adapter.clone(),
7689 &delegate,
7690 toolchain,
7691 cx,
7692 )
7693 .await
7694 .ok()?;
7695 server
7696 .notify::<lsp::notification::DidChangeConfiguration>(
7697 lsp::DidChangeConfigurationParams { settings },
7698 )
7699 .ok()?;
7700 Some(())
7701 }))
7702 }
7703 }
7704 })
7705 .collect::<Vec<_>>();
7706
7707 Some(servers)
7708 })
7709 .ok()
7710 .flatten()?;
7711
7712 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7713 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7714 // to stop and unregister its language server wrapper.
7715 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7716 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7717 let _: Vec<Option<()>> = join_all(servers).await;
7718
7719 Some(())
7720 })
7721 .await;
7722 }
7723
7724 fn maintain_workspace_config(
7725 external_refresh_requests: watch::Receiver<()>,
7726 cx: &mut Context<Self>,
7727 ) -> Task<Result<()>> {
7728 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7729 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7730
7731 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7732 *settings_changed_tx.borrow_mut() = ();
7733 });
7734
7735 let mut joint_future =
7736 futures::stream::select(settings_changed_rx, external_refresh_requests);
7737 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7738 // - 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).
7739 // - 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.
7740 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7741 // - 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,
7742 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7743 cx.spawn(async move |this, cx| {
7744 while let Some(()) = joint_future.next().await {
7745 this.update(cx, |this, cx| {
7746 this.refresh_server_tree(cx);
7747 })
7748 .ok();
7749
7750 Self::refresh_workspace_configurations(&this, cx).await;
7751 }
7752
7753 drop(settings_observation);
7754 anyhow::Ok(())
7755 })
7756 }
7757
7758 pub fn language_servers_for_local_buffer<'a>(
7759 &'a self,
7760 buffer: &Buffer,
7761 cx: &mut App,
7762 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7763 let local = self.as_local();
7764 let language_server_ids = local
7765 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7766 .unwrap_or_default();
7767
7768 language_server_ids
7769 .into_iter()
7770 .filter_map(
7771 move |server_id| match local?.language_servers.get(&server_id)? {
7772 LanguageServerState::Running {
7773 adapter, server, ..
7774 } => Some((adapter, server)),
7775 _ => None,
7776 },
7777 )
7778 }
7779
7780 pub fn language_server_for_local_buffer<'a>(
7781 &'a self,
7782 buffer: &'a Buffer,
7783 server_id: LanguageServerId,
7784 cx: &'a mut App,
7785 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7786 self.as_local()?
7787 .language_servers_for_buffer(buffer, cx)
7788 .find(|(_, s)| s.server_id() == server_id)
7789 }
7790
7791 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7792 self.diagnostic_summaries.remove(&id_to_remove);
7793 if let Some(local) = self.as_local_mut() {
7794 let to_remove = local.remove_worktree(id_to_remove, cx);
7795 for server in to_remove {
7796 self.language_server_statuses.remove(&server);
7797 }
7798 }
7799 }
7800
7801 pub fn shared(
7802 &mut self,
7803 project_id: u64,
7804 downstream_client: AnyProtoClient,
7805 _: &mut Context<Self>,
7806 ) {
7807 self.downstream_client = Some((downstream_client.clone(), project_id));
7808
7809 for (server_id, status) in &self.language_server_statuses {
7810 if let Some(server) = self.language_server_for_id(*server_id) {
7811 downstream_client
7812 .send(proto::StartLanguageServer {
7813 project_id,
7814 server: Some(proto::LanguageServer {
7815 id: server_id.to_proto(),
7816 name: status.name.to_string(),
7817 worktree_id: status.worktree.map(|id| id.to_proto()),
7818 }),
7819 capabilities: serde_json::to_string(&server.capabilities())
7820 .expect("serializing server LSP capabilities"),
7821 })
7822 .log_err();
7823 }
7824 }
7825 }
7826
7827 pub fn disconnected_from_host(&mut self) {
7828 self.downstream_client.take();
7829 }
7830
7831 pub fn disconnected_from_ssh_remote(&mut self) {
7832 if let LspStoreMode::Remote(RemoteLspStore {
7833 upstream_client, ..
7834 }) = &mut self.mode
7835 {
7836 upstream_client.take();
7837 }
7838 }
7839
7840 pub(crate) fn set_language_server_statuses_from_proto(
7841 &mut self,
7842 project: WeakEntity<Project>,
7843 language_servers: Vec<proto::LanguageServer>,
7844 server_capabilities: Vec<String>,
7845 cx: &mut Context<Self>,
7846 ) {
7847 let lsp_logs = cx
7848 .try_global::<GlobalLogStore>()
7849 .map(|lsp_store| lsp_store.0.clone());
7850
7851 self.language_server_statuses = language_servers
7852 .into_iter()
7853 .zip(server_capabilities)
7854 .map(|(server, server_capabilities)| {
7855 let server_id = LanguageServerId(server.id as usize);
7856 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7857 self.lsp_server_capabilities
7858 .insert(server_id, server_capabilities);
7859 }
7860
7861 let name = LanguageServerName::from_proto(server.name);
7862 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7863
7864 if let Some(lsp_logs) = &lsp_logs {
7865 lsp_logs.update(cx, |lsp_logs, cx| {
7866 lsp_logs.add_language_server(
7867 // Only remote clients get their language servers set from proto
7868 LanguageServerKind::Remote {
7869 project: project.clone(),
7870 },
7871 server_id,
7872 Some(name.clone()),
7873 worktree,
7874 None,
7875 cx,
7876 );
7877 });
7878 }
7879
7880 (
7881 server_id,
7882 LanguageServerStatus {
7883 name,
7884 pending_work: Default::default(),
7885 has_pending_diagnostic_updates: false,
7886 progress_tokens: Default::default(),
7887 worktree,
7888 },
7889 )
7890 })
7891 .collect();
7892 }
7893
7894 #[cfg(test)]
7895 pub fn update_diagnostic_entries(
7896 &mut self,
7897 server_id: LanguageServerId,
7898 abs_path: PathBuf,
7899 result_id: Option<String>,
7900 version: Option<i32>,
7901 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7902 cx: &mut Context<Self>,
7903 ) -> anyhow::Result<()> {
7904 self.merge_diagnostic_entries(
7905 vec![DocumentDiagnosticsUpdate {
7906 diagnostics: DocumentDiagnostics {
7907 diagnostics,
7908 document_abs_path: abs_path,
7909 version,
7910 },
7911 result_id,
7912 server_id,
7913 disk_based_sources: Cow::Borrowed(&[]),
7914 }],
7915 |_, _, _| false,
7916 cx,
7917 )?;
7918 Ok(())
7919 }
7920
7921 pub fn merge_diagnostic_entries<'a>(
7922 &mut self,
7923 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7924 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7925 cx: &mut Context<Self>,
7926 ) -> anyhow::Result<()> {
7927 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7928 let mut updated_diagnostics_paths = HashMap::default();
7929 for mut update in diagnostic_updates {
7930 let abs_path = &update.diagnostics.document_abs_path;
7931 let server_id = update.server_id;
7932 let Some((worktree, relative_path)) =
7933 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7934 else {
7935 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7936 return Ok(());
7937 };
7938
7939 let worktree_id = worktree.read(cx).id();
7940 let project_path = ProjectPath {
7941 worktree_id,
7942 path: relative_path,
7943 };
7944
7945 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7946 let snapshot = buffer_handle.read(cx).snapshot();
7947 let buffer = buffer_handle.read(cx);
7948 let reused_diagnostics = buffer
7949 .buffer_diagnostics(Some(server_id))
7950 .iter()
7951 .filter(|v| merge(buffer, &v.diagnostic, cx))
7952 .map(|v| {
7953 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7954 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7955 DiagnosticEntry {
7956 range: start..end,
7957 diagnostic: v.diagnostic.clone(),
7958 }
7959 })
7960 .collect::<Vec<_>>();
7961
7962 self.as_local_mut()
7963 .context("cannot merge diagnostics on a remote LspStore")?
7964 .update_buffer_diagnostics(
7965 &buffer_handle,
7966 server_id,
7967 update.result_id,
7968 update.diagnostics.version,
7969 update.diagnostics.diagnostics.clone(),
7970 reused_diagnostics.clone(),
7971 cx,
7972 )?;
7973
7974 update.diagnostics.diagnostics.extend(reused_diagnostics);
7975 }
7976
7977 let updated = worktree.update(cx, |worktree, cx| {
7978 self.update_worktree_diagnostics(
7979 worktree.id(),
7980 server_id,
7981 project_path.path.clone(),
7982 update.diagnostics.diagnostics,
7983 cx,
7984 )
7985 })?;
7986 match updated {
7987 ControlFlow::Continue(new_summary) => {
7988 if let Some((project_id, new_summary)) = new_summary {
7989 match &mut diagnostics_summary {
7990 Some(diagnostics_summary) => {
7991 diagnostics_summary
7992 .more_summaries
7993 .push(proto::DiagnosticSummary {
7994 path: project_path.path.as_ref().to_proto(),
7995 language_server_id: server_id.0 as u64,
7996 error_count: new_summary.error_count,
7997 warning_count: new_summary.warning_count,
7998 })
7999 }
8000 None => {
8001 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8002 project_id,
8003 worktree_id: worktree_id.to_proto(),
8004 summary: Some(proto::DiagnosticSummary {
8005 path: project_path.path.as_ref().to_proto(),
8006 language_server_id: server_id.0 as u64,
8007 error_count: new_summary.error_count,
8008 warning_count: new_summary.warning_count,
8009 }),
8010 more_summaries: Vec::new(),
8011 })
8012 }
8013 }
8014 }
8015 updated_diagnostics_paths
8016 .entry(server_id)
8017 .or_insert_with(Vec::new)
8018 .push(project_path);
8019 }
8020 ControlFlow::Break(()) => {}
8021 }
8022 }
8023
8024 if let Some((diagnostics_summary, (downstream_client, _))) =
8025 diagnostics_summary.zip(self.downstream_client.as_ref())
8026 {
8027 downstream_client.send(diagnostics_summary).log_err();
8028 }
8029 for (server_id, paths) in updated_diagnostics_paths {
8030 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8031 }
8032 Ok(())
8033 }
8034
8035 fn update_worktree_diagnostics(
8036 &mut self,
8037 worktree_id: WorktreeId,
8038 server_id: LanguageServerId,
8039 path_in_worktree: Arc<RelPath>,
8040 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8041 _: &mut Context<Worktree>,
8042 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8043 let local = match &mut self.mode {
8044 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8045 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8046 };
8047
8048 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8049 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8050 let summaries_by_server_id = summaries_for_tree
8051 .entry(path_in_worktree.clone())
8052 .or_default();
8053
8054 let old_summary = summaries_by_server_id
8055 .remove(&server_id)
8056 .unwrap_or_default();
8057
8058 let new_summary = DiagnosticSummary::new(&diagnostics);
8059 if new_summary.is_empty() {
8060 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8061 {
8062 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8063 diagnostics_by_server_id.remove(ix);
8064 }
8065 if diagnostics_by_server_id.is_empty() {
8066 diagnostics_for_tree.remove(&path_in_worktree);
8067 }
8068 }
8069 } else {
8070 summaries_by_server_id.insert(server_id, new_summary);
8071 let diagnostics_by_server_id = diagnostics_for_tree
8072 .entry(path_in_worktree.clone())
8073 .or_default();
8074 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8075 Ok(ix) => {
8076 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8077 }
8078 Err(ix) => {
8079 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8080 }
8081 }
8082 }
8083
8084 if !old_summary.is_empty() || !new_summary.is_empty() {
8085 if let Some((_, project_id)) = &self.downstream_client {
8086 Ok(ControlFlow::Continue(Some((
8087 *project_id,
8088 proto::DiagnosticSummary {
8089 path: path_in_worktree.to_proto(),
8090 language_server_id: server_id.0 as u64,
8091 error_count: new_summary.error_count as u32,
8092 warning_count: new_summary.warning_count as u32,
8093 },
8094 ))))
8095 } else {
8096 Ok(ControlFlow::Continue(None))
8097 }
8098 } else {
8099 Ok(ControlFlow::Break(()))
8100 }
8101 }
8102
8103 pub fn open_buffer_for_symbol(
8104 &mut self,
8105 symbol: &Symbol,
8106 cx: &mut Context<Self>,
8107 ) -> Task<Result<Entity<Buffer>>> {
8108 if let Some((client, project_id)) = self.upstream_client() {
8109 let request = client.request(proto::OpenBufferForSymbol {
8110 project_id,
8111 symbol: Some(Self::serialize_symbol(symbol)),
8112 });
8113 cx.spawn(async move |this, cx| {
8114 let response = request.await?;
8115 let buffer_id = BufferId::new(response.buffer_id)?;
8116 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8117 .await
8118 })
8119 } else if let Some(local) = self.as_local() {
8120 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8121 seed.worktree_id == symbol.source_worktree_id
8122 && state.id == symbol.source_language_server_id
8123 && symbol.language_server_name == seed.name
8124 });
8125 if !is_valid {
8126 return Task::ready(Err(anyhow!(
8127 "language server for worktree and language not found"
8128 )));
8129 };
8130
8131 let symbol_abs_path = match &symbol.path {
8132 SymbolLocation::InProject(project_path) => self
8133 .worktree_store
8134 .read(cx)
8135 .absolutize(&project_path, cx)
8136 .context("no such worktree"),
8137 SymbolLocation::OutsideProject {
8138 abs_path,
8139 signature: _,
8140 } => Ok(abs_path.to_path_buf()),
8141 };
8142 let symbol_abs_path = match symbol_abs_path {
8143 Ok(abs_path) => abs_path,
8144 Err(err) => return Task::ready(Err(err)),
8145 };
8146 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8147 uri
8148 } else {
8149 return Task::ready(Err(anyhow!("invalid symbol path")));
8150 };
8151
8152 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8153 } else {
8154 Task::ready(Err(anyhow!("no upstream client or local store")))
8155 }
8156 }
8157
8158 pub(crate) fn open_local_buffer_via_lsp(
8159 &mut self,
8160 abs_path: lsp::Uri,
8161 language_server_id: LanguageServerId,
8162 cx: &mut Context<Self>,
8163 ) -> Task<Result<Entity<Buffer>>> {
8164 cx.spawn(async move |lsp_store, cx| {
8165 // Escape percent-encoded string.
8166 let current_scheme = abs_path.scheme().to_owned();
8167 // Uri is immutable, so we can't modify the scheme
8168
8169 let abs_path = abs_path
8170 .to_file_path()
8171 .map_err(|()| anyhow!("can't convert URI to path"))?;
8172 let p = abs_path.clone();
8173 let yarn_worktree = lsp_store
8174 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8175 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8176 cx.spawn(async move |this, cx| {
8177 let t = this
8178 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8179 .ok()?;
8180 t.await
8181 })
8182 }),
8183 None => Task::ready(None),
8184 })?
8185 .await;
8186 let (worktree_root_target, known_relative_path) =
8187 if let Some((zip_root, relative_path)) = yarn_worktree {
8188 (zip_root, Some(relative_path))
8189 } else {
8190 (Arc::<Path>::from(abs_path.as_path()), None)
8191 };
8192 let (worktree, relative_path) = if let Some(result) =
8193 lsp_store.update(cx, |lsp_store, cx| {
8194 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8195 worktree_store.find_worktree(&worktree_root_target, cx)
8196 })
8197 })? {
8198 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8199 (result.0, relative_path)
8200 } else {
8201 let worktree = lsp_store
8202 .update(cx, |lsp_store, cx| {
8203 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8204 worktree_store.create_worktree(&worktree_root_target, false, cx)
8205 })
8206 })?
8207 .await?;
8208 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8209 lsp_store
8210 .update(cx, |lsp_store, cx| {
8211 if let Some(local) = lsp_store.as_local_mut() {
8212 local.register_language_server_for_invisible_worktree(
8213 &worktree,
8214 language_server_id,
8215 cx,
8216 )
8217 }
8218 })
8219 .ok();
8220 }
8221 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8222 let relative_path = if let Some(known_path) = known_relative_path {
8223 known_path
8224 } else {
8225 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8226 .into_arc()
8227 };
8228 (worktree, relative_path)
8229 };
8230 let project_path = ProjectPath {
8231 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8232 path: relative_path,
8233 };
8234 lsp_store
8235 .update(cx, |lsp_store, cx| {
8236 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8237 buffer_store.open_buffer(project_path, cx)
8238 })
8239 })?
8240 .await
8241 })
8242 }
8243
8244 fn request_multiple_lsp_locally<P, R>(
8245 &mut self,
8246 buffer: &Entity<Buffer>,
8247 position: Option<P>,
8248 request: R,
8249 cx: &mut Context<Self>,
8250 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8251 where
8252 P: ToOffset,
8253 R: LspCommand + Clone,
8254 <R::LspRequest as lsp::request::Request>::Result: Send,
8255 <R::LspRequest as lsp::request::Request>::Params: Send,
8256 {
8257 let Some(local) = self.as_local() else {
8258 return Task::ready(Vec::new());
8259 };
8260
8261 let snapshot = buffer.read(cx).snapshot();
8262 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8263
8264 let server_ids = buffer.update(cx, |buffer, cx| {
8265 local
8266 .language_servers_for_buffer(buffer, cx)
8267 .filter(|(adapter, _)| {
8268 scope
8269 .as_ref()
8270 .map(|scope| scope.language_allowed(&adapter.name))
8271 .unwrap_or(true)
8272 })
8273 .map(|(_, server)| server.server_id())
8274 .filter(|server_id| {
8275 self.as_local().is_none_or(|local| {
8276 local
8277 .buffers_opened_in_servers
8278 .get(&snapshot.remote_id())
8279 .is_some_and(|servers| servers.contains(server_id))
8280 })
8281 })
8282 .collect::<Vec<_>>()
8283 });
8284
8285 let mut response_results = server_ids
8286 .into_iter()
8287 .map(|server_id| {
8288 let task = self.request_lsp(
8289 buffer.clone(),
8290 LanguageServerToQuery::Other(server_id),
8291 request.clone(),
8292 cx,
8293 );
8294 async move { (server_id, task.await) }
8295 })
8296 .collect::<FuturesUnordered<_>>();
8297
8298 cx.background_spawn(async move {
8299 let mut responses = Vec::with_capacity(response_results.len());
8300 while let Some((server_id, response_result)) = response_results.next().await {
8301 match response_result {
8302 Ok(response) => responses.push((server_id, response)),
8303 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8304 }
8305 }
8306 responses
8307 })
8308 }
8309
8310 async fn handle_lsp_command<T: LspCommand>(
8311 this: Entity<Self>,
8312 envelope: TypedEnvelope<T::ProtoRequest>,
8313 mut cx: AsyncApp,
8314 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8315 where
8316 <T::LspRequest as lsp::request::Request>::Params: Send,
8317 <T::LspRequest as lsp::request::Request>::Result: Send,
8318 {
8319 let sender_id = envelope.original_sender_id().unwrap_or_default();
8320 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8321 let buffer_handle = this.update(&mut cx, |this, cx| {
8322 this.buffer_store.read(cx).get_existing(buffer_id)
8323 })??;
8324 let request = T::from_proto(
8325 envelope.payload,
8326 this.clone(),
8327 buffer_handle.clone(),
8328 cx.clone(),
8329 )
8330 .await?;
8331 let response = this
8332 .update(&mut cx, |this, cx| {
8333 this.request_lsp(
8334 buffer_handle.clone(),
8335 LanguageServerToQuery::FirstCapable,
8336 request,
8337 cx,
8338 )
8339 })?
8340 .await?;
8341 this.update(&mut cx, |this, cx| {
8342 Ok(T::response_to_proto(
8343 response,
8344 this,
8345 sender_id,
8346 &buffer_handle.read(cx).version(),
8347 cx,
8348 ))
8349 })?
8350 }
8351
8352 async fn handle_lsp_query(
8353 lsp_store: Entity<Self>,
8354 envelope: TypedEnvelope<proto::LspQuery>,
8355 mut cx: AsyncApp,
8356 ) -> Result<proto::Ack> {
8357 use proto::lsp_query::Request;
8358 let sender_id = envelope.original_sender_id().unwrap_or_default();
8359 let lsp_query = envelope.payload;
8360 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8361 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8362 match lsp_query.request.context("invalid LSP query request")? {
8363 Request::GetReferences(get_references) => {
8364 let position = get_references.position.clone().and_then(deserialize_anchor);
8365 Self::query_lsp_locally::<GetReferences>(
8366 lsp_store,
8367 server_id,
8368 sender_id,
8369 lsp_request_id,
8370 get_references,
8371 position,
8372 &mut cx,
8373 )
8374 .await?;
8375 }
8376 Request::GetDocumentColor(get_document_color) => {
8377 Self::query_lsp_locally::<GetDocumentColor>(
8378 lsp_store,
8379 server_id,
8380 sender_id,
8381 lsp_request_id,
8382 get_document_color,
8383 None,
8384 &mut cx,
8385 )
8386 .await?;
8387 }
8388 Request::GetHover(get_hover) => {
8389 let position = get_hover.position.clone().and_then(deserialize_anchor);
8390 Self::query_lsp_locally::<GetHover>(
8391 lsp_store,
8392 server_id,
8393 sender_id,
8394 lsp_request_id,
8395 get_hover,
8396 position,
8397 &mut cx,
8398 )
8399 .await?;
8400 }
8401 Request::GetCodeActions(get_code_actions) => {
8402 Self::query_lsp_locally::<GetCodeActions>(
8403 lsp_store,
8404 server_id,
8405 sender_id,
8406 lsp_request_id,
8407 get_code_actions,
8408 None,
8409 &mut cx,
8410 )
8411 .await?;
8412 }
8413 Request::GetSignatureHelp(get_signature_help) => {
8414 let position = get_signature_help
8415 .position
8416 .clone()
8417 .and_then(deserialize_anchor);
8418 Self::query_lsp_locally::<GetSignatureHelp>(
8419 lsp_store,
8420 server_id,
8421 sender_id,
8422 lsp_request_id,
8423 get_signature_help,
8424 position,
8425 &mut cx,
8426 )
8427 .await?;
8428 }
8429 Request::GetCodeLens(get_code_lens) => {
8430 Self::query_lsp_locally::<GetCodeLens>(
8431 lsp_store,
8432 server_id,
8433 sender_id,
8434 lsp_request_id,
8435 get_code_lens,
8436 None,
8437 &mut cx,
8438 )
8439 .await?;
8440 }
8441 Request::GetDefinition(get_definition) => {
8442 let position = get_definition.position.clone().and_then(deserialize_anchor);
8443 Self::query_lsp_locally::<GetDefinitions>(
8444 lsp_store,
8445 server_id,
8446 sender_id,
8447 lsp_request_id,
8448 get_definition,
8449 position,
8450 &mut cx,
8451 )
8452 .await?;
8453 }
8454 Request::GetDeclaration(get_declaration) => {
8455 let position = get_declaration
8456 .position
8457 .clone()
8458 .and_then(deserialize_anchor);
8459 Self::query_lsp_locally::<GetDeclarations>(
8460 lsp_store,
8461 server_id,
8462 sender_id,
8463 lsp_request_id,
8464 get_declaration,
8465 position,
8466 &mut cx,
8467 )
8468 .await?;
8469 }
8470 Request::GetTypeDefinition(get_type_definition) => {
8471 let position = get_type_definition
8472 .position
8473 .clone()
8474 .and_then(deserialize_anchor);
8475 Self::query_lsp_locally::<GetTypeDefinitions>(
8476 lsp_store,
8477 server_id,
8478 sender_id,
8479 lsp_request_id,
8480 get_type_definition,
8481 position,
8482 &mut cx,
8483 )
8484 .await?;
8485 }
8486 Request::GetImplementation(get_implementation) => {
8487 let position = get_implementation
8488 .position
8489 .clone()
8490 .and_then(deserialize_anchor);
8491 Self::query_lsp_locally::<GetImplementations>(
8492 lsp_store,
8493 server_id,
8494 sender_id,
8495 lsp_request_id,
8496 get_implementation,
8497 position,
8498 &mut cx,
8499 )
8500 .await?;
8501 }
8502 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8503 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8504 let version = deserialize_version(get_document_diagnostics.buffer_version());
8505 let buffer = lsp_store.update(&mut cx, |this, cx| {
8506 this.buffer_store.read(cx).get_existing(buffer_id)
8507 })??;
8508 buffer
8509 .update(&mut cx, |buffer, _| {
8510 buffer.wait_for_version(version.clone())
8511 })?
8512 .await?;
8513 lsp_store.update(&mut cx, |lsp_store, cx| {
8514 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8515 let key = LspKey {
8516 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8517 server_queried: server_id,
8518 };
8519 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8520 ) {
8521 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8522 lsp_requests.clear();
8523 };
8524 }
8525
8526 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8527 existing_queries.insert(
8528 lsp_request_id,
8529 cx.spawn(async move |lsp_store, cx| {
8530 let diagnostics_pull = lsp_store
8531 .update(cx, |lsp_store, cx| {
8532 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8533 })
8534 .ok();
8535 if let Some(diagnostics_pull) = diagnostics_pull {
8536 match diagnostics_pull.await {
8537 Ok(()) => {}
8538 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8539 };
8540 }
8541 }),
8542 );
8543 })?;
8544 }
8545 Request::InlayHints(inlay_hints) => {
8546 let query_start = inlay_hints
8547 .start
8548 .clone()
8549 .and_then(deserialize_anchor)
8550 .context("invalid inlay hints range start")?;
8551 let query_end = inlay_hints
8552 .end
8553 .clone()
8554 .and_then(deserialize_anchor)
8555 .context("invalid inlay hints range end")?;
8556 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8557 &lsp_store,
8558 server_id,
8559 lsp_request_id,
8560 &inlay_hints,
8561 query_start..query_end,
8562 &mut cx,
8563 )
8564 .await
8565 .context("preparing inlay hints request")?;
8566 Self::query_lsp_locally::<InlayHints>(
8567 lsp_store,
8568 server_id,
8569 sender_id,
8570 lsp_request_id,
8571 inlay_hints,
8572 None,
8573 &mut cx,
8574 )
8575 .await
8576 .context("querying for inlay hints")?
8577 }
8578 }
8579 Ok(proto::Ack {})
8580 }
8581
8582 async fn handle_lsp_query_response(
8583 lsp_store: Entity<Self>,
8584 envelope: TypedEnvelope<proto::LspQueryResponse>,
8585 cx: AsyncApp,
8586 ) -> Result<()> {
8587 lsp_store.read_with(&cx, |lsp_store, _| {
8588 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8589 upstream_client.handle_lsp_response(envelope.clone());
8590 }
8591 })?;
8592 Ok(())
8593 }
8594
8595 async fn handle_apply_code_action(
8596 this: Entity<Self>,
8597 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8598 mut cx: AsyncApp,
8599 ) -> Result<proto::ApplyCodeActionResponse> {
8600 let sender_id = envelope.original_sender_id().unwrap_or_default();
8601 let action =
8602 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8603 let apply_code_action = this.update(&mut cx, |this, cx| {
8604 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8605 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8606 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8607 })??;
8608
8609 let project_transaction = apply_code_action.await?;
8610 let project_transaction = this.update(&mut cx, |this, cx| {
8611 this.buffer_store.update(cx, |buffer_store, cx| {
8612 buffer_store.serialize_project_transaction_for_peer(
8613 project_transaction,
8614 sender_id,
8615 cx,
8616 )
8617 })
8618 })?;
8619 Ok(proto::ApplyCodeActionResponse {
8620 transaction: Some(project_transaction),
8621 })
8622 }
8623
8624 async fn handle_register_buffer_with_language_servers(
8625 this: Entity<Self>,
8626 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8627 mut cx: AsyncApp,
8628 ) -> Result<proto::Ack> {
8629 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8630 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8631 this.update(&mut cx, |this, cx| {
8632 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8633 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8634 project_id: upstream_project_id,
8635 buffer_id: buffer_id.to_proto(),
8636 only_servers: envelope.payload.only_servers,
8637 });
8638 }
8639
8640 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8641 anyhow::bail!("buffer is not open");
8642 };
8643
8644 let handle = this.register_buffer_with_language_servers(
8645 &buffer,
8646 envelope
8647 .payload
8648 .only_servers
8649 .into_iter()
8650 .filter_map(|selector| {
8651 Some(match selector.selector? {
8652 proto::language_server_selector::Selector::ServerId(server_id) => {
8653 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8654 }
8655 proto::language_server_selector::Selector::Name(name) => {
8656 LanguageServerSelector::Name(LanguageServerName(
8657 SharedString::from(name),
8658 ))
8659 }
8660 })
8661 })
8662 .collect(),
8663 false,
8664 cx,
8665 );
8666 this.buffer_store().update(cx, |buffer_store, _| {
8667 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8668 });
8669
8670 Ok(())
8671 })??;
8672 Ok(proto::Ack {})
8673 }
8674
8675 async fn handle_rename_project_entry(
8676 this: Entity<Self>,
8677 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8678 mut cx: AsyncApp,
8679 ) -> Result<proto::ProjectEntryResponse> {
8680 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8681 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8682 let new_path =
8683 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8684
8685 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8686 .update(&mut cx, |this, cx| {
8687 let (worktree, entry) = this
8688 .worktree_store
8689 .read(cx)
8690 .worktree_and_entry_for_id(entry_id, cx)?;
8691 let new_worktree = this
8692 .worktree_store
8693 .read(cx)
8694 .worktree_for_id(new_worktree_id, cx)?;
8695 Some((
8696 this.worktree_store.clone(),
8697 worktree,
8698 new_worktree,
8699 entry.clone(),
8700 ))
8701 })?
8702 .context("worktree not found")?;
8703 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8704 (worktree.absolutize(&old_entry.path), worktree.id())
8705 })?;
8706 let new_abs_path =
8707 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8708
8709 let _transaction = Self::will_rename_entry(
8710 this.downgrade(),
8711 old_worktree_id,
8712 &old_abs_path,
8713 &new_abs_path,
8714 old_entry.is_dir(),
8715 cx.clone(),
8716 )
8717 .await;
8718 let response = WorktreeStore::handle_rename_project_entry(
8719 worktree_store,
8720 envelope.payload,
8721 cx.clone(),
8722 )
8723 .await;
8724 this.read_with(&cx, |this, _| {
8725 this.did_rename_entry(
8726 old_worktree_id,
8727 &old_abs_path,
8728 &new_abs_path,
8729 old_entry.is_dir(),
8730 );
8731 })
8732 .ok();
8733 response
8734 }
8735
8736 async fn handle_update_diagnostic_summary(
8737 this: Entity<Self>,
8738 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8739 mut cx: AsyncApp,
8740 ) -> Result<()> {
8741 this.update(&mut cx, |lsp_store, cx| {
8742 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8743 let mut updated_diagnostics_paths = HashMap::default();
8744 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8745 for message_summary in envelope
8746 .payload
8747 .summary
8748 .into_iter()
8749 .chain(envelope.payload.more_summaries)
8750 {
8751 let project_path = ProjectPath {
8752 worktree_id,
8753 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8754 };
8755 let path = project_path.path.clone();
8756 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8757 let summary = DiagnosticSummary {
8758 error_count: message_summary.error_count as usize,
8759 warning_count: message_summary.warning_count as usize,
8760 };
8761
8762 if summary.is_empty() {
8763 if let Some(worktree_summaries) =
8764 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8765 && let Some(summaries) = worktree_summaries.get_mut(&path)
8766 {
8767 summaries.remove(&server_id);
8768 if summaries.is_empty() {
8769 worktree_summaries.remove(&path);
8770 }
8771 }
8772 } else {
8773 lsp_store
8774 .diagnostic_summaries
8775 .entry(worktree_id)
8776 .or_default()
8777 .entry(path)
8778 .or_default()
8779 .insert(server_id, summary);
8780 }
8781
8782 if let Some((_, project_id)) = &lsp_store.downstream_client {
8783 match &mut diagnostics_summary {
8784 Some(diagnostics_summary) => {
8785 diagnostics_summary
8786 .more_summaries
8787 .push(proto::DiagnosticSummary {
8788 path: project_path.path.as_ref().to_proto(),
8789 language_server_id: server_id.0 as u64,
8790 error_count: summary.error_count as u32,
8791 warning_count: summary.warning_count as u32,
8792 })
8793 }
8794 None => {
8795 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8796 project_id: *project_id,
8797 worktree_id: worktree_id.to_proto(),
8798 summary: Some(proto::DiagnosticSummary {
8799 path: project_path.path.as_ref().to_proto(),
8800 language_server_id: server_id.0 as u64,
8801 error_count: summary.error_count as u32,
8802 warning_count: summary.warning_count as u32,
8803 }),
8804 more_summaries: Vec::new(),
8805 })
8806 }
8807 }
8808 }
8809 updated_diagnostics_paths
8810 .entry(server_id)
8811 .or_insert_with(Vec::new)
8812 .push(project_path);
8813 }
8814
8815 if let Some((diagnostics_summary, (downstream_client, _))) =
8816 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8817 {
8818 downstream_client.send(diagnostics_summary).log_err();
8819 }
8820 for (server_id, paths) in updated_diagnostics_paths {
8821 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8822 }
8823 Ok(())
8824 })?
8825 }
8826
8827 async fn handle_start_language_server(
8828 lsp_store: Entity<Self>,
8829 envelope: TypedEnvelope<proto::StartLanguageServer>,
8830 mut cx: AsyncApp,
8831 ) -> Result<()> {
8832 let server = envelope.payload.server.context("invalid server")?;
8833 let server_capabilities =
8834 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8835 .with_context(|| {
8836 format!(
8837 "incorrect server capabilities {}",
8838 envelope.payload.capabilities
8839 )
8840 })?;
8841 lsp_store.update(&mut cx, |lsp_store, cx| {
8842 let server_id = LanguageServerId(server.id as usize);
8843 let server_name = LanguageServerName::from_proto(server.name.clone());
8844 lsp_store
8845 .lsp_server_capabilities
8846 .insert(server_id, server_capabilities);
8847 lsp_store.language_server_statuses.insert(
8848 server_id,
8849 LanguageServerStatus {
8850 name: server_name.clone(),
8851 pending_work: Default::default(),
8852 has_pending_diagnostic_updates: false,
8853 progress_tokens: Default::default(),
8854 worktree: server.worktree_id.map(WorktreeId::from_proto),
8855 },
8856 );
8857 cx.emit(LspStoreEvent::LanguageServerAdded(
8858 server_id,
8859 server_name,
8860 server.worktree_id.map(WorktreeId::from_proto),
8861 ));
8862 cx.notify();
8863 })?;
8864 Ok(())
8865 }
8866
8867 async fn handle_update_language_server(
8868 lsp_store: Entity<Self>,
8869 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8870 mut cx: AsyncApp,
8871 ) -> Result<()> {
8872 lsp_store.update(&mut cx, |lsp_store, cx| {
8873 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8874
8875 match envelope.payload.variant.context("invalid variant")? {
8876 proto::update_language_server::Variant::WorkStart(payload) => {
8877 lsp_store.on_lsp_work_start(
8878 language_server_id,
8879 payload.token,
8880 LanguageServerProgress {
8881 title: payload.title,
8882 is_disk_based_diagnostics_progress: false,
8883 is_cancellable: payload.is_cancellable.unwrap_or(false),
8884 message: payload.message,
8885 percentage: payload.percentage.map(|p| p as usize),
8886 last_update_at: cx.background_executor().now(),
8887 },
8888 cx,
8889 );
8890 }
8891 proto::update_language_server::Variant::WorkProgress(payload) => {
8892 lsp_store.on_lsp_work_progress(
8893 language_server_id,
8894 payload.token,
8895 LanguageServerProgress {
8896 title: None,
8897 is_disk_based_diagnostics_progress: false,
8898 is_cancellable: payload.is_cancellable.unwrap_or(false),
8899 message: payload.message,
8900 percentage: payload.percentage.map(|p| p as usize),
8901 last_update_at: cx.background_executor().now(),
8902 },
8903 cx,
8904 );
8905 }
8906
8907 proto::update_language_server::Variant::WorkEnd(payload) => {
8908 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8909 }
8910
8911 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8912 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8913 }
8914
8915 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8916 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8917 }
8918
8919 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8920 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8921 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8922 cx.emit(LspStoreEvent::LanguageServerUpdate {
8923 language_server_id,
8924 name: envelope
8925 .payload
8926 .server_name
8927 .map(SharedString::new)
8928 .map(LanguageServerName),
8929 message: non_lsp,
8930 });
8931 }
8932 }
8933
8934 Ok(())
8935 })?
8936 }
8937
8938 async fn handle_language_server_log(
8939 this: Entity<Self>,
8940 envelope: TypedEnvelope<proto::LanguageServerLog>,
8941 mut cx: AsyncApp,
8942 ) -> Result<()> {
8943 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8944 let log_type = envelope
8945 .payload
8946 .log_type
8947 .map(LanguageServerLogType::from_proto)
8948 .context("invalid language server log type")?;
8949
8950 let message = envelope.payload.message;
8951
8952 this.update(&mut cx, |_, cx| {
8953 cx.emit(LspStoreEvent::LanguageServerLog(
8954 language_server_id,
8955 log_type,
8956 message,
8957 ));
8958 })
8959 }
8960
8961 async fn handle_lsp_ext_cancel_flycheck(
8962 lsp_store: Entity<Self>,
8963 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8964 cx: AsyncApp,
8965 ) -> Result<proto::Ack> {
8966 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8967 let task = lsp_store.read_with(&cx, |lsp_store, _| {
8968 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8969 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
8970 } else {
8971 None
8972 }
8973 })?;
8974 if let Some(task) = task {
8975 task.context("handling lsp ext cancel flycheck")?;
8976 }
8977
8978 Ok(proto::Ack {})
8979 }
8980
8981 async fn handle_lsp_ext_run_flycheck(
8982 lsp_store: Entity<Self>,
8983 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8984 mut cx: AsyncApp,
8985 ) -> Result<proto::Ack> {
8986 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8987 lsp_store.update(&mut cx, |lsp_store, cx| {
8988 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8989 let text_document = if envelope.payload.current_file_only {
8990 let buffer_id = envelope
8991 .payload
8992 .buffer_id
8993 .map(|id| BufferId::new(id))
8994 .transpose()?;
8995 buffer_id
8996 .and_then(|buffer_id| {
8997 lsp_store
8998 .buffer_store()
8999 .read(cx)
9000 .get(buffer_id)
9001 .and_then(|buffer| {
9002 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9003 })
9004 .map(|path| make_text_document_identifier(&path))
9005 })
9006 .transpose()?
9007 } else {
9008 None
9009 };
9010 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9011 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9012 )?;
9013 }
9014 anyhow::Ok(())
9015 })??;
9016
9017 Ok(proto::Ack {})
9018 }
9019
9020 async fn handle_lsp_ext_clear_flycheck(
9021 lsp_store: Entity<Self>,
9022 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9023 cx: AsyncApp,
9024 ) -> Result<proto::Ack> {
9025 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9026 lsp_store
9027 .read_with(&cx, |lsp_store, _| {
9028 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9029 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9030 } else {
9031 None
9032 }
9033 })
9034 .context("handling lsp ext clear flycheck")?;
9035
9036 Ok(proto::Ack {})
9037 }
9038
9039 pub fn disk_based_diagnostics_started(
9040 &mut self,
9041 language_server_id: LanguageServerId,
9042 cx: &mut Context<Self>,
9043 ) {
9044 if let Some(language_server_status) =
9045 self.language_server_statuses.get_mut(&language_server_id)
9046 {
9047 language_server_status.has_pending_diagnostic_updates = true;
9048 }
9049
9050 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9051 cx.emit(LspStoreEvent::LanguageServerUpdate {
9052 language_server_id,
9053 name: self
9054 .language_server_adapter_for_id(language_server_id)
9055 .map(|adapter| adapter.name()),
9056 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9057 Default::default(),
9058 ),
9059 })
9060 }
9061
9062 pub fn disk_based_diagnostics_finished(
9063 &mut self,
9064 language_server_id: LanguageServerId,
9065 cx: &mut Context<Self>,
9066 ) {
9067 if let Some(language_server_status) =
9068 self.language_server_statuses.get_mut(&language_server_id)
9069 {
9070 language_server_status.has_pending_diagnostic_updates = false;
9071 }
9072
9073 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9074 cx.emit(LspStoreEvent::LanguageServerUpdate {
9075 language_server_id,
9076 name: self
9077 .language_server_adapter_for_id(language_server_id)
9078 .map(|adapter| adapter.name()),
9079 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9080 Default::default(),
9081 ),
9082 })
9083 }
9084
9085 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9086 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9087 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9088 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9089 // the language server might take some time to publish diagnostics.
9090 fn simulate_disk_based_diagnostics_events_if_needed(
9091 &mut self,
9092 language_server_id: LanguageServerId,
9093 cx: &mut Context<Self>,
9094 ) {
9095 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9096
9097 let Some(LanguageServerState::Running {
9098 simulate_disk_based_diagnostics_completion,
9099 adapter,
9100 ..
9101 }) = self
9102 .as_local_mut()
9103 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9104 else {
9105 return;
9106 };
9107
9108 if adapter.disk_based_diagnostics_progress_token.is_some() {
9109 return;
9110 }
9111
9112 let prev_task =
9113 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9114 cx.background_executor()
9115 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9116 .await;
9117
9118 this.update(cx, |this, cx| {
9119 this.disk_based_diagnostics_finished(language_server_id, cx);
9120
9121 if let Some(LanguageServerState::Running {
9122 simulate_disk_based_diagnostics_completion,
9123 ..
9124 }) = this.as_local_mut().and_then(|local_store| {
9125 local_store.language_servers.get_mut(&language_server_id)
9126 }) {
9127 *simulate_disk_based_diagnostics_completion = None;
9128 }
9129 })
9130 .ok();
9131 }));
9132
9133 if prev_task.is_none() {
9134 self.disk_based_diagnostics_started(language_server_id, cx);
9135 }
9136 }
9137
9138 pub fn language_server_statuses(
9139 &self,
9140 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9141 self.language_server_statuses
9142 .iter()
9143 .map(|(key, value)| (*key, value))
9144 }
9145
9146 pub(super) fn did_rename_entry(
9147 &self,
9148 worktree_id: WorktreeId,
9149 old_path: &Path,
9150 new_path: &Path,
9151 is_dir: bool,
9152 ) {
9153 maybe!({
9154 let local_store = self.as_local()?;
9155
9156 let old_uri = lsp::Uri::from_file_path(old_path)
9157 .ok()
9158 .map(|uri| uri.to_string())?;
9159 let new_uri = lsp::Uri::from_file_path(new_path)
9160 .ok()
9161 .map(|uri| uri.to_string())?;
9162
9163 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9164 let Some(filter) = local_store
9165 .language_server_paths_watched_for_rename
9166 .get(&language_server.server_id())
9167 else {
9168 continue;
9169 };
9170
9171 if filter.should_send_did_rename(&old_uri, is_dir) {
9172 language_server
9173 .notify::<DidRenameFiles>(RenameFilesParams {
9174 files: vec![FileRename {
9175 old_uri: old_uri.clone(),
9176 new_uri: new_uri.clone(),
9177 }],
9178 })
9179 .ok();
9180 }
9181 }
9182 Some(())
9183 });
9184 }
9185
9186 pub(super) fn will_rename_entry(
9187 this: WeakEntity<Self>,
9188 worktree_id: WorktreeId,
9189 old_path: &Path,
9190 new_path: &Path,
9191 is_dir: bool,
9192 cx: AsyncApp,
9193 ) -> Task<ProjectTransaction> {
9194 let old_uri = lsp::Uri::from_file_path(old_path)
9195 .ok()
9196 .map(|uri| uri.to_string());
9197 let new_uri = lsp::Uri::from_file_path(new_path)
9198 .ok()
9199 .map(|uri| uri.to_string());
9200 cx.spawn(async move |cx| {
9201 let mut tasks = vec![];
9202 this.update(cx, |this, cx| {
9203 let local_store = this.as_local()?;
9204 let old_uri = old_uri?;
9205 let new_uri = new_uri?;
9206 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9207 let Some(filter) = local_store
9208 .language_server_paths_watched_for_rename
9209 .get(&language_server.server_id())
9210 else {
9211 continue;
9212 };
9213
9214 if filter.should_send_will_rename(&old_uri, is_dir) {
9215 let apply_edit = cx.spawn({
9216 let old_uri = old_uri.clone();
9217 let new_uri = new_uri.clone();
9218 let language_server = language_server.clone();
9219 async move |this, cx| {
9220 let edit = language_server
9221 .request::<WillRenameFiles>(RenameFilesParams {
9222 files: vec![FileRename { old_uri, new_uri }],
9223 })
9224 .await
9225 .into_response()
9226 .context("will rename files")
9227 .log_err()
9228 .flatten()?;
9229
9230 let transaction = LocalLspStore::deserialize_workspace_edit(
9231 this.upgrade()?,
9232 edit,
9233 false,
9234 language_server.clone(),
9235 cx,
9236 )
9237 .await
9238 .ok()?;
9239 Some(transaction)
9240 }
9241 });
9242 tasks.push(apply_edit);
9243 }
9244 }
9245 Some(())
9246 })
9247 .ok()
9248 .flatten();
9249 let mut merged_transaction = ProjectTransaction::default();
9250 for task in tasks {
9251 // Await on tasks sequentially so that the order of application of edits is deterministic
9252 // (at least with regards to the order of registration of language servers)
9253 if let Some(transaction) = task.await {
9254 for (buffer, buffer_transaction) in transaction.0 {
9255 merged_transaction.0.insert(buffer, buffer_transaction);
9256 }
9257 }
9258 }
9259 merged_transaction
9260 })
9261 }
9262
9263 fn lsp_notify_abs_paths_changed(
9264 &mut self,
9265 server_id: LanguageServerId,
9266 changes: Vec<PathEvent>,
9267 ) {
9268 maybe!({
9269 let server = self.language_server_for_id(server_id)?;
9270 let changes = changes
9271 .into_iter()
9272 .filter_map(|event| {
9273 let typ = match event.kind? {
9274 PathEventKind::Created => lsp::FileChangeType::CREATED,
9275 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9276 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9277 };
9278 Some(lsp::FileEvent {
9279 uri: file_path_to_lsp_url(&event.path).log_err()?,
9280 typ,
9281 })
9282 })
9283 .collect::<Vec<_>>();
9284 if !changes.is_empty() {
9285 server
9286 .notify::<lsp::notification::DidChangeWatchedFiles>(
9287 lsp::DidChangeWatchedFilesParams { changes },
9288 )
9289 .ok();
9290 }
9291 Some(())
9292 });
9293 }
9294
9295 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9296 self.as_local()?.language_server_for_id(id)
9297 }
9298
9299 fn on_lsp_progress(
9300 &mut self,
9301 progress: lsp::ProgressParams,
9302 language_server_id: LanguageServerId,
9303 disk_based_diagnostics_progress_token: Option<String>,
9304 cx: &mut Context<Self>,
9305 ) {
9306 let token = match progress.token {
9307 lsp::NumberOrString::String(token) => token,
9308 lsp::NumberOrString::Number(token) => {
9309 log::info!("skipping numeric progress token {}", token);
9310 return;
9311 }
9312 };
9313
9314 match progress.value {
9315 lsp::ProgressParamsValue::WorkDone(progress) => {
9316 self.handle_work_done_progress(
9317 progress,
9318 language_server_id,
9319 disk_based_diagnostics_progress_token,
9320 token,
9321 cx,
9322 );
9323 }
9324 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9325 if let Some(LanguageServerState::Running {
9326 workspace_refresh_task: Some(workspace_refresh_task),
9327 ..
9328 }) = self
9329 .as_local_mut()
9330 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9331 {
9332 workspace_refresh_task.progress_tx.try_send(()).ok();
9333 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9334 }
9335 }
9336 }
9337 }
9338
9339 fn handle_work_done_progress(
9340 &mut self,
9341 progress: lsp::WorkDoneProgress,
9342 language_server_id: LanguageServerId,
9343 disk_based_diagnostics_progress_token: Option<String>,
9344 token: String,
9345 cx: &mut Context<Self>,
9346 ) {
9347 let language_server_status =
9348 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9349 status
9350 } else {
9351 return;
9352 };
9353
9354 if !language_server_status.progress_tokens.contains(&token) {
9355 return;
9356 }
9357
9358 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9359 .as_ref()
9360 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9361
9362 match progress {
9363 lsp::WorkDoneProgress::Begin(report) => {
9364 if is_disk_based_diagnostics_progress {
9365 self.disk_based_diagnostics_started(language_server_id, cx);
9366 }
9367 self.on_lsp_work_start(
9368 language_server_id,
9369 token.clone(),
9370 LanguageServerProgress {
9371 title: Some(report.title),
9372 is_disk_based_diagnostics_progress,
9373 is_cancellable: report.cancellable.unwrap_or(false),
9374 message: report.message.clone(),
9375 percentage: report.percentage.map(|p| p as usize),
9376 last_update_at: cx.background_executor().now(),
9377 },
9378 cx,
9379 );
9380 }
9381 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9382 language_server_id,
9383 token,
9384 LanguageServerProgress {
9385 title: None,
9386 is_disk_based_diagnostics_progress,
9387 is_cancellable: report.cancellable.unwrap_or(false),
9388 message: report.message,
9389 percentage: report.percentage.map(|p| p as usize),
9390 last_update_at: cx.background_executor().now(),
9391 },
9392 cx,
9393 ),
9394 lsp::WorkDoneProgress::End(_) => {
9395 language_server_status.progress_tokens.remove(&token);
9396 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9397 if is_disk_based_diagnostics_progress {
9398 self.disk_based_diagnostics_finished(language_server_id, cx);
9399 }
9400 }
9401 }
9402 }
9403
9404 fn on_lsp_work_start(
9405 &mut self,
9406 language_server_id: LanguageServerId,
9407 token: String,
9408 progress: LanguageServerProgress,
9409 cx: &mut Context<Self>,
9410 ) {
9411 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9412 status.pending_work.insert(token.clone(), progress.clone());
9413 cx.notify();
9414 }
9415 cx.emit(LspStoreEvent::LanguageServerUpdate {
9416 language_server_id,
9417 name: self
9418 .language_server_adapter_for_id(language_server_id)
9419 .map(|adapter| adapter.name()),
9420 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9421 token,
9422 title: progress.title,
9423 message: progress.message,
9424 percentage: progress.percentage.map(|p| p as u32),
9425 is_cancellable: Some(progress.is_cancellable),
9426 }),
9427 })
9428 }
9429
9430 fn on_lsp_work_progress(
9431 &mut self,
9432 language_server_id: LanguageServerId,
9433 token: String,
9434 progress: LanguageServerProgress,
9435 cx: &mut Context<Self>,
9436 ) {
9437 let mut did_update = false;
9438 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9439 match status.pending_work.entry(token.clone()) {
9440 btree_map::Entry::Vacant(entry) => {
9441 entry.insert(progress.clone());
9442 did_update = true;
9443 }
9444 btree_map::Entry::Occupied(mut entry) => {
9445 let entry = entry.get_mut();
9446 if (progress.last_update_at - entry.last_update_at)
9447 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9448 {
9449 entry.last_update_at = progress.last_update_at;
9450 if progress.message.is_some() {
9451 entry.message = progress.message.clone();
9452 }
9453 if progress.percentage.is_some() {
9454 entry.percentage = progress.percentage;
9455 }
9456 if progress.is_cancellable != entry.is_cancellable {
9457 entry.is_cancellable = progress.is_cancellable;
9458 }
9459 did_update = true;
9460 }
9461 }
9462 }
9463 }
9464
9465 if did_update {
9466 cx.emit(LspStoreEvent::LanguageServerUpdate {
9467 language_server_id,
9468 name: self
9469 .language_server_adapter_for_id(language_server_id)
9470 .map(|adapter| adapter.name()),
9471 message: proto::update_language_server::Variant::WorkProgress(
9472 proto::LspWorkProgress {
9473 token,
9474 message: progress.message,
9475 percentage: progress.percentage.map(|p| p as u32),
9476 is_cancellable: Some(progress.is_cancellable),
9477 },
9478 ),
9479 })
9480 }
9481 }
9482
9483 fn on_lsp_work_end(
9484 &mut self,
9485 language_server_id: LanguageServerId,
9486 token: String,
9487 cx: &mut Context<Self>,
9488 ) {
9489 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9490 if let Some(work) = status.pending_work.remove(&token)
9491 && !work.is_disk_based_diagnostics_progress
9492 {
9493 cx.emit(LspStoreEvent::RefreshInlayHints(language_server_id));
9494 }
9495 cx.notify();
9496 }
9497
9498 cx.emit(LspStoreEvent::LanguageServerUpdate {
9499 language_server_id,
9500 name: self
9501 .language_server_adapter_for_id(language_server_id)
9502 .map(|adapter| adapter.name()),
9503 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9504 })
9505 }
9506
9507 pub async fn handle_resolve_completion_documentation(
9508 this: Entity<Self>,
9509 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9510 mut cx: AsyncApp,
9511 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9512 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9513
9514 let completion = this
9515 .read_with(&cx, |this, cx| {
9516 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9517 let server = this
9518 .language_server_for_id(id)
9519 .with_context(|| format!("No language server {id}"))?;
9520
9521 anyhow::Ok(cx.background_spawn(async move {
9522 let can_resolve = server
9523 .capabilities()
9524 .completion_provider
9525 .as_ref()
9526 .and_then(|options| options.resolve_provider)
9527 .unwrap_or(false);
9528 if can_resolve {
9529 server
9530 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9531 .await
9532 .into_response()
9533 .context("resolve completion item")
9534 } else {
9535 anyhow::Ok(lsp_completion)
9536 }
9537 }))
9538 })??
9539 .await?;
9540
9541 let mut documentation_is_markdown = false;
9542 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9543 let documentation = match completion.documentation {
9544 Some(lsp::Documentation::String(text)) => text,
9545
9546 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9547 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9548 value
9549 }
9550
9551 _ => String::new(),
9552 };
9553
9554 // If we have a new buffer_id, that means we're talking to a new client
9555 // and want to check for new text_edits in the completion too.
9556 let mut old_replace_start = None;
9557 let mut old_replace_end = None;
9558 let mut old_insert_start = None;
9559 let mut old_insert_end = None;
9560 let mut new_text = String::default();
9561 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9562 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9563 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9564 anyhow::Ok(buffer.read(cx).snapshot())
9565 })??;
9566
9567 if let Some(text_edit) = completion.text_edit.as_ref() {
9568 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9569
9570 if let Some(mut edit) = edit {
9571 LineEnding::normalize(&mut edit.new_text);
9572
9573 new_text = edit.new_text;
9574 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9575 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9576 if let Some(insert_range) = edit.insert_range {
9577 old_insert_start = Some(serialize_anchor(&insert_range.start));
9578 old_insert_end = Some(serialize_anchor(&insert_range.end));
9579 }
9580 }
9581 }
9582 }
9583
9584 Ok(proto::ResolveCompletionDocumentationResponse {
9585 documentation,
9586 documentation_is_markdown,
9587 old_replace_start,
9588 old_replace_end,
9589 new_text,
9590 lsp_completion,
9591 old_insert_start,
9592 old_insert_end,
9593 })
9594 }
9595
9596 async fn handle_on_type_formatting(
9597 this: Entity<Self>,
9598 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9599 mut cx: AsyncApp,
9600 ) -> Result<proto::OnTypeFormattingResponse> {
9601 let on_type_formatting = this.update(&mut cx, |this, cx| {
9602 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9603 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9604 let position = envelope
9605 .payload
9606 .position
9607 .and_then(deserialize_anchor)
9608 .context("invalid position")?;
9609 anyhow::Ok(this.apply_on_type_formatting(
9610 buffer,
9611 position,
9612 envelope.payload.trigger.clone(),
9613 cx,
9614 ))
9615 })??;
9616
9617 let transaction = on_type_formatting
9618 .await?
9619 .as_ref()
9620 .map(language::proto::serialize_transaction);
9621 Ok(proto::OnTypeFormattingResponse { transaction })
9622 }
9623
9624 async fn handle_refresh_inlay_hints(
9625 lsp_store: Entity<Self>,
9626 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9627 mut cx: AsyncApp,
9628 ) -> Result<proto::Ack> {
9629 lsp_store.update(&mut cx, |_, cx| {
9630 cx.emit(LspStoreEvent::RefreshInlayHints(
9631 LanguageServerId::from_proto(envelope.payload.server_id),
9632 ));
9633 })?;
9634 Ok(proto::Ack {})
9635 }
9636
9637 async fn handle_pull_workspace_diagnostics(
9638 lsp_store: Entity<Self>,
9639 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9640 mut cx: AsyncApp,
9641 ) -> Result<proto::Ack> {
9642 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9643 lsp_store.update(&mut cx, |lsp_store, _| {
9644 lsp_store.pull_workspace_diagnostics(server_id);
9645 })?;
9646 Ok(proto::Ack {})
9647 }
9648
9649 async fn handle_get_color_presentation(
9650 lsp_store: Entity<Self>,
9651 envelope: TypedEnvelope<proto::GetColorPresentation>,
9652 mut cx: AsyncApp,
9653 ) -> Result<proto::GetColorPresentationResponse> {
9654 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9655 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9656 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9657 })??;
9658
9659 let color = envelope
9660 .payload
9661 .color
9662 .context("invalid color resolve request")?;
9663 let start = color
9664 .lsp_range_start
9665 .context("invalid color resolve request")?;
9666 let end = color
9667 .lsp_range_end
9668 .context("invalid color resolve request")?;
9669
9670 let color = DocumentColor {
9671 lsp_range: lsp::Range {
9672 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9673 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9674 },
9675 color: lsp::Color {
9676 red: color.red,
9677 green: color.green,
9678 blue: color.blue,
9679 alpha: color.alpha,
9680 },
9681 resolved: false,
9682 color_presentations: Vec::new(),
9683 };
9684 let resolved_color = lsp_store
9685 .update(&mut cx, |lsp_store, cx| {
9686 lsp_store.resolve_color_presentation(
9687 color,
9688 buffer.clone(),
9689 LanguageServerId(envelope.payload.server_id as usize),
9690 cx,
9691 )
9692 })?
9693 .await
9694 .context("resolving color presentation")?;
9695
9696 Ok(proto::GetColorPresentationResponse {
9697 presentations: resolved_color
9698 .color_presentations
9699 .into_iter()
9700 .map(|presentation| proto::ColorPresentation {
9701 label: presentation.label.to_string(),
9702 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9703 additional_text_edits: presentation
9704 .additional_text_edits
9705 .into_iter()
9706 .map(serialize_lsp_edit)
9707 .collect(),
9708 })
9709 .collect(),
9710 })
9711 }
9712
9713 async fn handle_resolve_inlay_hint(
9714 lsp_store: Entity<Self>,
9715 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9716 mut cx: AsyncApp,
9717 ) -> Result<proto::ResolveInlayHintResponse> {
9718 let proto_hint = envelope
9719 .payload
9720 .hint
9721 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9722 let hint = InlayHints::proto_to_project_hint(proto_hint)
9723 .context("resolved proto inlay hint conversion")?;
9724 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9725 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9726 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9727 })??;
9728 let response_hint = lsp_store
9729 .update(&mut cx, |lsp_store, cx| {
9730 lsp_store.resolve_inlay_hint(
9731 hint,
9732 buffer,
9733 LanguageServerId(envelope.payload.language_server_id as usize),
9734 cx,
9735 )
9736 })?
9737 .await
9738 .context("inlay hints fetch")?;
9739 Ok(proto::ResolveInlayHintResponse {
9740 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9741 })
9742 }
9743
9744 async fn handle_refresh_code_lens(
9745 this: Entity<Self>,
9746 _: TypedEnvelope<proto::RefreshCodeLens>,
9747 mut cx: AsyncApp,
9748 ) -> Result<proto::Ack> {
9749 this.update(&mut cx, |_, cx| {
9750 cx.emit(LspStoreEvent::RefreshCodeLens);
9751 })?;
9752 Ok(proto::Ack {})
9753 }
9754
9755 async fn handle_open_buffer_for_symbol(
9756 this: Entity<Self>,
9757 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9758 mut cx: AsyncApp,
9759 ) -> Result<proto::OpenBufferForSymbolResponse> {
9760 let peer_id = envelope.original_sender_id().unwrap_or_default();
9761 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9762 let symbol = Self::deserialize_symbol(symbol)?;
9763 this.read_with(&cx, |this, _| {
9764 if let SymbolLocation::OutsideProject {
9765 abs_path,
9766 signature,
9767 } = &symbol.path
9768 {
9769 let new_signature = this.symbol_signature(&abs_path);
9770 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9771 }
9772 Ok(())
9773 })??;
9774 let buffer = this
9775 .update(&mut cx, |this, cx| {
9776 this.open_buffer_for_symbol(
9777 &Symbol {
9778 language_server_name: symbol.language_server_name,
9779 source_worktree_id: symbol.source_worktree_id,
9780 source_language_server_id: symbol.source_language_server_id,
9781 path: symbol.path,
9782 name: symbol.name,
9783 kind: symbol.kind,
9784 range: symbol.range,
9785 label: CodeLabel::default(),
9786 },
9787 cx,
9788 )
9789 })?
9790 .await?;
9791
9792 this.update(&mut cx, |this, cx| {
9793 let is_private = buffer
9794 .read(cx)
9795 .file()
9796 .map(|f| f.is_private())
9797 .unwrap_or_default();
9798 if is_private {
9799 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9800 } else {
9801 this.buffer_store
9802 .update(cx, |buffer_store, cx| {
9803 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9804 })
9805 .detach_and_log_err(cx);
9806 let buffer_id = buffer.read(cx).remote_id().to_proto();
9807 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9808 }
9809 })?
9810 }
9811
9812 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9813 let mut hasher = Sha256::new();
9814 hasher.update(abs_path.to_string_lossy().as_bytes());
9815 hasher.update(self.nonce.to_be_bytes());
9816 hasher.finalize().as_slice().try_into().unwrap()
9817 }
9818
9819 pub async fn handle_get_project_symbols(
9820 this: Entity<Self>,
9821 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9822 mut cx: AsyncApp,
9823 ) -> Result<proto::GetProjectSymbolsResponse> {
9824 let symbols = this
9825 .update(&mut cx, |this, cx| {
9826 this.symbols(&envelope.payload.query, cx)
9827 })?
9828 .await?;
9829
9830 Ok(proto::GetProjectSymbolsResponse {
9831 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9832 })
9833 }
9834
9835 pub async fn handle_restart_language_servers(
9836 this: Entity<Self>,
9837 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9838 mut cx: AsyncApp,
9839 ) -> Result<proto::Ack> {
9840 this.update(&mut cx, |lsp_store, cx| {
9841 let buffers =
9842 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9843 lsp_store.restart_language_servers_for_buffers(
9844 buffers,
9845 envelope
9846 .payload
9847 .only_servers
9848 .into_iter()
9849 .filter_map(|selector| {
9850 Some(match selector.selector? {
9851 proto::language_server_selector::Selector::ServerId(server_id) => {
9852 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9853 }
9854 proto::language_server_selector::Selector::Name(name) => {
9855 LanguageServerSelector::Name(LanguageServerName(
9856 SharedString::from(name),
9857 ))
9858 }
9859 })
9860 })
9861 .collect(),
9862 cx,
9863 );
9864 })?;
9865
9866 Ok(proto::Ack {})
9867 }
9868
9869 pub async fn handle_stop_language_servers(
9870 lsp_store: Entity<Self>,
9871 envelope: TypedEnvelope<proto::StopLanguageServers>,
9872 mut cx: AsyncApp,
9873 ) -> Result<proto::Ack> {
9874 lsp_store.update(&mut cx, |lsp_store, cx| {
9875 if envelope.payload.all
9876 && envelope.payload.also_servers.is_empty()
9877 && envelope.payload.buffer_ids.is_empty()
9878 {
9879 lsp_store.stop_all_language_servers(cx);
9880 } else {
9881 let buffers =
9882 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9883 lsp_store
9884 .stop_language_servers_for_buffers(
9885 buffers,
9886 envelope
9887 .payload
9888 .also_servers
9889 .into_iter()
9890 .filter_map(|selector| {
9891 Some(match selector.selector? {
9892 proto::language_server_selector::Selector::ServerId(
9893 server_id,
9894 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9895 server_id,
9896 )),
9897 proto::language_server_selector::Selector::Name(name) => {
9898 LanguageServerSelector::Name(LanguageServerName(
9899 SharedString::from(name),
9900 ))
9901 }
9902 })
9903 })
9904 .collect(),
9905 cx,
9906 )
9907 .detach_and_log_err(cx);
9908 }
9909 })?;
9910
9911 Ok(proto::Ack {})
9912 }
9913
9914 pub async fn handle_cancel_language_server_work(
9915 this: Entity<Self>,
9916 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9917 mut cx: AsyncApp,
9918 ) -> Result<proto::Ack> {
9919 this.update(&mut cx, |this, cx| {
9920 if let Some(work) = envelope.payload.work {
9921 match work {
9922 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9923 let buffers =
9924 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9925 this.cancel_language_server_work_for_buffers(buffers, cx);
9926 }
9927 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9928 let server_id = LanguageServerId::from_proto(work.language_server_id);
9929 this.cancel_language_server_work(server_id, work.token, cx);
9930 }
9931 }
9932 }
9933 })?;
9934
9935 Ok(proto::Ack {})
9936 }
9937
9938 fn buffer_ids_to_buffers(
9939 &mut self,
9940 buffer_ids: impl Iterator<Item = u64>,
9941 cx: &mut Context<Self>,
9942 ) -> Vec<Entity<Buffer>> {
9943 buffer_ids
9944 .into_iter()
9945 .flat_map(|buffer_id| {
9946 self.buffer_store
9947 .read(cx)
9948 .get(BufferId::new(buffer_id).log_err()?)
9949 })
9950 .collect::<Vec<_>>()
9951 }
9952
9953 async fn handle_apply_additional_edits_for_completion(
9954 this: Entity<Self>,
9955 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9956 mut cx: AsyncApp,
9957 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9958 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9959 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9960 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9961 let completion = Self::deserialize_completion(
9962 envelope.payload.completion.context("invalid completion")?,
9963 )?;
9964 anyhow::Ok((buffer, completion))
9965 })??;
9966
9967 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9968 this.apply_additional_edits_for_completion(
9969 buffer,
9970 Rc::new(RefCell::new(Box::new([Completion {
9971 replace_range: completion.replace_range,
9972 new_text: completion.new_text,
9973 source: completion.source,
9974 documentation: None,
9975 label: CodeLabel::default(),
9976 insert_text_mode: None,
9977 icon_path: None,
9978 confirm: None,
9979 }]))),
9980 0,
9981 false,
9982 cx,
9983 )
9984 })?;
9985
9986 Ok(proto::ApplyCompletionAdditionalEditsResponse {
9987 transaction: apply_additional_edits
9988 .await?
9989 .as_ref()
9990 .map(language::proto::serialize_transaction),
9991 })
9992 }
9993
9994 pub fn last_formatting_failure(&self) -> Option<&str> {
9995 self.last_formatting_failure.as_deref()
9996 }
9997
9998 pub fn reset_last_formatting_failure(&mut self) {
9999 self.last_formatting_failure = None;
10000 }
10001
10002 pub fn environment_for_buffer(
10003 &self,
10004 buffer: &Entity<Buffer>,
10005 cx: &mut Context<Self>,
10006 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10007 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10008 environment.update(cx, |env, cx| {
10009 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10010 })
10011 } else {
10012 Task::ready(None).shared()
10013 }
10014 }
10015
10016 pub fn format(
10017 &mut self,
10018 buffers: HashSet<Entity<Buffer>>,
10019 target: LspFormatTarget,
10020 push_to_history: bool,
10021 trigger: FormatTrigger,
10022 cx: &mut Context<Self>,
10023 ) -> Task<anyhow::Result<ProjectTransaction>> {
10024 let logger = zlog::scoped!("format");
10025 if self.as_local().is_some() {
10026 zlog::trace!(logger => "Formatting locally");
10027 let logger = zlog::scoped!(logger => "local");
10028 let buffers = buffers
10029 .into_iter()
10030 .map(|buffer_handle| {
10031 let buffer = buffer_handle.read(cx);
10032 let buffer_abs_path = File::from_dyn(buffer.file())
10033 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10034
10035 (buffer_handle, buffer_abs_path, buffer.remote_id())
10036 })
10037 .collect::<Vec<_>>();
10038
10039 cx.spawn(async move |lsp_store, cx| {
10040 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10041
10042 for (handle, abs_path, id) in buffers {
10043 let env = lsp_store
10044 .update(cx, |lsp_store, cx| {
10045 lsp_store.environment_for_buffer(&handle, cx)
10046 })?
10047 .await;
10048
10049 let ranges = match &target {
10050 LspFormatTarget::Buffers => None,
10051 LspFormatTarget::Ranges(ranges) => {
10052 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10053 }
10054 };
10055
10056 formattable_buffers.push(FormattableBuffer {
10057 handle,
10058 abs_path,
10059 env,
10060 ranges,
10061 });
10062 }
10063 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10064
10065 let format_timer = zlog::time!(logger => "Formatting buffers");
10066 let result = LocalLspStore::format_locally(
10067 lsp_store.clone(),
10068 formattable_buffers,
10069 push_to_history,
10070 trigger,
10071 logger,
10072 cx,
10073 )
10074 .await;
10075 format_timer.end();
10076
10077 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10078
10079 lsp_store.update(cx, |lsp_store, _| {
10080 lsp_store.update_last_formatting_failure(&result);
10081 })?;
10082
10083 result
10084 })
10085 } else if let Some((client, project_id)) = self.upstream_client() {
10086 zlog::trace!(logger => "Formatting remotely");
10087 let logger = zlog::scoped!(logger => "remote");
10088 // Don't support formatting ranges via remote
10089 match target {
10090 LspFormatTarget::Buffers => {}
10091 LspFormatTarget::Ranges(_) => {
10092 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10093 return Task::ready(Ok(ProjectTransaction::default()));
10094 }
10095 }
10096
10097 let buffer_store = self.buffer_store();
10098 cx.spawn(async move |lsp_store, cx| {
10099 zlog::trace!(logger => "Sending remote format request");
10100 let request_timer = zlog::time!(logger => "remote format request");
10101 let result = client
10102 .request(proto::FormatBuffers {
10103 project_id,
10104 trigger: trigger as i32,
10105 buffer_ids: buffers
10106 .iter()
10107 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10108 .collect::<Result<_>>()?,
10109 })
10110 .await
10111 .and_then(|result| result.transaction.context("missing transaction"));
10112 request_timer.end();
10113
10114 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10115
10116 lsp_store.update(cx, |lsp_store, _| {
10117 lsp_store.update_last_formatting_failure(&result);
10118 })?;
10119
10120 let transaction_response = result?;
10121 let _timer = zlog::time!(logger => "deserializing project transaction");
10122 buffer_store
10123 .update(cx, |buffer_store, cx| {
10124 buffer_store.deserialize_project_transaction(
10125 transaction_response,
10126 push_to_history,
10127 cx,
10128 )
10129 })?
10130 .await
10131 })
10132 } else {
10133 zlog::trace!(logger => "Not formatting");
10134 Task::ready(Ok(ProjectTransaction::default()))
10135 }
10136 }
10137
10138 async fn handle_format_buffers(
10139 this: Entity<Self>,
10140 envelope: TypedEnvelope<proto::FormatBuffers>,
10141 mut cx: AsyncApp,
10142 ) -> Result<proto::FormatBuffersResponse> {
10143 let sender_id = envelope.original_sender_id().unwrap_or_default();
10144 let format = this.update(&mut cx, |this, cx| {
10145 let mut buffers = HashSet::default();
10146 for buffer_id in &envelope.payload.buffer_ids {
10147 let buffer_id = BufferId::new(*buffer_id)?;
10148 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10149 }
10150 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10151 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10152 })??;
10153
10154 let project_transaction = format.await?;
10155 let project_transaction = this.update(&mut cx, |this, cx| {
10156 this.buffer_store.update(cx, |buffer_store, cx| {
10157 buffer_store.serialize_project_transaction_for_peer(
10158 project_transaction,
10159 sender_id,
10160 cx,
10161 )
10162 })
10163 })?;
10164 Ok(proto::FormatBuffersResponse {
10165 transaction: Some(project_transaction),
10166 })
10167 }
10168
10169 async fn handle_apply_code_action_kind(
10170 this: Entity<Self>,
10171 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10172 mut cx: AsyncApp,
10173 ) -> Result<proto::ApplyCodeActionKindResponse> {
10174 let sender_id = envelope.original_sender_id().unwrap_or_default();
10175 let format = this.update(&mut cx, |this, cx| {
10176 let mut buffers = HashSet::default();
10177 for buffer_id in &envelope.payload.buffer_ids {
10178 let buffer_id = BufferId::new(*buffer_id)?;
10179 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10180 }
10181 let kind = match envelope.payload.kind.as_str() {
10182 "" => CodeActionKind::EMPTY,
10183 "quickfix" => CodeActionKind::QUICKFIX,
10184 "refactor" => CodeActionKind::REFACTOR,
10185 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10186 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10187 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10188 "source" => CodeActionKind::SOURCE,
10189 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10190 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10191 _ => anyhow::bail!(
10192 "Invalid code action kind {}",
10193 envelope.payload.kind.as_str()
10194 ),
10195 };
10196 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10197 })??;
10198
10199 let project_transaction = format.await?;
10200 let project_transaction = this.update(&mut cx, |this, cx| {
10201 this.buffer_store.update(cx, |buffer_store, cx| {
10202 buffer_store.serialize_project_transaction_for_peer(
10203 project_transaction,
10204 sender_id,
10205 cx,
10206 )
10207 })
10208 })?;
10209 Ok(proto::ApplyCodeActionKindResponse {
10210 transaction: Some(project_transaction),
10211 })
10212 }
10213
10214 async fn shutdown_language_server(
10215 server_state: Option<LanguageServerState>,
10216 name: LanguageServerName,
10217 cx: &mut AsyncApp,
10218 ) {
10219 let server = match server_state {
10220 Some(LanguageServerState::Starting { startup, .. }) => {
10221 let mut timer = cx
10222 .background_executor()
10223 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10224 .fuse();
10225
10226 select! {
10227 server = startup.fuse() => server,
10228 () = timer => {
10229 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10230 None
10231 },
10232 }
10233 }
10234
10235 Some(LanguageServerState::Running { server, .. }) => Some(server),
10236
10237 None => None,
10238 };
10239
10240 if let Some(server) = server
10241 && let Some(shutdown) = server.shutdown()
10242 {
10243 shutdown.await;
10244 }
10245 }
10246
10247 // Returns a list of all of the worktrees which no longer have a language server and the root path
10248 // for the stopped server
10249 fn stop_local_language_server(
10250 &mut self,
10251 server_id: LanguageServerId,
10252 cx: &mut Context<Self>,
10253 ) -> Task<()> {
10254 let local = match &mut self.mode {
10255 LspStoreMode::Local(local) => local,
10256 _ => {
10257 return Task::ready(());
10258 }
10259 };
10260
10261 // Remove this server ID from all entries in the given worktree.
10262 local
10263 .language_server_ids
10264 .retain(|_, state| state.id != server_id);
10265 self.buffer_store.update(cx, |buffer_store, cx| {
10266 for buffer in buffer_store.buffers() {
10267 buffer.update(cx, |buffer, cx| {
10268 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10269 buffer.set_completion_triggers(server_id, Default::default(), cx);
10270 });
10271 }
10272 });
10273
10274 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10275 summaries.retain(|path, summaries_by_server_id| {
10276 if summaries_by_server_id.remove(&server_id).is_some() {
10277 if let Some((client, project_id)) = self.downstream_client.clone() {
10278 client
10279 .send(proto::UpdateDiagnosticSummary {
10280 project_id,
10281 worktree_id: worktree_id.to_proto(),
10282 summary: Some(proto::DiagnosticSummary {
10283 path: path.as_ref().to_proto(),
10284 language_server_id: server_id.0 as u64,
10285 error_count: 0,
10286 warning_count: 0,
10287 }),
10288 more_summaries: Vec::new(),
10289 })
10290 .log_err();
10291 }
10292 !summaries_by_server_id.is_empty()
10293 } else {
10294 true
10295 }
10296 });
10297 }
10298
10299 let local = self.as_local_mut().unwrap();
10300 for diagnostics in local.diagnostics.values_mut() {
10301 diagnostics.retain(|_, diagnostics_by_server_id| {
10302 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10303 diagnostics_by_server_id.remove(ix);
10304 !diagnostics_by_server_id.is_empty()
10305 } else {
10306 true
10307 }
10308 });
10309 }
10310 local.language_server_watched_paths.remove(&server_id);
10311
10312 let server_state = local.language_servers.remove(&server_id);
10313 self.cleanup_lsp_data(server_id);
10314 let name = self
10315 .language_server_statuses
10316 .remove(&server_id)
10317 .map(|status| status.name)
10318 .or_else(|| {
10319 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10320 Some(adapter.name())
10321 } else {
10322 None
10323 }
10324 });
10325
10326 if let Some(name) = name {
10327 log::info!("stopping language server {name}");
10328 self.languages
10329 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10330 cx.notify();
10331
10332 return cx.spawn(async move |lsp_store, cx| {
10333 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10334 lsp_store
10335 .update(cx, |lsp_store, cx| {
10336 lsp_store
10337 .languages
10338 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10339 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10340 cx.notify();
10341 })
10342 .ok();
10343 });
10344 }
10345
10346 if server_state.is_some() {
10347 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10348 }
10349 Task::ready(())
10350 }
10351
10352 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10353 if let Some((client, project_id)) = self.upstream_client() {
10354 let request = client.request(proto::StopLanguageServers {
10355 project_id,
10356 buffer_ids: Vec::new(),
10357 also_servers: Vec::new(),
10358 all: true,
10359 });
10360 cx.background_spawn(request).detach_and_log_err(cx);
10361 } else {
10362 let Some(local) = self.as_local_mut() else {
10363 return;
10364 };
10365 let language_servers_to_stop = local
10366 .language_server_ids
10367 .values()
10368 .map(|state| state.id)
10369 .collect();
10370 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10371 let tasks = language_servers_to_stop
10372 .into_iter()
10373 .map(|server| self.stop_local_language_server(server, cx))
10374 .collect::<Vec<_>>();
10375 cx.background_spawn(async move {
10376 futures::future::join_all(tasks).await;
10377 })
10378 .detach();
10379 }
10380 }
10381
10382 pub fn restart_language_servers_for_buffers(
10383 &mut self,
10384 buffers: Vec<Entity<Buffer>>,
10385 only_restart_servers: HashSet<LanguageServerSelector>,
10386 cx: &mut Context<Self>,
10387 ) {
10388 if let Some((client, project_id)) = self.upstream_client() {
10389 let request = client.request(proto::RestartLanguageServers {
10390 project_id,
10391 buffer_ids: buffers
10392 .into_iter()
10393 .map(|b| b.read(cx).remote_id().to_proto())
10394 .collect(),
10395 only_servers: only_restart_servers
10396 .into_iter()
10397 .map(|selector| {
10398 let selector = match selector {
10399 LanguageServerSelector::Id(language_server_id) => {
10400 proto::language_server_selector::Selector::ServerId(
10401 language_server_id.to_proto(),
10402 )
10403 }
10404 LanguageServerSelector::Name(language_server_name) => {
10405 proto::language_server_selector::Selector::Name(
10406 language_server_name.to_string(),
10407 )
10408 }
10409 };
10410 proto::LanguageServerSelector {
10411 selector: Some(selector),
10412 }
10413 })
10414 .collect(),
10415 all: false,
10416 });
10417 cx.background_spawn(request).detach_and_log_err(cx);
10418 } else {
10419 let stop_task = if only_restart_servers.is_empty() {
10420 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10421 } else {
10422 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10423 };
10424 cx.spawn(async move |lsp_store, cx| {
10425 stop_task.await;
10426 lsp_store
10427 .update(cx, |lsp_store, cx| {
10428 for buffer in buffers {
10429 lsp_store.register_buffer_with_language_servers(
10430 &buffer,
10431 only_restart_servers.clone(),
10432 true,
10433 cx,
10434 );
10435 }
10436 })
10437 .ok()
10438 })
10439 .detach();
10440 }
10441 }
10442
10443 pub fn stop_language_servers_for_buffers(
10444 &mut self,
10445 buffers: Vec<Entity<Buffer>>,
10446 also_stop_servers: HashSet<LanguageServerSelector>,
10447 cx: &mut Context<Self>,
10448 ) -> Task<Result<()>> {
10449 if let Some((client, project_id)) = self.upstream_client() {
10450 let request = client.request(proto::StopLanguageServers {
10451 project_id,
10452 buffer_ids: buffers
10453 .into_iter()
10454 .map(|b| b.read(cx).remote_id().to_proto())
10455 .collect(),
10456 also_servers: also_stop_servers
10457 .into_iter()
10458 .map(|selector| {
10459 let selector = match selector {
10460 LanguageServerSelector::Id(language_server_id) => {
10461 proto::language_server_selector::Selector::ServerId(
10462 language_server_id.to_proto(),
10463 )
10464 }
10465 LanguageServerSelector::Name(language_server_name) => {
10466 proto::language_server_selector::Selector::Name(
10467 language_server_name.to_string(),
10468 )
10469 }
10470 };
10471 proto::LanguageServerSelector {
10472 selector: Some(selector),
10473 }
10474 })
10475 .collect(),
10476 all: false,
10477 });
10478 cx.background_spawn(async move {
10479 let _ = request.await?;
10480 Ok(())
10481 })
10482 } else {
10483 let task =
10484 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10485 cx.background_spawn(async move {
10486 task.await;
10487 Ok(())
10488 })
10489 }
10490 }
10491
10492 fn stop_local_language_servers_for_buffers(
10493 &mut self,
10494 buffers: &[Entity<Buffer>],
10495 also_stop_servers: HashSet<LanguageServerSelector>,
10496 cx: &mut Context<Self>,
10497 ) -> Task<()> {
10498 let Some(local) = self.as_local_mut() else {
10499 return Task::ready(());
10500 };
10501 let mut language_server_names_to_stop = BTreeSet::default();
10502 let mut language_servers_to_stop = also_stop_servers
10503 .into_iter()
10504 .flat_map(|selector| match selector {
10505 LanguageServerSelector::Id(id) => Some(id),
10506 LanguageServerSelector::Name(name) => {
10507 language_server_names_to_stop.insert(name);
10508 None
10509 }
10510 })
10511 .collect::<BTreeSet<_>>();
10512
10513 let mut covered_worktrees = HashSet::default();
10514 for buffer in buffers {
10515 buffer.update(cx, |buffer, cx| {
10516 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10517 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10518 && covered_worktrees.insert(worktree_id)
10519 {
10520 language_server_names_to_stop.retain(|name| {
10521 let old_ids_count = language_servers_to_stop.len();
10522 let all_language_servers_with_this_name = local
10523 .language_server_ids
10524 .iter()
10525 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10526 language_servers_to_stop.extend(all_language_servers_with_this_name);
10527 old_ids_count == language_servers_to_stop.len()
10528 });
10529 }
10530 });
10531 }
10532 for name in language_server_names_to_stop {
10533 language_servers_to_stop.extend(
10534 local
10535 .language_server_ids
10536 .iter()
10537 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10538 );
10539 }
10540
10541 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10542 let tasks = language_servers_to_stop
10543 .into_iter()
10544 .map(|server| self.stop_local_language_server(server, cx))
10545 .collect::<Vec<_>>();
10546
10547 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10548 }
10549
10550 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10551 let (worktree, relative_path) =
10552 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10553
10554 let project_path = ProjectPath {
10555 worktree_id: worktree.read(cx).id(),
10556 path: relative_path,
10557 };
10558
10559 Some(
10560 self.buffer_store()
10561 .read(cx)
10562 .get_by_path(&project_path)?
10563 .read(cx),
10564 )
10565 }
10566
10567 #[cfg(any(test, feature = "test-support"))]
10568 pub fn update_diagnostics(
10569 &mut self,
10570 server_id: LanguageServerId,
10571 diagnostics: lsp::PublishDiagnosticsParams,
10572 result_id: Option<String>,
10573 source_kind: DiagnosticSourceKind,
10574 disk_based_sources: &[String],
10575 cx: &mut Context<Self>,
10576 ) -> Result<()> {
10577 self.merge_lsp_diagnostics(
10578 source_kind,
10579 vec![DocumentDiagnosticsUpdate {
10580 diagnostics,
10581 result_id,
10582 server_id,
10583 disk_based_sources: Cow::Borrowed(disk_based_sources),
10584 }],
10585 |_, _, _| false,
10586 cx,
10587 )
10588 }
10589
10590 pub fn merge_lsp_diagnostics(
10591 &mut self,
10592 source_kind: DiagnosticSourceKind,
10593 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10594 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10595 cx: &mut Context<Self>,
10596 ) -> Result<()> {
10597 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10598 let updates = lsp_diagnostics
10599 .into_iter()
10600 .filter_map(|update| {
10601 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10602 Some(DocumentDiagnosticsUpdate {
10603 diagnostics: self.lsp_to_document_diagnostics(
10604 abs_path,
10605 source_kind,
10606 update.server_id,
10607 update.diagnostics,
10608 &update.disk_based_sources,
10609 ),
10610 result_id: update.result_id,
10611 server_id: update.server_id,
10612 disk_based_sources: update.disk_based_sources,
10613 })
10614 })
10615 .collect();
10616 self.merge_diagnostic_entries(updates, merge, cx)?;
10617 Ok(())
10618 }
10619
10620 fn lsp_to_document_diagnostics(
10621 &mut self,
10622 document_abs_path: PathBuf,
10623 source_kind: DiagnosticSourceKind,
10624 server_id: LanguageServerId,
10625 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10626 disk_based_sources: &[String],
10627 ) -> DocumentDiagnostics {
10628 let mut diagnostics = Vec::default();
10629 let mut primary_diagnostic_group_ids = HashMap::default();
10630 let mut sources_by_group_id = HashMap::default();
10631 let mut supporting_diagnostics = HashMap::default();
10632
10633 let adapter = self.language_server_adapter_for_id(server_id);
10634
10635 // Ensure that primary diagnostics are always the most severe
10636 lsp_diagnostics
10637 .diagnostics
10638 .sort_by_key(|item| item.severity);
10639
10640 for diagnostic in &lsp_diagnostics.diagnostics {
10641 let source = diagnostic.source.as_ref();
10642 let range = range_from_lsp(diagnostic.range);
10643 let is_supporting = diagnostic
10644 .related_information
10645 .as_ref()
10646 .is_some_and(|infos| {
10647 infos.iter().any(|info| {
10648 primary_diagnostic_group_ids.contains_key(&(
10649 source,
10650 diagnostic.code.clone(),
10651 range_from_lsp(info.location.range),
10652 ))
10653 })
10654 });
10655
10656 let is_unnecessary = diagnostic
10657 .tags
10658 .as_ref()
10659 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10660
10661 let underline = self
10662 .language_server_adapter_for_id(server_id)
10663 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10664
10665 if is_supporting {
10666 supporting_diagnostics.insert(
10667 (source, diagnostic.code.clone(), range),
10668 (diagnostic.severity, is_unnecessary),
10669 );
10670 } else {
10671 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10672 let is_disk_based =
10673 source.is_some_and(|source| disk_based_sources.contains(source));
10674
10675 sources_by_group_id.insert(group_id, source);
10676 primary_diagnostic_group_ids
10677 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10678
10679 diagnostics.push(DiagnosticEntry {
10680 range,
10681 diagnostic: Diagnostic {
10682 source: diagnostic.source.clone(),
10683 source_kind,
10684 code: diagnostic.code.clone(),
10685 code_description: diagnostic
10686 .code_description
10687 .as_ref()
10688 .and_then(|d| d.href.clone()),
10689 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10690 markdown: adapter.as_ref().and_then(|adapter| {
10691 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10692 }),
10693 message: diagnostic.message.trim().to_string(),
10694 group_id,
10695 is_primary: true,
10696 is_disk_based,
10697 is_unnecessary,
10698 underline,
10699 data: diagnostic.data.clone(),
10700 },
10701 });
10702 if let Some(infos) = &diagnostic.related_information {
10703 for info in infos {
10704 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10705 let range = range_from_lsp(info.location.range);
10706 diagnostics.push(DiagnosticEntry {
10707 range,
10708 diagnostic: Diagnostic {
10709 source: diagnostic.source.clone(),
10710 source_kind,
10711 code: diagnostic.code.clone(),
10712 code_description: diagnostic
10713 .code_description
10714 .as_ref()
10715 .and_then(|d| d.href.clone()),
10716 severity: DiagnosticSeverity::INFORMATION,
10717 markdown: adapter.as_ref().and_then(|adapter| {
10718 adapter.diagnostic_message_to_markdown(&info.message)
10719 }),
10720 message: info.message.trim().to_string(),
10721 group_id,
10722 is_primary: false,
10723 is_disk_based,
10724 is_unnecessary: false,
10725 underline,
10726 data: diagnostic.data.clone(),
10727 },
10728 });
10729 }
10730 }
10731 }
10732 }
10733 }
10734
10735 for entry in &mut diagnostics {
10736 let diagnostic = &mut entry.diagnostic;
10737 if !diagnostic.is_primary {
10738 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10739 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10740 source,
10741 diagnostic.code.clone(),
10742 entry.range.clone(),
10743 )) {
10744 if let Some(severity) = severity {
10745 diagnostic.severity = severity;
10746 }
10747 diagnostic.is_unnecessary = is_unnecessary;
10748 }
10749 }
10750 }
10751
10752 DocumentDiagnostics {
10753 diagnostics,
10754 document_abs_path,
10755 version: lsp_diagnostics.version,
10756 }
10757 }
10758
10759 fn insert_newly_running_language_server(
10760 &mut self,
10761 adapter: Arc<CachedLspAdapter>,
10762 language_server: Arc<LanguageServer>,
10763 server_id: LanguageServerId,
10764 key: LanguageServerSeed,
10765 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10766 cx: &mut Context<Self>,
10767 ) {
10768 let Some(local) = self.as_local_mut() else {
10769 return;
10770 };
10771 // If the language server for this key doesn't match the server id, don't store the
10772 // server. Which will cause it to be dropped, killing the process
10773 if local
10774 .language_server_ids
10775 .get(&key)
10776 .map(|state| state.id != server_id)
10777 .unwrap_or(false)
10778 {
10779 return;
10780 }
10781
10782 // Update language_servers collection with Running variant of LanguageServerState
10783 // indicating that the server is up and running and ready
10784 let workspace_folders = workspace_folders.lock().clone();
10785 language_server.set_workspace_folders(workspace_folders);
10786
10787 local.language_servers.insert(
10788 server_id,
10789 LanguageServerState::Running {
10790 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10791 language_server.clone(),
10792 cx,
10793 ),
10794 adapter: adapter.clone(),
10795 server: language_server.clone(),
10796 simulate_disk_based_diagnostics_completion: None,
10797 },
10798 );
10799 local
10800 .languages
10801 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10802 if let Some(file_ops_caps) = language_server
10803 .capabilities()
10804 .workspace
10805 .as_ref()
10806 .and_then(|ws| ws.file_operations.as_ref())
10807 {
10808 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10809 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10810 if did_rename_caps.or(will_rename_caps).is_some() {
10811 let watcher = RenamePathsWatchedForServer::default()
10812 .with_did_rename_patterns(did_rename_caps)
10813 .with_will_rename_patterns(will_rename_caps);
10814 local
10815 .language_server_paths_watched_for_rename
10816 .insert(server_id, watcher);
10817 }
10818 }
10819
10820 self.language_server_statuses.insert(
10821 server_id,
10822 LanguageServerStatus {
10823 name: language_server.name(),
10824 pending_work: Default::default(),
10825 has_pending_diagnostic_updates: false,
10826 progress_tokens: Default::default(),
10827 worktree: Some(key.worktree_id),
10828 },
10829 );
10830
10831 cx.emit(LspStoreEvent::LanguageServerAdded(
10832 server_id,
10833 language_server.name(),
10834 Some(key.worktree_id),
10835 ));
10836 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
10837
10838 let server_capabilities = language_server.capabilities();
10839 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10840 downstream_client
10841 .send(proto::StartLanguageServer {
10842 project_id: *project_id,
10843 server: Some(proto::LanguageServer {
10844 id: server_id.to_proto(),
10845 name: language_server.name().to_string(),
10846 worktree_id: Some(key.worktree_id.to_proto()),
10847 }),
10848 capabilities: serde_json::to_string(&server_capabilities)
10849 .expect("serializing server LSP capabilities"),
10850 })
10851 .log_err();
10852 }
10853 self.lsp_server_capabilities
10854 .insert(server_id, server_capabilities);
10855
10856 // Tell the language server about every open buffer in the worktree that matches the language.
10857 // Also check for buffers in worktrees that reused this server
10858 let mut worktrees_using_server = vec![key.worktree_id];
10859 if let Some(local) = self.as_local() {
10860 // Find all worktrees that have this server in their language server tree
10861 for (worktree_id, servers) in &local.lsp_tree.instances {
10862 if *worktree_id != key.worktree_id {
10863 for server_map in servers.roots.values() {
10864 if server_map
10865 .values()
10866 .any(|(node, _)| node.id() == Some(server_id))
10867 {
10868 worktrees_using_server.push(*worktree_id);
10869 }
10870 }
10871 }
10872 }
10873 }
10874
10875 let mut buffer_paths_registered = Vec::new();
10876 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10877 let mut lsp_adapters = HashMap::default();
10878 for buffer_handle in buffer_store.buffers() {
10879 let buffer = buffer_handle.read(cx);
10880 let file = match File::from_dyn(buffer.file()) {
10881 Some(file) => file,
10882 None => continue,
10883 };
10884 let language = match buffer.language() {
10885 Some(language) => language,
10886 None => continue,
10887 };
10888
10889 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10890 || !lsp_adapters
10891 .entry(language.name())
10892 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
10893 .iter()
10894 .any(|a| a.name == key.name)
10895 {
10896 continue;
10897 }
10898 // didOpen
10899 let file = match file.as_local() {
10900 Some(file) => file,
10901 None => continue,
10902 };
10903
10904 let local = self.as_local_mut().unwrap();
10905
10906 let buffer_id = buffer.remote_id();
10907 if local.registered_buffers.contains_key(&buffer_id) {
10908 let versions = local
10909 .buffer_snapshots
10910 .entry(buffer_id)
10911 .or_default()
10912 .entry(server_id)
10913 .and_modify(|_| {
10914 assert!(
10915 false,
10916 "There should not be an existing snapshot for a newly inserted buffer"
10917 )
10918 })
10919 .or_insert_with(|| {
10920 vec![LspBufferSnapshot {
10921 version: 0,
10922 snapshot: buffer.text_snapshot(),
10923 }]
10924 });
10925
10926 let snapshot = versions.last().unwrap();
10927 let version = snapshot.version;
10928 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
10929 language_server.register_buffer(
10930 uri,
10931 adapter.language_id(&language.name()),
10932 version,
10933 buffer_handle.read(cx).text_with_original_line_endings(),
10934 );
10935 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10936 local
10937 .buffers_opened_in_servers
10938 .entry(buffer_id)
10939 .or_default()
10940 .insert(server_id);
10941 }
10942 buffer_handle.update(cx, |buffer, cx| {
10943 buffer.set_completion_triggers(
10944 server_id,
10945 language_server
10946 .capabilities()
10947 .completion_provider
10948 .as_ref()
10949 .and_then(|provider| {
10950 provider
10951 .trigger_characters
10952 .as_ref()
10953 .map(|characters| characters.iter().cloned().collect())
10954 })
10955 .unwrap_or_default(),
10956 cx,
10957 )
10958 });
10959 }
10960 });
10961
10962 for (buffer_id, abs_path) in buffer_paths_registered {
10963 cx.emit(LspStoreEvent::LanguageServerUpdate {
10964 language_server_id: server_id,
10965 name: Some(adapter.name()),
10966 message: proto::update_language_server::Variant::RegisteredForBuffer(
10967 proto::RegisteredForBuffer {
10968 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
10969 buffer_id: buffer_id.to_proto(),
10970 },
10971 ),
10972 });
10973 }
10974
10975 cx.notify();
10976 }
10977
10978 pub fn language_servers_running_disk_based_diagnostics(
10979 &self,
10980 ) -> impl Iterator<Item = LanguageServerId> + '_ {
10981 self.language_server_statuses
10982 .iter()
10983 .filter_map(|(id, status)| {
10984 if status.has_pending_diagnostic_updates {
10985 Some(*id)
10986 } else {
10987 None
10988 }
10989 })
10990 }
10991
10992 pub(crate) fn cancel_language_server_work_for_buffers(
10993 &mut self,
10994 buffers: impl IntoIterator<Item = Entity<Buffer>>,
10995 cx: &mut Context<Self>,
10996 ) {
10997 if let Some((client, project_id)) = self.upstream_client() {
10998 let request = client.request(proto::CancelLanguageServerWork {
10999 project_id,
11000 work: Some(proto::cancel_language_server_work::Work::Buffers(
11001 proto::cancel_language_server_work::Buffers {
11002 buffer_ids: buffers
11003 .into_iter()
11004 .map(|b| b.read(cx).remote_id().to_proto())
11005 .collect(),
11006 },
11007 )),
11008 });
11009 cx.background_spawn(request).detach_and_log_err(cx);
11010 } else if let Some(local) = self.as_local() {
11011 let servers = buffers
11012 .into_iter()
11013 .flat_map(|buffer| {
11014 buffer.update(cx, |buffer, cx| {
11015 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11016 })
11017 })
11018 .collect::<HashSet<_>>();
11019 for server_id in servers {
11020 self.cancel_language_server_work(server_id, None, cx);
11021 }
11022 }
11023 }
11024
11025 pub(crate) fn cancel_language_server_work(
11026 &mut self,
11027 server_id: LanguageServerId,
11028 token_to_cancel: Option<String>,
11029 cx: &mut Context<Self>,
11030 ) {
11031 if let Some(local) = self.as_local() {
11032 let status = self.language_server_statuses.get(&server_id);
11033 let server = local.language_servers.get(&server_id);
11034 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11035 {
11036 for (token, progress) in &status.pending_work {
11037 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11038 && token != token_to_cancel
11039 {
11040 continue;
11041 }
11042 if progress.is_cancellable {
11043 server
11044 .notify::<lsp::notification::WorkDoneProgressCancel>(
11045 WorkDoneProgressCancelParams {
11046 token: lsp::NumberOrString::String(token.clone()),
11047 },
11048 )
11049 .ok();
11050 }
11051 }
11052 }
11053 } else if let Some((client, project_id)) = self.upstream_client() {
11054 let request = client.request(proto::CancelLanguageServerWork {
11055 project_id,
11056 work: Some(
11057 proto::cancel_language_server_work::Work::LanguageServerWork(
11058 proto::cancel_language_server_work::LanguageServerWork {
11059 language_server_id: server_id.to_proto(),
11060 token: token_to_cancel,
11061 },
11062 ),
11063 ),
11064 });
11065 cx.background_spawn(request).detach_and_log_err(cx);
11066 }
11067 }
11068
11069 fn register_supplementary_language_server(
11070 &mut self,
11071 id: LanguageServerId,
11072 name: LanguageServerName,
11073 server: Arc<LanguageServer>,
11074 cx: &mut Context<Self>,
11075 ) {
11076 if let Some(local) = self.as_local_mut() {
11077 local
11078 .supplementary_language_servers
11079 .insert(id, (name.clone(), server));
11080 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11081 }
11082 }
11083
11084 fn unregister_supplementary_language_server(
11085 &mut self,
11086 id: LanguageServerId,
11087 cx: &mut Context<Self>,
11088 ) {
11089 if let Some(local) = self.as_local_mut() {
11090 local.supplementary_language_servers.remove(&id);
11091 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11092 }
11093 }
11094
11095 pub(crate) fn supplementary_language_servers(
11096 &self,
11097 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11098 self.as_local().into_iter().flat_map(|local| {
11099 local
11100 .supplementary_language_servers
11101 .iter()
11102 .map(|(id, (name, _))| (*id, name.clone()))
11103 })
11104 }
11105
11106 pub fn language_server_adapter_for_id(
11107 &self,
11108 id: LanguageServerId,
11109 ) -> Option<Arc<CachedLspAdapter>> {
11110 self.as_local()
11111 .and_then(|local| local.language_servers.get(&id))
11112 .and_then(|language_server_state| match language_server_state {
11113 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11114 _ => None,
11115 })
11116 }
11117
11118 pub(super) fn update_local_worktree_language_servers(
11119 &mut self,
11120 worktree_handle: &Entity<Worktree>,
11121 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11122 cx: &mut Context<Self>,
11123 ) {
11124 if changes.is_empty() {
11125 return;
11126 }
11127
11128 let Some(local) = self.as_local() else { return };
11129
11130 local.prettier_store.update(cx, |prettier_store, cx| {
11131 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11132 });
11133
11134 let worktree_id = worktree_handle.read(cx).id();
11135 let mut language_server_ids = local
11136 .language_server_ids
11137 .iter()
11138 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11139 .collect::<Vec<_>>();
11140 language_server_ids.sort();
11141 language_server_ids.dedup();
11142
11143 // let abs_path = worktree_handle.read(cx).abs_path();
11144 for server_id in &language_server_ids {
11145 if let Some(LanguageServerState::Running { server, .. }) =
11146 local.language_servers.get(server_id)
11147 && let Some(watched_paths) = local
11148 .language_server_watched_paths
11149 .get(server_id)
11150 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11151 {
11152 let params = lsp::DidChangeWatchedFilesParams {
11153 changes: changes
11154 .iter()
11155 .filter_map(|(path, _, change)| {
11156 if !watched_paths.is_match(path.as_std_path()) {
11157 return None;
11158 }
11159 let typ = match change {
11160 PathChange::Loaded => return None,
11161 PathChange::Added => lsp::FileChangeType::CREATED,
11162 PathChange::Removed => lsp::FileChangeType::DELETED,
11163 PathChange::Updated => lsp::FileChangeType::CHANGED,
11164 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11165 };
11166 let uri = lsp::Uri::from_file_path(
11167 worktree_handle.read(cx).absolutize(&path),
11168 )
11169 .ok()?;
11170 Some(lsp::FileEvent { uri, typ })
11171 })
11172 .collect(),
11173 };
11174 if !params.changes.is_empty() {
11175 server
11176 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11177 .ok();
11178 }
11179 }
11180 }
11181 for (path, _, _) in changes {
11182 if let Some(file_name) = path.file_name()
11183 && local.watched_manifest_filenames.contains(file_name)
11184 {
11185 self.request_workspace_config_refresh();
11186 break;
11187 }
11188 }
11189 }
11190
11191 pub fn wait_for_remote_buffer(
11192 &mut self,
11193 id: BufferId,
11194 cx: &mut Context<Self>,
11195 ) -> Task<Result<Entity<Buffer>>> {
11196 self.buffer_store.update(cx, |buffer_store, cx| {
11197 buffer_store.wait_for_remote_buffer(id, cx)
11198 })
11199 }
11200
11201 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11202 let mut result = proto::Symbol {
11203 language_server_name: symbol.language_server_name.0.to_string(),
11204 source_worktree_id: symbol.source_worktree_id.to_proto(),
11205 language_server_id: symbol.source_language_server_id.to_proto(),
11206 name: symbol.name.clone(),
11207 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11208 start: Some(proto::PointUtf16 {
11209 row: symbol.range.start.0.row,
11210 column: symbol.range.start.0.column,
11211 }),
11212 end: Some(proto::PointUtf16 {
11213 row: symbol.range.end.0.row,
11214 column: symbol.range.end.0.column,
11215 }),
11216 worktree_id: Default::default(),
11217 path: Default::default(),
11218 signature: Default::default(),
11219 };
11220 match &symbol.path {
11221 SymbolLocation::InProject(path) => {
11222 result.worktree_id = path.worktree_id.to_proto();
11223 result.path = path.path.to_proto();
11224 }
11225 SymbolLocation::OutsideProject {
11226 abs_path,
11227 signature,
11228 } => {
11229 result.path = abs_path.to_string_lossy().into_owned();
11230 result.signature = signature.to_vec();
11231 }
11232 }
11233 result
11234 }
11235
11236 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11237 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11238 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11239 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11240
11241 let path = if serialized_symbol.signature.is_empty() {
11242 SymbolLocation::InProject(ProjectPath {
11243 worktree_id,
11244 path: RelPath::from_proto(&serialized_symbol.path)
11245 .context("invalid symbol path")?,
11246 })
11247 } else {
11248 SymbolLocation::OutsideProject {
11249 abs_path: Path::new(&serialized_symbol.path).into(),
11250 signature: serialized_symbol
11251 .signature
11252 .try_into()
11253 .map_err(|_| anyhow!("invalid signature"))?,
11254 }
11255 };
11256
11257 let start = serialized_symbol.start.context("invalid start")?;
11258 let end = serialized_symbol.end.context("invalid end")?;
11259 Ok(CoreSymbol {
11260 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11261 source_worktree_id,
11262 source_language_server_id: LanguageServerId::from_proto(
11263 serialized_symbol.language_server_id,
11264 ),
11265 path,
11266 name: serialized_symbol.name,
11267 range: Unclipped(PointUtf16::new(start.row, start.column))
11268 ..Unclipped(PointUtf16::new(end.row, end.column)),
11269 kind,
11270 })
11271 }
11272
11273 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11274 let mut serialized_completion = proto::Completion {
11275 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11276 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11277 new_text: completion.new_text.clone(),
11278 ..proto::Completion::default()
11279 };
11280 match &completion.source {
11281 CompletionSource::Lsp {
11282 insert_range,
11283 server_id,
11284 lsp_completion,
11285 lsp_defaults,
11286 resolved,
11287 } => {
11288 let (old_insert_start, old_insert_end) = insert_range
11289 .as_ref()
11290 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11291 .unzip();
11292
11293 serialized_completion.old_insert_start = old_insert_start;
11294 serialized_completion.old_insert_end = old_insert_end;
11295 serialized_completion.source = proto::completion::Source::Lsp as i32;
11296 serialized_completion.server_id = server_id.0 as u64;
11297 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11298 serialized_completion.lsp_defaults = lsp_defaults
11299 .as_deref()
11300 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11301 serialized_completion.resolved = *resolved;
11302 }
11303 CompletionSource::BufferWord {
11304 word_range,
11305 resolved,
11306 } => {
11307 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11308 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11309 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11310 serialized_completion.resolved = *resolved;
11311 }
11312 CompletionSource::Custom => {
11313 serialized_completion.source = proto::completion::Source::Custom as i32;
11314 serialized_completion.resolved = true;
11315 }
11316 CompletionSource::Dap { sort_text } => {
11317 serialized_completion.source = proto::completion::Source::Dap as i32;
11318 serialized_completion.sort_text = Some(sort_text.clone());
11319 }
11320 }
11321
11322 serialized_completion
11323 }
11324
11325 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11326 let old_replace_start = completion
11327 .old_replace_start
11328 .and_then(deserialize_anchor)
11329 .context("invalid old start")?;
11330 let old_replace_end = completion
11331 .old_replace_end
11332 .and_then(deserialize_anchor)
11333 .context("invalid old end")?;
11334 let insert_range = {
11335 match completion.old_insert_start.zip(completion.old_insert_end) {
11336 Some((start, end)) => {
11337 let start = deserialize_anchor(start).context("invalid insert old start")?;
11338 let end = deserialize_anchor(end).context("invalid insert old end")?;
11339 Some(start..end)
11340 }
11341 None => None,
11342 }
11343 };
11344 Ok(CoreCompletion {
11345 replace_range: old_replace_start..old_replace_end,
11346 new_text: completion.new_text,
11347 source: match proto::completion::Source::from_i32(completion.source) {
11348 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11349 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11350 insert_range,
11351 server_id: LanguageServerId::from_proto(completion.server_id),
11352 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11353 lsp_defaults: completion
11354 .lsp_defaults
11355 .as_deref()
11356 .map(serde_json::from_slice)
11357 .transpose()?,
11358 resolved: completion.resolved,
11359 },
11360 Some(proto::completion::Source::BufferWord) => {
11361 let word_range = completion
11362 .buffer_word_start
11363 .and_then(deserialize_anchor)
11364 .context("invalid buffer word start")?
11365 ..completion
11366 .buffer_word_end
11367 .and_then(deserialize_anchor)
11368 .context("invalid buffer word end")?;
11369 CompletionSource::BufferWord {
11370 word_range,
11371 resolved: completion.resolved,
11372 }
11373 }
11374 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11375 sort_text: completion
11376 .sort_text
11377 .context("expected sort text to exist")?,
11378 },
11379 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11380 },
11381 })
11382 }
11383
11384 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11385 let (kind, lsp_action) = match &action.lsp_action {
11386 LspAction::Action(code_action) => (
11387 proto::code_action::Kind::Action as i32,
11388 serde_json::to_vec(code_action).unwrap(),
11389 ),
11390 LspAction::Command(command) => (
11391 proto::code_action::Kind::Command as i32,
11392 serde_json::to_vec(command).unwrap(),
11393 ),
11394 LspAction::CodeLens(code_lens) => (
11395 proto::code_action::Kind::CodeLens as i32,
11396 serde_json::to_vec(code_lens).unwrap(),
11397 ),
11398 };
11399
11400 proto::CodeAction {
11401 server_id: action.server_id.0 as u64,
11402 start: Some(serialize_anchor(&action.range.start)),
11403 end: Some(serialize_anchor(&action.range.end)),
11404 lsp_action,
11405 kind,
11406 resolved: action.resolved,
11407 }
11408 }
11409
11410 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11411 let start = action
11412 .start
11413 .and_then(deserialize_anchor)
11414 .context("invalid start")?;
11415 let end = action
11416 .end
11417 .and_then(deserialize_anchor)
11418 .context("invalid end")?;
11419 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11420 Some(proto::code_action::Kind::Action) => {
11421 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11422 }
11423 Some(proto::code_action::Kind::Command) => {
11424 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11425 }
11426 Some(proto::code_action::Kind::CodeLens) => {
11427 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11428 }
11429 None => anyhow::bail!("Unknown action kind {}", action.kind),
11430 };
11431 Ok(CodeAction {
11432 server_id: LanguageServerId(action.server_id as usize),
11433 range: start..end,
11434 resolved: action.resolved,
11435 lsp_action,
11436 })
11437 }
11438
11439 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11440 match &formatting_result {
11441 Ok(_) => self.last_formatting_failure = None,
11442 Err(error) => {
11443 let error_string = format!("{error:#}");
11444 log::error!("Formatting failed: {error_string}");
11445 self.last_formatting_failure
11446 .replace(error_string.lines().join(" "));
11447 }
11448 }
11449 }
11450
11451 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11452 self.lsp_server_capabilities.remove(&for_server);
11453 for lsp_data in self.lsp_data.values_mut() {
11454 lsp_data.remove_server_data(for_server);
11455 }
11456 if let Some(local) = self.as_local_mut() {
11457 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11458 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11459 buffer_servers.remove(&for_server);
11460 }
11461 }
11462 }
11463
11464 pub fn result_id(
11465 &self,
11466 server_id: LanguageServerId,
11467 buffer_id: BufferId,
11468 cx: &App,
11469 ) -> Option<String> {
11470 let abs_path = self
11471 .buffer_store
11472 .read(cx)
11473 .get(buffer_id)
11474 .and_then(|b| File::from_dyn(b.read(cx).file()))
11475 .map(|f| f.abs_path(cx))?;
11476 self.as_local()?
11477 .buffer_pull_diagnostics_result_ids
11478 .get(&server_id)?
11479 .get(&abs_path)?
11480 .clone()
11481 }
11482
11483 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11484 let Some(local) = self.as_local() else {
11485 return HashMap::default();
11486 };
11487 local
11488 .buffer_pull_diagnostics_result_ids
11489 .get(&server_id)
11490 .into_iter()
11491 .flatten()
11492 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11493 .collect()
11494 }
11495
11496 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11497 if let Some(LanguageServerState::Running {
11498 workspace_refresh_task: Some(workspace_refresh_task),
11499 ..
11500 }) = self
11501 .as_local_mut()
11502 .and_then(|local| local.language_servers.get_mut(&server_id))
11503 {
11504 workspace_refresh_task.refresh_tx.try_send(()).ok();
11505 }
11506 }
11507
11508 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11509 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11510 return;
11511 };
11512 let Some(local) = self.as_local_mut() else {
11513 return;
11514 };
11515
11516 for server_id in buffer.update(cx, |buffer, cx| {
11517 local.language_server_ids_for_buffer(buffer, cx)
11518 }) {
11519 if let Some(LanguageServerState::Running {
11520 workspace_refresh_task: Some(workspace_refresh_task),
11521 ..
11522 }) = local.language_servers.get_mut(&server_id)
11523 {
11524 workspace_refresh_task.refresh_tx.try_send(()).ok();
11525 }
11526 }
11527 }
11528
11529 fn apply_workspace_diagnostic_report(
11530 &mut self,
11531 server_id: LanguageServerId,
11532 report: lsp::WorkspaceDiagnosticReportResult,
11533 cx: &mut Context<Self>,
11534 ) {
11535 let workspace_diagnostics =
11536 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11537 let mut unchanged_buffers = HashSet::default();
11538 let mut changed_buffers = HashSet::default();
11539 let workspace_diagnostics_updates = workspace_diagnostics
11540 .into_iter()
11541 .filter_map(
11542 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11543 LspPullDiagnostics::Response {
11544 server_id,
11545 uri,
11546 diagnostics,
11547 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11548 LspPullDiagnostics::Default => None,
11549 },
11550 )
11551 .fold(
11552 HashMap::default(),
11553 |mut acc, (server_id, uri, diagnostics, version)| {
11554 let (result_id, diagnostics) = match diagnostics {
11555 PulledDiagnostics::Unchanged { result_id } => {
11556 unchanged_buffers.insert(uri.clone());
11557 (Some(result_id), Vec::new())
11558 }
11559 PulledDiagnostics::Changed {
11560 result_id,
11561 diagnostics,
11562 } => {
11563 changed_buffers.insert(uri.clone());
11564 (result_id, diagnostics)
11565 }
11566 };
11567 let disk_based_sources = Cow::Owned(
11568 self.language_server_adapter_for_id(server_id)
11569 .as_ref()
11570 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11571 .unwrap_or(&[])
11572 .to_vec(),
11573 );
11574 acc.entry(server_id)
11575 .or_insert_with(Vec::new)
11576 .push(DocumentDiagnosticsUpdate {
11577 server_id,
11578 diagnostics: lsp::PublishDiagnosticsParams {
11579 uri,
11580 diagnostics,
11581 version,
11582 },
11583 result_id,
11584 disk_based_sources,
11585 });
11586 acc
11587 },
11588 );
11589
11590 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11591 self.merge_lsp_diagnostics(
11592 DiagnosticSourceKind::Pulled,
11593 diagnostic_updates,
11594 |buffer, old_diagnostic, cx| {
11595 File::from_dyn(buffer.file())
11596 .and_then(|file| {
11597 let abs_path = file.as_local()?.abs_path(cx);
11598 lsp::Uri::from_file_path(abs_path).ok()
11599 })
11600 .is_none_or(|buffer_uri| {
11601 unchanged_buffers.contains(&buffer_uri)
11602 || match old_diagnostic.source_kind {
11603 DiagnosticSourceKind::Pulled => {
11604 !changed_buffers.contains(&buffer_uri)
11605 }
11606 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11607 true
11608 }
11609 }
11610 })
11611 },
11612 cx,
11613 )
11614 .log_err();
11615 }
11616 }
11617
11618 fn register_server_capabilities(
11619 &mut self,
11620 server_id: LanguageServerId,
11621 params: lsp::RegistrationParams,
11622 cx: &mut Context<Self>,
11623 ) -> anyhow::Result<()> {
11624 let server = self
11625 .language_server_for_id(server_id)
11626 .with_context(|| format!("no server {server_id} found"))?;
11627 for reg in params.registrations {
11628 match reg.method.as_str() {
11629 "workspace/didChangeWatchedFiles" => {
11630 if let Some(options) = reg.register_options {
11631 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11632 let caps = serde_json::from_value(options)?;
11633 local_lsp_store
11634 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11635 true
11636 } else {
11637 false
11638 };
11639 if notify {
11640 notify_server_capabilities_updated(&server, cx);
11641 }
11642 }
11643 }
11644 "workspace/didChangeConfiguration" => {
11645 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11646 }
11647 "workspace/didChangeWorkspaceFolders" => {
11648 // In this case register options is an empty object, we can ignore it
11649 let caps = lsp::WorkspaceFoldersServerCapabilities {
11650 supported: Some(true),
11651 change_notifications: Some(OneOf::Right(reg.id)),
11652 };
11653 server.update_capabilities(|capabilities| {
11654 capabilities
11655 .workspace
11656 .get_or_insert_default()
11657 .workspace_folders = Some(caps);
11658 });
11659 notify_server_capabilities_updated(&server, cx);
11660 }
11661 "workspace/symbol" => {
11662 let options = parse_register_capabilities(reg)?;
11663 server.update_capabilities(|capabilities| {
11664 capabilities.workspace_symbol_provider = Some(options);
11665 });
11666 notify_server_capabilities_updated(&server, cx);
11667 }
11668 "workspace/fileOperations" => {
11669 if let Some(options) = reg.register_options {
11670 let caps = serde_json::from_value(options)?;
11671 server.update_capabilities(|capabilities| {
11672 capabilities
11673 .workspace
11674 .get_or_insert_default()
11675 .file_operations = Some(caps);
11676 });
11677 notify_server_capabilities_updated(&server, cx);
11678 }
11679 }
11680 "workspace/executeCommand" => {
11681 if let Some(options) = reg.register_options {
11682 let options = serde_json::from_value(options)?;
11683 server.update_capabilities(|capabilities| {
11684 capabilities.execute_command_provider = Some(options);
11685 });
11686 notify_server_capabilities_updated(&server, cx);
11687 }
11688 }
11689 "textDocument/rangeFormatting" => {
11690 let options = parse_register_capabilities(reg)?;
11691 server.update_capabilities(|capabilities| {
11692 capabilities.document_range_formatting_provider = Some(options);
11693 });
11694 notify_server_capabilities_updated(&server, cx);
11695 }
11696 "textDocument/onTypeFormatting" => {
11697 if let Some(options) = reg
11698 .register_options
11699 .map(serde_json::from_value)
11700 .transpose()?
11701 {
11702 server.update_capabilities(|capabilities| {
11703 capabilities.document_on_type_formatting_provider = Some(options);
11704 });
11705 notify_server_capabilities_updated(&server, cx);
11706 }
11707 }
11708 "textDocument/formatting" => {
11709 let options = parse_register_capabilities(reg)?;
11710 server.update_capabilities(|capabilities| {
11711 capabilities.document_formatting_provider = Some(options);
11712 });
11713 notify_server_capabilities_updated(&server, cx);
11714 }
11715 "textDocument/rename" => {
11716 let options = parse_register_capabilities(reg)?;
11717 server.update_capabilities(|capabilities| {
11718 capabilities.rename_provider = Some(options);
11719 });
11720 notify_server_capabilities_updated(&server, cx);
11721 }
11722 "textDocument/inlayHint" => {
11723 let options = parse_register_capabilities(reg)?;
11724 server.update_capabilities(|capabilities| {
11725 capabilities.inlay_hint_provider = Some(options);
11726 });
11727 notify_server_capabilities_updated(&server, cx);
11728 }
11729 "textDocument/documentSymbol" => {
11730 let options = parse_register_capabilities(reg)?;
11731 server.update_capabilities(|capabilities| {
11732 capabilities.document_symbol_provider = Some(options);
11733 });
11734 notify_server_capabilities_updated(&server, cx);
11735 }
11736 "textDocument/codeAction" => {
11737 let options = parse_register_capabilities(reg)?;
11738 let provider = match options {
11739 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11740 OneOf::Right(caps) => caps,
11741 };
11742 server.update_capabilities(|capabilities| {
11743 capabilities.code_action_provider = Some(provider);
11744 });
11745 notify_server_capabilities_updated(&server, cx);
11746 }
11747 "textDocument/definition" => {
11748 let options = parse_register_capabilities(reg)?;
11749 server.update_capabilities(|capabilities| {
11750 capabilities.definition_provider = Some(options);
11751 });
11752 notify_server_capabilities_updated(&server, cx);
11753 }
11754 "textDocument/completion" => {
11755 if let Some(caps) = reg
11756 .register_options
11757 .map(serde_json::from_value)
11758 .transpose()?
11759 {
11760 server.update_capabilities(|capabilities| {
11761 capabilities.completion_provider = Some(caps);
11762 });
11763 notify_server_capabilities_updated(&server, cx);
11764 }
11765 }
11766 "textDocument/hover" => {
11767 let options = parse_register_capabilities(reg)?;
11768 let provider = match options {
11769 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11770 OneOf::Right(caps) => caps,
11771 };
11772 server.update_capabilities(|capabilities| {
11773 capabilities.hover_provider = Some(provider);
11774 });
11775 notify_server_capabilities_updated(&server, cx);
11776 }
11777 "textDocument/signatureHelp" => {
11778 if let Some(caps) = reg
11779 .register_options
11780 .map(serde_json::from_value)
11781 .transpose()?
11782 {
11783 server.update_capabilities(|capabilities| {
11784 capabilities.signature_help_provider = Some(caps);
11785 });
11786 notify_server_capabilities_updated(&server, cx);
11787 }
11788 }
11789 "textDocument/didChange" => {
11790 if let Some(sync_kind) = reg
11791 .register_options
11792 .and_then(|opts| opts.get("syncKind").cloned())
11793 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11794 .transpose()?
11795 {
11796 server.update_capabilities(|capabilities| {
11797 let mut sync_options =
11798 Self::take_text_document_sync_options(capabilities);
11799 sync_options.change = Some(sync_kind);
11800 capabilities.text_document_sync =
11801 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11802 });
11803 notify_server_capabilities_updated(&server, cx);
11804 }
11805 }
11806 "textDocument/didSave" => {
11807 if let Some(include_text) = reg
11808 .register_options
11809 .map(|opts| {
11810 let transpose = opts
11811 .get("includeText")
11812 .cloned()
11813 .map(serde_json::from_value::<Option<bool>>)
11814 .transpose();
11815 match transpose {
11816 Ok(value) => Ok(value.flatten()),
11817 Err(e) => Err(e),
11818 }
11819 })
11820 .transpose()?
11821 {
11822 server.update_capabilities(|capabilities| {
11823 let mut sync_options =
11824 Self::take_text_document_sync_options(capabilities);
11825 sync_options.save =
11826 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11827 include_text,
11828 }));
11829 capabilities.text_document_sync =
11830 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11831 });
11832 notify_server_capabilities_updated(&server, cx);
11833 }
11834 }
11835 "textDocument/codeLens" => {
11836 if let Some(caps) = reg
11837 .register_options
11838 .map(serde_json::from_value)
11839 .transpose()?
11840 {
11841 server.update_capabilities(|capabilities| {
11842 capabilities.code_lens_provider = Some(caps);
11843 });
11844 notify_server_capabilities_updated(&server, cx);
11845 }
11846 }
11847 "textDocument/diagnostic" => {
11848 if let Some(caps) = reg
11849 .register_options
11850 .map(serde_json::from_value)
11851 .transpose()?
11852 {
11853 let state = self
11854 .as_local_mut()
11855 .context("Expected LSP Store to be local")?
11856 .language_servers
11857 .get_mut(&server_id)
11858 .context("Could not obtain Language Servers state")?;
11859 server.update_capabilities(|capabilities| {
11860 capabilities.diagnostic_provider = Some(caps);
11861 });
11862 if let LanguageServerState::Running {
11863 workspace_refresh_task,
11864 ..
11865 } = state
11866 && workspace_refresh_task.is_none()
11867 {
11868 *workspace_refresh_task =
11869 lsp_workspace_diagnostics_refresh(server.clone(), cx)
11870 }
11871
11872 notify_server_capabilities_updated(&server, cx);
11873 }
11874 }
11875 "textDocument/documentColor" => {
11876 let options = parse_register_capabilities(reg)?;
11877 let provider = match options {
11878 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11879 OneOf::Right(caps) => caps,
11880 };
11881 server.update_capabilities(|capabilities| {
11882 capabilities.color_provider = Some(provider);
11883 });
11884 notify_server_capabilities_updated(&server, cx);
11885 }
11886 _ => log::warn!("unhandled capability registration: {reg:?}"),
11887 }
11888 }
11889
11890 Ok(())
11891 }
11892
11893 fn unregister_server_capabilities(
11894 &mut self,
11895 server_id: LanguageServerId,
11896 params: lsp::UnregistrationParams,
11897 cx: &mut Context<Self>,
11898 ) -> anyhow::Result<()> {
11899 let server = self
11900 .language_server_for_id(server_id)
11901 .with_context(|| format!("no server {server_id} found"))?;
11902 for unreg in params.unregisterations.iter() {
11903 match unreg.method.as_str() {
11904 "workspace/didChangeWatchedFiles" => {
11905 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11906 local_lsp_store
11907 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11908 true
11909 } else {
11910 false
11911 };
11912 if notify {
11913 notify_server_capabilities_updated(&server, cx);
11914 }
11915 }
11916 "workspace/didChangeConfiguration" => {
11917 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11918 }
11919 "workspace/didChangeWorkspaceFolders" => {
11920 server.update_capabilities(|capabilities| {
11921 capabilities
11922 .workspace
11923 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11924 workspace_folders: None,
11925 file_operations: None,
11926 })
11927 .workspace_folders = None;
11928 });
11929 notify_server_capabilities_updated(&server, cx);
11930 }
11931 "workspace/symbol" => {
11932 server.update_capabilities(|capabilities| {
11933 capabilities.workspace_symbol_provider = None
11934 });
11935 notify_server_capabilities_updated(&server, cx);
11936 }
11937 "workspace/fileOperations" => {
11938 server.update_capabilities(|capabilities| {
11939 capabilities
11940 .workspace
11941 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11942 workspace_folders: None,
11943 file_operations: None,
11944 })
11945 .file_operations = None;
11946 });
11947 notify_server_capabilities_updated(&server, cx);
11948 }
11949 "workspace/executeCommand" => {
11950 server.update_capabilities(|capabilities| {
11951 capabilities.execute_command_provider = None;
11952 });
11953 notify_server_capabilities_updated(&server, cx);
11954 }
11955 "textDocument/rangeFormatting" => {
11956 server.update_capabilities(|capabilities| {
11957 capabilities.document_range_formatting_provider = None
11958 });
11959 notify_server_capabilities_updated(&server, cx);
11960 }
11961 "textDocument/onTypeFormatting" => {
11962 server.update_capabilities(|capabilities| {
11963 capabilities.document_on_type_formatting_provider = None;
11964 });
11965 notify_server_capabilities_updated(&server, cx);
11966 }
11967 "textDocument/formatting" => {
11968 server.update_capabilities(|capabilities| {
11969 capabilities.document_formatting_provider = None;
11970 });
11971 notify_server_capabilities_updated(&server, cx);
11972 }
11973 "textDocument/rename" => {
11974 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11975 notify_server_capabilities_updated(&server, cx);
11976 }
11977 "textDocument/codeAction" => {
11978 server.update_capabilities(|capabilities| {
11979 capabilities.code_action_provider = None;
11980 });
11981 notify_server_capabilities_updated(&server, cx);
11982 }
11983 "textDocument/definition" => {
11984 server.update_capabilities(|capabilities| {
11985 capabilities.definition_provider = None;
11986 });
11987 notify_server_capabilities_updated(&server, cx);
11988 }
11989 "textDocument/completion" => {
11990 server.update_capabilities(|capabilities| {
11991 capabilities.completion_provider = None;
11992 });
11993 notify_server_capabilities_updated(&server, cx);
11994 }
11995 "textDocument/hover" => {
11996 server.update_capabilities(|capabilities| {
11997 capabilities.hover_provider = None;
11998 });
11999 notify_server_capabilities_updated(&server, cx);
12000 }
12001 "textDocument/signatureHelp" => {
12002 server.update_capabilities(|capabilities| {
12003 capabilities.signature_help_provider = None;
12004 });
12005 notify_server_capabilities_updated(&server, cx);
12006 }
12007 "textDocument/didChange" => {
12008 server.update_capabilities(|capabilities| {
12009 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12010 sync_options.change = None;
12011 capabilities.text_document_sync =
12012 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12013 });
12014 notify_server_capabilities_updated(&server, cx);
12015 }
12016 "textDocument/didSave" => {
12017 server.update_capabilities(|capabilities| {
12018 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12019 sync_options.save = None;
12020 capabilities.text_document_sync =
12021 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12022 });
12023 notify_server_capabilities_updated(&server, cx);
12024 }
12025 "textDocument/codeLens" => {
12026 server.update_capabilities(|capabilities| {
12027 capabilities.code_lens_provider = None;
12028 });
12029 notify_server_capabilities_updated(&server, cx);
12030 }
12031 "textDocument/diagnostic" => {
12032 server.update_capabilities(|capabilities| {
12033 capabilities.diagnostic_provider = None;
12034 });
12035 let state = self
12036 .as_local_mut()
12037 .context("Expected LSP Store to be local")?
12038 .language_servers
12039 .get_mut(&server_id)
12040 .context("Could not obtain Language Servers state")?;
12041 if let LanguageServerState::Running {
12042 workspace_refresh_task,
12043 ..
12044 } = state
12045 {
12046 _ = workspace_refresh_task.take();
12047 }
12048 notify_server_capabilities_updated(&server, cx);
12049 }
12050 "textDocument/documentColor" => {
12051 server.update_capabilities(|capabilities| {
12052 capabilities.color_provider = None;
12053 });
12054 notify_server_capabilities_updated(&server, cx);
12055 }
12056 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12057 }
12058 }
12059
12060 Ok(())
12061 }
12062
12063 async fn deduplicate_range_based_lsp_requests<T>(
12064 lsp_store: &Entity<Self>,
12065 server_id: Option<LanguageServerId>,
12066 lsp_request_id: LspRequestId,
12067 proto_request: &T::ProtoRequest,
12068 range: Range<Anchor>,
12069 cx: &mut AsyncApp,
12070 ) -> Result<()>
12071 where
12072 T: LspCommand,
12073 T::ProtoRequest: proto::LspRequestMessage,
12074 {
12075 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12076 let version = deserialize_version(proto_request.buffer_version());
12077 let buffer = lsp_store.update(cx, |this, cx| {
12078 this.buffer_store.read(cx).get_existing(buffer_id)
12079 })??;
12080 buffer
12081 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12082 .await?;
12083 lsp_store.update(cx, |lsp_store, cx| {
12084 let lsp_data = lsp_store
12085 .lsp_data
12086 .entry(buffer_id)
12087 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12088 let chunks_queried_for = lsp_data
12089 .inlay_hints
12090 .applicable_chunks(&[range])
12091 .collect::<Vec<_>>();
12092 match chunks_queried_for.as_slice() {
12093 &[chunk] => {
12094 let key = LspKey {
12095 request_type: TypeId::of::<T>(),
12096 server_queried: server_id,
12097 };
12098 let previous_request = lsp_data
12099 .chunk_lsp_requests
12100 .entry(key)
12101 .or_default()
12102 .insert(chunk, lsp_request_id);
12103 if let Some((previous_request, running_requests)) =
12104 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12105 {
12106 running_requests.remove(&previous_request);
12107 }
12108 }
12109 _ambiguous_chunks => {
12110 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12111 // there, a buffer version-based check will be performed and outdated requests discarded.
12112 }
12113 }
12114 anyhow::Ok(())
12115 })??;
12116
12117 Ok(())
12118 }
12119
12120 async fn query_lsp_locally<T>(
12121 lsp_store: Entity<Self>,
12122 for_server_id: Option<LanguageServerId>,
12123 sender_id: proto::PeerId,
12124 lsp_request_id: LspRequestId,
12125 proto_request: T::ProtoRequest,
12126 position: Option<Anchor>,
12127 cx: &mut AsyncApp,
12128 ) -> Result<()>
12129 where
12130 T: LspCommand + Clone,
12131 T::ProtoRequest: proto::LspRequestMessage,
12132 <T::ProtoRequest as proto::RequestMessage>::Response:
12133 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12134 {
12135 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12136 let version = deserialize_version(proto_request.buffer_version());
12137 let buffer = lsp_store.update(cx, |this, cx| {
12138 this.buffer_store.read(cx).get_existing(buffer_id)
12139 })??;
12140 buffer
12141 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12142 .await?;
12143 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12144 let request =
12145 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12146 let key = LspKey {
12147 request_type: TypeId::of::<T>(),
12148 server_queried: for_server_id,
12149 };
12150 lsp_store.update(cx, |lsp_store, cx| {
12151 let request_task = match for_server_id {
12152 Some(server_id) => {
12153 let server_task = lsp_store.request_lsp(
12154 buffer.clone(),
12155 LanguageServerToQuery::Other(server_id),
12156 request.clone(),
12157 cx,
12158 );
12159 cx.background_spawn(async move {
12160 let mut responses = Vec::new();
12161 match server_task.await {
12162 Ok(response) => responses.push((server_id, response)),
12163 Err(e) => log::error!(
12164 "Error handling response for request {request:?}: {e:#}"
12165 ),
12166 }
12167 responses
12168 })
12169 }
12170 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12171 };
12172 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12173 if T::ProtoRequest::stop_previous_requests() {
12174 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12175 lsp_requests.clear();
12176 }
12177 }
12178 lsp_data.lsp_requests.entry(key).or_default().insert(
12179 lsp_request_id,
12180 cx.spawn(async move |lsp_store, cx| {
12181 let response = request_task.await;
12182 lsp_store
12183 .update(cx, |lsp_store, cx| {
12184 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12185 {
12186 let response = response
12187 .into_iter()
12188 .map(|(server_id, response)| {
12189 (
12190 server_id.to_proto(),
12191 T::response_to_proto(
12192 response,
12193 lsp_store,
12194 sender_id,
12195 &buffer_version,
12196 cx,
12197 )
12198 .into(),
12199 )
12200 })
12201 .collect::<HashMap<_, _>>();
12202 match client.send_lsp_response::<T::ProtoRequest>(
12203 project_id,
12204 lsp_request_id,
12205 response,
12206 ) {
12207 Ok(()) => {}
12208 Err(e) => {
12209 log::error!("Failed to send LSP response: {e:#}",)
12210 }
12211 }
12212 }
12213 })
12214 .ok();
12215 }),
12216 );
12217 })?;
12218 Ok(())
12219 }
12220
12221 fn take_text_document_sync_options(
12222 capabilities: &mut lsp::ServerCapabilities,
12223 ) -> lsp::TextDocumentSyncOptions {
12224 match capabilities.text_document_sync.take() {
12225 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12226 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12227 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12228 sync_options.change = Some(sync_kind);
12229 sync_options
12230 }
12231 None => lsp::TextDocumentSyncOptions::default(),
12232 }
12233 }
12234
12235 #[cfg(any(test, feature = "test-support"))]
12236 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12237 Some(
12238 self.lsp_data
12239 .get_mut(&buffer_id)?
12240 .code_lens
12241 .take()?
12242 .update
12243 .take()?
12244 .1,
12245 )
12246 }
12247
12248 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12249 self.downstream_client.clone()
12250 }
12251
12252 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12253 self.worktree_store.clone()
12254 }
12255
12256 /// Gets what's stored in the LSP data for the given buffer.
12257 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12258 self.lsp_data.get_mut(&buffer_id)
12259 }
12260
12261 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12262 /// new [`BufferLspData`] will be created to replace the previous state.
12263 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12264 let (buffer_id, buffer_version) =
12265 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12266 let lsp_data = self
12267 .lsp_data
12268 .entry(buffer_id)
12269 .or_insert_with(|| BufferLspData::new(buffer, cx));
12270 if buffer_version.changed_since(&lsp_data.buffer_version) {
12271 *lsp_data = BufferLspData::new(buffer, cx);
12272 }
12273 lsp_data
12274 }
12275}
12276
12277// Registration with registerOptions as null, should fallback to true.
12278// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12279fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12280 reg: lsp::Registration,
12281) -> Result<OneOf<bool, T>> {
12282 Ok(match reg.register_options {
12283 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12284 None => OneOf::Left(true),
12285 })
12286}
12287
12288fn subscribe_to_binary_statuses(
12289 languages: &Arc<LanguageRegistry>,
12290 cx: &mut Context<'_, LspStore>,
12291) -> Task<()> {
12292 let mut server_statuses = languages.language_server_binary_statuses();
12293 cx.spawn(async move |lsp_store, cx| {
12294 while let Some((server_name, binary_status)) = server_statuses.next().await {
12295 if lsp_store
12296 .update(cx, |_, cx| {
12297 let mut message = None;
12298 let binary_status = match binary_status {
12299 BinaryStatus::None => proto::ServerBinaryStatus::None,
12300 BinaryStatus::CheckingForUpdate => {
12301 proto::ServerBinaryStatus::CheckingForUpdate
12302 }
12303 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12304 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12305 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12306 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12307 BinaryStatus::Failed { error } => {
12308 message = Some(error);
12309 proto::ServerBinaryStatus::Failed
12310 }
12311 };
12312 cx.emit(LspStoreEvent::LanguageServerUpdate {
12313 // Binary updates are about the binary that might not have any language server id at that point.
12314 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12315 language_server_id: LanguageServerId(0),
12316 name: Some(server_name),
12317 message: proto::update_language_server::Variant::StatusUpdate(
12318 proto::StatusUpdate {
12319 message,
12320 status: Some(proto::status_update::Status::Binary(
12321 binary_status as i32,
12322 )),
12323 },
12324 ),
12325 });
12326 })
12327 .is_err()
12328 {
12329 break;
12330 }
12331 }
12332 })
12333}
12334
12335fn lsp_workspace_diagnostics_refresh(
12336 server: Arc<LanguageServer>,
12337 cx: &mut Context<'_, LspStore>,
12338) -> Option<WorkspaceRefreshTask> {
12339 let identifier = match server.capabilities().diagnostic_provider? {
12340 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12341 if !diagnostic_options.workspace_diagnostics {
12342 return None;
12343 }
12344 diagnostic_options.identifier
12345 }
12346 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12347 let diagnostic_options = registration_options.diagnostic_options;
12348 if !diagnostic_options.workspace_diagnostics {
12349 return None;
12350 }
12351 diagnostic_options.identifier
12352 }
12353 };
12354
12355 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12356 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12357 refresh_tx.try_send(()).ok();
12358
12359 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12360 let mut attempts = 0;
12361 let max_attempts = 50;
12362 let mut requests = 0;
12363
12364 loop {
12365 let Some(()) = refresh_rx.recv().await else {
12366 return;
12367 };
12368
12369 'request: loop {
12370 requests += 1;
12371 if attempts > max_attempts {
12372 log::error!(
12373 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12374 );
12375 return;
12376 }
12377 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12378 cx.background_executor()
12379 .timer(Duration::from_millis(backoff_millis))
12380 .await;
12381 attempts += 1;
12382
12383 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12384 lsp_store
12385 .all_result_ids(server.server_id())
12386 .into_iter()
12387 .filter_map(|(abs_path, result_id)| {
12388 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12389 Some(lsp::PreviousResultId {
12390 uri,
12391 value: result_id,
12392 })
12393 })
12394 .collect()
12395 }) else {
12396 return;
12397 };
12398
12399 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12400
12401 progress_rx.try_recv().ok();
12402 let timer =
12403 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12404 let progress = pin!(progress_rx.recv().fuse());
12405 let response_result = server
12406 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12407 lsp::WorkspaceDiagnosticParams {
12408 previous_result_ids,
12409 identifier: identifier.clone(),
12410 work_done_progress_params: Default::default(),
12411 partial_result_params: lsp::PartialResultParams {
12412 partial_result_token: Some(lsp::ProgressToken::String(token)),
12413 },
12414 },
12415 select(timer, progress).then(|either| match either {
12416 Either::Left((message, ..)) => ready(message).left_future(),
12417 Either::Right(..) => pending::<String>().right_future(),
12418 }),
12419 )
12420 .await;
12421
12422 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12423 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12424 match response_result {
12425 ConnectionResult::Timeout => {
12426 log::error!("Timeout during workspace diagnostics pull");
12427 continue 'request;
12428 }
12429 ConnectionResult::ConnectionReset => {
12430 log::error!("Server closed a workspace diagnostics pull request");
12431 continue 'request;
12432 }
12433 ConnectionResult::Result(Err(e)) => {
12434 log::error!("Error during workspace diagnostics pull: {e:#}");
12435 break 'request;
12436 }
12437 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12438 attempts = 0;
12439 if lsp_store
12440 .update(cx, |lsp_store, cx| {
12441 lsp_store.apply_workspace_diagnostic_report(
12442 server.server_id(),
12443 pulled_diagnostics,
12444 cx,
12445 )
12446 })
12447 .is_err()
12448 {
12449 return;
12450 }
12451 break 'request;
12452 }
12453 }
12454 }
12455 }
12456 });
12457
12458 Some(WorkspaceRefreshTask {
12459 refresh_tx,
12460 progress_tx,
12461 task: workspace_query_language_server,
12462 })
12463}
12464
12465fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12466 let CompletionSource::BufferWord {
12467 word_range,
12468 resolved,
12469 } = &mut completion.source
12470 else {
12471 return;
12472 };
12473 if *resolved {
12474 return;
12475 }
12476
12477 if completion.new_text
12478 != snapshot
12479 .text_for_range(word_range.clone())
12480 .collect::<String>()
12481 {
12482 return;
12483 }
12484
12485 let mut offset = 0;
12486 for chunk in snapshot.chunks(word_range.clone(), true) {
12487 let end_offset = offset + chunk.text.len();
12488 if let Some(highlight_id) = chunk.syntax_highlight_id {
12489 completion
12490 .label
12491 .runs
12492 .push((offset..end_offset, highlight_id));
12493 }
12494 offset = end_offset;
12495 }
12496 *resolved = true;
12497}
12498
12499impl EventEmitter<LspStoreEvent> for LspStore {}
12500
12501fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12502 hover
12503 .contents
12504 .retain(|hover_block| !hover_block.text.trim().is_empty());
12505 if hover.contents.is_empty() {
12506 None
12507 } else {
12508 Some(hover)
12509 }
12510}
12511
12512async fn populate_labels_for_completions(
12513 new_completions: Vec<CoreCompletion>,
12514 language: Option<Arc<Language>>,
12515 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12516) -> Vec<Completion> {
12517 let lsp_completions = new_completions
12518 .iter()
12519 .filter_map(|new_completion| {
12520 new_completion
12521 .source
12522 .lsp_completion(true)
12523 .map(|lsp_completion| lsp_completion.into_owned())
12524 })
12525 .collect::<Vec<_>>();
12526
12527 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12528 lsp_adapter
12529 .labels_for_completions(&lsp_completions, language)
12530 .await
12531 .log_err()
12532 .unwrap_or_default()
12533 } else {
12534 Vec::new()
12535 }
12536 .into_iter()
12537 .fuse();
12538
12539 let mut completions = Vec::new();
12540 for completion in new_completions {
12541 match completion.source.lsp_completion(true) {
12542 Some(lsp_completion) => {
12543 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12544
12545 let mut label = labels.next().flatten().unwrap_or_else(|| {
12546 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12547 });
12548 ensure_uniform_list_compatible_label(&mut label);
12549 completions.push(Completion {
12550 label,
12551 documentation,
12552 replace_range: completion.replace_range,
12553 new_text: completion.new_text,
12554 insert_text_mode: lsp_completion.insert_text_mode,
12555 source: completion.source,
12556 icon_path: None,
12557 confirm: None,
12558 });
12559 }
12560 None => {
12561 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12562 ensure_uniform_list_compatible_label(&mut label);
12563 completions.push(Completion {
12564 label,
12565 documentation: None,
12566 replace_range: completion.replace_range,
12567 new_text: completion.new_text,
12568 source: completion.source,
12569 insert_text_mode: None,
12570 icon_path: None,
12571 confirm: None,
12572 });
12573 }
12574 }
12575 }
12576 completions
12577}
12578
12579#[derive(Debug)]
12580pub enum LanguageServerToQuery {
12581 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12582 FirstCapable,
12583 /// Query a specific language server.
12584 Other(LanguageServerId),
12585}
12586
12587#[derive(Default)]
12588struct RenamePathsWatchedForServer {
12589 did_rename: Vec<RenameActionPredicate>,
12590 will_rename: Vec<RenameActionPredicate>,
12591}
12592
12593impl RenamePathsWatchedForServer {
12594 fn with_did_rename_patterns(
12595 mut self,
12596 did_rename: Option<&FileOperationRegistrationOptions>,
12597 ) -> Self {
12598 if let Some(did_rename) = did_rename {
12599 self.did_rename = did_rename
12600 .filters
12601 .iter()
12602 .filter_map(|filter| filter.try_into().log_err())
12603 .collect();
12604 }
12605 self
12606 }
12607 fn with_will_rename_patterns(
12608 mut self,
12609 will_rename: Option<&FileOperationRegistrationOptions>,
12610 ) -> Self {
12611 if let Some(will_rename) = will_rename {
12612 self.will_rename = will_rename
12613 .filters
12614 .iter()
12615 .filter_map(|filter| filter.try_into().log_err())
12616 .collect();
12617 }
12618 self
12619 }
12620
12621 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12622 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12623 }
12624 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12625 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12626 }
12627}
12628
12629impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12630 type Error = globset::Error;
12631 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12632 Ok(Self {
12633 kind: ops.pattern.matches.clone(),
12634 glob: GlobBuilder::new(&ops.pattern.glob)
12635 .case_insensitive(
12636 ops.pattern
12637 .options
12638 .as_ref()
12639 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12640 )
12641 .build()?
12642 .compile_matcher(),
12643 })
12644 }
12645}
12646struct RenameActionPredicate {
12647 glob: GlobMatcher,
12648 kind: Option<FileOperationPatternKind>,
12649}
12650
12651impl RenameActionPredicate {
12652 // Returns true if language server should be notified
12653 fn eval(&self, path: &str, is_dir: bool) -> bool {
12654 self.kind.as_ref().is_none_or(|kind| {
12655 let expected_kind = if is_dir {
12656 FileOperationPatternKind::Folder
12657 } else {
12658 FileOperationPatternKind::File
12659 };
12660 kind == &expected_kind
12661 }) && self.glob.is_match(path)
12662 }
12663}
12664
12665#[derive(Default)]
12666struct LanguageServerWatchedPaths {
12667 worktree_paths: HashMap<WorktreeId, GlobSet>,
12668 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12669}
12670
12671#[derive(Default)]
12672struct LanguageServerWatchedPathsBuilder {
12673 worktree_paths: HashMap<WorktreeId, GlobSet>,
12674 abs_paths: HashMap<Arc<Path>, GlobSet>,
12675}
12676
12677impl LanguageServerWatchedPathsBuilder {
12678 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12679 self.worktree_paths.insert(worktree_id, glob_set);
12680 }
12681 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12682 self.abs_paths.insert(path, glob_set);
12683 }
12684 fn build(
12685 self,
12686 fs: Arc<dyn Fs>,
12687 language_server_id: LanguageServerId,
12688 cx: &mut Context<LspStore>,
12689 ) -> LanguageServerWatchedPaths {
12690 let project = cx.weak_entity();
12691
12692 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12693 let abs_paths = self
12694 .abs_paths
12695 .into_iter()
12696 .map(|(abs_path, globset)| {
12697 let task = cx.spawn({
12698 let abs_path = abs_path.clone();
12699 let fs = fs.clone();
12700
12701 let lsp_store = project.clone();
12702 async move |_, cx| {
12703 maybe!(async move {
12704 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12705 while let Some(update) = push_updates.0.next().await {
12706 let action = lsp_store
12707 .update(cx, |this, _| {
12708 let Some(local) = this.as_local() else {
12709 return ControlFlow::Break(());
12710 };
12711 let Some(watcher) = local
12712 .language_server_watched_paths
12713 .get(&language_server_id)
12714 else {
12715 return ControlFlow::Break(());
12716 };
12717 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12718 "Watched abs path is not registered with a watcher",
12719 );
12720 let matching_entries = update
12721 .into_iter()
12722 .filter(|event| globs.is_match(&event.path))
12723 .collect::<Vec<_>>();
12724 this.lsp_notify_abs_paths_changed(
12725 language_server_id,
12726 matching_entries,
12727 );
12728 ControlFlow::Continue(())
12729 })
12730 .ok()?;
12731
12732 if action.is_break() {
12733 break;
12734 }
12735 }
12736 Some(())
12737 })
12738 .await;
12739 }
12740 });
12741 (abs_path, (globset, task))
12742 })
12743 .collect();
12744 LanguageServerWatchedPaths {
12745 worktree_paths: self.worktree_paths,
12746 abs_paths,
12747 }
12748 }
12749}
12750
12751struct LspBufferSnapshot {
12752 version: i32,
12753 snapshot: TextBufferSnapshot,
12754}
12755
12756/// A prompt requested by LSP server.
12757#[derive(Clone, Debug)]
12758pub struct LanguageServerPromptRequest {
12759 pub level: PromptLevel,
12760 pub message: String,
12761 pub actions: Vec<MessageActionItem>,
12762 pub lsp_name: String,
12763 pub(crate) response_channel: Sender<MessageActionItem>,
12764}
12765
12766impl LanguageServerPromptRequest {
12767 pub async fn respond(self, index: usize) -> Option<()> {
12768 if let Some(response) = self.actions.into_iter().nth(index) {
12769 self.response_channel.send(response).await.ok()
12770 } else {
12771 None
12772 }
12773 }
12774}
12775impl PartialEq for LanguageServerPromptRequest {
12776 fn eq(&self, other: &Self) -> bool {
12777 self.message == other.message && self.actions == other.actions
12778 }
12779}
12780
12781#[derive(Clone, Debug, PartialEq)]
12782pub enum LanguageServerLogType {
12783 Log(MessageType),
12784 Trace { verbose_info: Option<String> },
12785 Rpc { received: bool },
12786}
12787
12788impl LanguageServerLogType {
12789 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12790 match self {
12791 Self::Log(log_type) => {
12792 use proto::log_message::LogLevel;
12793 let level = match *log_type {
12794 MessageType::ERROR => LogLevel::Error,
12795 MessageType::WARNING => LogLevel::Warning,
12796 MessageType::INFO => LogLevel::Info,
12797 MessageType::LOG => LogLevel::Log,
12798 other => {
12799 log::warn!("Unknown lsp log message type: {other:?}");
12800 LogLevel::Log
12801 }
12802 };
12803 proto::language_server_log::LogType::Log(proto::LogMessage {
12804 level: level as i32,
12805 })
12806 }
12807 Self::Trace { verbose_info } => {
12808 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12809 verbose_info: verbose_info.to_owned(),
12810 })
12811 }
12812 Self::Rpc { received } => {
12813 let kind = if *received {
12814 proto::rpc_message::Kind::Received
12815 } else {
12816 proto::rpc_message::Kind::Sent
12817 };
12818 let kind = kind as i32;
12819 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12820 }
12821 }
12822 }
12823
12824 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12825 use proto::log_message::LogLevel;
12826 use proto::rpc_message;
12827 match log_type {
12828 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12829 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12830 LogLevel::Error => MessageType::ERROR,
12831 LogLevel::Warning => MessageType::WARNING,
12832 LogLevel::Info => MessageType::INFO,
12833 LogLevel::Log => MessageType::LOG,
12834 },
12835 ),
12836 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12837 verbose_info: trace_message.verbose_info,
12838 },
12839 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12840 received: match rpc_message::Kind::from_i32(message.kind)
12841 .unwrap_or(rpc_message::Kind::Received)
12842 {
12843 rpc_message::Kind::Received => true,
12844 rpc_message::Kind::Sent => false,
12845 },
12846 },
12847 }
12848 }
12849}
12850
12851pub struct WorkspaceRefreshTask {
12852 refresh_tx: mpsc::Sender<()>,
12853 progress_tx: mpsc::Sender<()>,
12854 #[allow(dead_code)]
12855 task: Task<()>,
12856}
12857
12858pub enum LanguageServerState {
12859 Starting {
12860 startup: Task<Option<Arc<LanguageServer>>>,
12861 /// List of language servers that will be added to the workspace once it's initialization completes.
12862 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12863 },
12864
12865 Running {
12866 adapter: Arc<CachedLspAdapter>,
12867 server: Arc<LanguageServer>,
12868 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12869 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12870 },
12871}
12872
12873impl LanguageServerState {
12874 fn add_workspace_folder(&self, uri: Uri) {
12875 match self {
12876 LanguageServerState::Starting {
12877 pending_workspace_folders,
12878 ..
12879 } => {
12880 pending_workspace_folders.lock().insert(uri);
12881 }
12882 LanguageServerState::Running { server, .. } => {
12883 server.add_workspace_folder(uri);
12884 }
12885 }
12886 }
12887 fn _remove_workspace_folder(&self, uri: Uri) {
12888 match self {
12889 LanguageServerState::Starting {
12890 pending_workspace_folders,
12891 ..
12892 } => {
12893 pending_workspace_folders.lock().remove(&uri);
12894 }
12895 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12896 }
12897 }
12898}
12899
12900impl std::fmt::Debug for LanguageServerState {
12901 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12902 match self {
12903 LanguageServerState::Starting { .. } => {
12904 f.debug_struct("LanguageServerState::Starting").finish()
12905 }
12906 LanguageServerState::Running { .. } => {
12907 f.debug_struct("LanguageServerState::Running").finish()
12908 }
12909 }
12910 }
12911}
12912
12913#[derive(Clone, Debug, Serialize)]
12914pub struct LanguageServerProgress {
12915 pub is_disk_based_diagnostics_progress: bool,
12916 pub is_cancellable: bool,
12917 pub title: Option<String>,
12918 pub message: Option<String>,
12919 pub percentage: Option<usize>,
12920 #[serde(skip_serializing)]
12921 pub last_update_at: Instant,
12922}
12923
12924#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12925pub struct DiagnosticSummary {
12926 pub error_count: usize,
12927 pub warning_count: usize,
12928}
12929
12930impl DiagnosticSummary {
12931 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12932 let mut this = Self {
12933 error_count: 0,
12934 warning_count: 0,
12935 };
12936
12937 for entry in diagnostics {
12938 if entry.diagnostic.is_primary {
12939 match entry.diagnostic.severity {
12940 DiagnosticSeverity::ERROR => this.error_count += 1,
12941 DiagnosticSeverity::WARNING => this.warning_count += 1,
12942 _ => {}
12943 }
12944 }
12945 }
12946
12947 this
12948 }
12949
12950 pub fn is_empty(&self) -> bool {
12951 self.error_count == 0 && self.warning_count == 0
12952 }
12953
12954 pub fn to_proto(
12955 self,
12956 language_server_id: LanguageServerId,
12957 path: &RelPath,
12958 ) -> proto::DiagnosticSummary {
12959 proto::DiagnosticSummary {
12960 path: path.to_proto(),
12961 language_server_id: language_server_id.0 as u64,
12962 error_count: self.error_count as u32,
12963 warning_count: self.warning_count as u32,
12964 }
12965 }
12966}
12967
12968#[derive(Clone, Debug)]
12969pub enum CompletionDocumentation {
12970 /// There is no documentation for this completion.
12971 Undocumented,
12972 /// A single line of documentation.
12973 SingleLine(SharedString),
12974 /// Multiple lines of plain text documentation.
12975 MultiLinePlainText(SharedString),
12976 /// Markdown documentation.
12977 MultiLineMarkdown(SharedString),
12978 /// Both single line and multiple lines of plain text documentation.
12979 SingleLineAndMultiLinePlainText {
12980 single_line: SharedString,
12981 plain_text: Option<SharedString>,
12982 },
12983}
12984
12985impl CompletionDocumentation {
12986 #[cfg(any(test, feature = "test-support"))]
12987 pub fn text(&self) -> SharedString {
12988 match self {
12989 CompletionDocumentation::Undocumented => "".into(),
12990 CompletionDocumentation::SingleLine(s) => s.clone(),
12991 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
12992 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
12993 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
12994 single_line.clone()
12995 }
12996 }
12997 }
12998}
12999
13000impl From<lsp::Documentation> for CompletionDocumentation {
13001 fn from(docs: lsp::Documentation) -> Self {
13002 match docs {
13003 lsp::Documentation::String(text) => {
13004 if text.lines().count() <= 1 {
13005 CompletionDocumentation::SingleLine(text.into())
13006 } else {
13007 CompletionDocumentation::MultiLinePlainText(text.into())
13008 }
13009 }
13010
13011 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13012 lsp::MarkupKind::PlainText => {
13013 if value.lines().count() <= 1 {
13014 CompletionDocumentation::SingleLine(value.into())
13015 } else {
13016 CompletionDocumentation::MultiLinePlainText(value.into())
13017 }
13018 }
13019
13020 lsp::MarkupKind::Markdown => {
13021 CompletionDocumentation::MultiLineMarkdown(value.into())
13022 }
13023 },
13024 }
13025 }
13026}
13027
13028pub enum ResolvedHint {
13029 Resolved(InlayHint),
13030 Resolving(Shared<Task<()>>),
13031}
13032
13033fn glob_literal_prefix(glob: &Path) -> PathBuf {
13034 glob.components()
13035 .take_while(|component| match component {
13036 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13037 _ => true,
13038 })
13039 .collect()
13040}
13041
13042pub struct SshLspAdapter {
13043 name: LanguageServerName,
13044 binary: LanguageServerBinary,
13045 initialization_options: Option<String>,
13046 code_action_kinds: Option<Vec<CodeActionKind>>,
13047}
13048
13049impl SshLspAdapter {
13050 pub fn new(
13051 name: LanguageServerName,
13052 binary: LanguageServerBinary,
13053 initialization_options: Option<String>,
13054 code_action_kinds: Option<String>,
13055 ) -> Self {
13056 Self {
13057 name,
13058 binary,
13059 initialization_options,
13060 code_action_kinds: code_action_kinds
13061 .as_ref()
13062 .and_then(|c| serde_json::from_str(c).ok()),
13063 }
13064 }
13065}
13066
13067impl LspInstaller for SshLspAdapter {
13068 type BinaryVersion = ();
13069 async fn check_if_user_installed(
13070 &self,
13071 _: &dyn LspAdapterDelegate,
13072 _: Option<Toolchain>,
13073 _: &AsyncApp,
13074 ) -> Option<LanguageServerBinary> {
13075 Some(self.binary.clone())
13076 }
13077
13078 async fn cached_server_binary(
13079 &self,
13080 _: PathBuf,
13081 _: &dyn LspAdapterDelegate,
13082 ) -> Option<LanguageServerBinary> {
13083 None
13084 }
13085
13086 async fn fetch_latest_server_version(
13087 &self,
13088 _: &dyn LspAdapterDelegate,
13089 _: bool,
13090 _: &mut AsyncApp,
13091 ) -> Result<()> {
13092 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13093 }
13094
13095 async fn fetch_server_binary(
13096 &self,
13097 _: (),
13098 _: PathBuf,
13099 _: &dyn LspAdapterDelegate,
13100 ) -> Result<LanguageServerBinary> {
13101 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13102 }
13103}
13104
13105#[async_trait(?Send)]
13106impl LspAdapter for SshLspAdapter {
13107 fn name(&self) -> LanguageServerName {
13108 self.name.clone()
13109 }
13110
13111 async fn initialization_options(
13112 self: Arc<Self>,
13113 _: &Arc<dyn LspAdapterDelegate>,
13114 ) -> Result<Option<serde_json::Value>> {
13115 let Some(options) = &self.initialization_options else {
13116 return Ok(None);
13117 };
13118 let result = serde_json::from_str(options)?;
13119 Ok(result)
13120 }
13121
13122 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13123 self.code_action_kinds.clone()
13124 }
13125}
13126
13127pub fn language_server_settings<'a>(
13128 delegate: &'a dyn LspAdapterDelegate,
13129 language: &LanguageServerName,
13130 cx: &'a App,
13131) -> Option<&'a LspSettings> {
13132 language_server_settings_for(
13133 SettingsLocation {
13134 worktree_id: delegate.worktree_id(),
13135 path: RelPath::empty(),
13136 },
13137 language,
13138 cx,
13139 )
13140}
13141
13142pub(crate) fn language_server_settings_for<'a>(
13143 location: SettingsLocation<'a>,
13144 language: &LanguageServerName,
13145 cx: &'a App,
13146) -> Option<&'a LspSettings> {
13147 ProjectSettings::get(Some(location), cx).lsp.get(language)
13148}
13149
13150pub struct LocalLspAdapterDelegate {
13151 lsp_store: WeakEntity<LspStore>,
13152 worktree: worktree::Snapshot,
13153 fs: Arc<dyn Fs>,
13154 http_client: Arc<dyn HttpClient>,
13155 language_registry: Arc<LanguageRegistry>,
13156 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13157}
13158
13159impl LocalLspAdapterDelegate {
13160 pub fn new(
13161 language_registry: Arc<LanguageRegistry>,
13162 environment: &Entity<ProjectEnvironment>,
13163 lsp_store: WeakEntity<LspStore>,
13164 worktree: &Entity<Worktree>,
13165 http_client: Arc<dyn HttpClient>,
13166 fs: Arc<dyn Fs>,
13167 cx: &mut App,
13168 ) -> Arc<Self> {
13169 let load_shell_env_task = environment.update(cx, |env, cx| {
13170 env.get_worktree_environment(worktree.clone(), cx)
13171 });
13172
13173 Arc::new(Self {
13174 lsp_store,
13175 worktree: worktree.read(cx).snapshot(),
13176 fs,
13177 http_client,
13178 language_registry,
13179 load_shell_env_task,
13180 })
13181 }
13182
13183 fn from_local_lsp(
13184 local: &LocalLspStore,
13185 worktree: &Entity<Worktree>,
13186 cx: &mut App,
13187 ) -> Arc<Self> {
13188 Self::new(
13189 local.languages.clone(),
13190 &local.environment,
13191 local.weak.clone(),
13192 worktree,
13193 local.http_client.clone(),
13194 local.fs.clone(),
13195 cx,
13196 )
13197 }
13198}
13199
13200#[async_trait]
13201impl LspAdapterDelegate for LocalLspAdapterDelegate {
13202 fn show_notification(&self, message: &str, cx: &mut App) {
13203 self.lsp_store
13204 .update(cx, |_, cx| {
13205 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13206 })
13207 .ok();
13208 }
13209
13210 fn http_client(&self) -> Arc<dyn HttpClient> {
13211 self.http_client.clone()
13212 }
13213
13214 fn worktree_id(&self) -> WorktreeId {
13215 self.worktree.id()
13216 }
13217
13218 fn worktree_root_path(&self) -> &Path {
13219 self.worktree.abs_path().as_ref()
13220 }
13221
13222 async fn shell_env(&self) -> HashMap<String, String> {
13223 let task = self.load_shell_env_task.clone();
13224 task.await.unwrap_or_default()
13225 }
13226
13227 async fn npm_package_installed_version(
13228 &self,
13229 package_name: &str,
13230 ) -> Result<Option<(PathBuf, String)>> {
13231 let local_package_directory = self.worktree_root_path();
13232 let node_modules_directory = local_package_directory.join("node_modules");
13233
13234 if let Some(version) =
13235 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13236 {
13237 return Ok(Some((node_modules_directory, version)));
13238 }
13239 let Some(npm) = self.which("npm".as_ref()).await else {
13240 log::warn!(
13241 "Failed to find npm executable for {:?}",
13242 local_package_directory
13243 );
13244 return Ok(None);
13245 };
13246
13247 let env = self.shell_env().await;
13248 let output = util::command::new_smol_command(&npm)
13249 .args(["root", "-g"])
13250 .envs(env)
13251 .current_dir(local_package_directory)
13252 .output()
13253 .await?;
13254 let global_node_modules =
13255 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13256
13257 if let Some(version) =
13258 read_package_installed_version(global_node_modules.clone(), package_name).await?
13259 {
13260 return Ok(Some((global_node_modules, version)));
13261 }
13262 return Ok(None);
13263 }
13264
13265 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13266 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13267 if self.fs.is_file(&worktree_abs_path).await {
13268 worktree_abs_path.pop();
13269 }
13270
13271 let env = self.shell_env().await;
13272
13273 let shell_path = env.get("PATH").cloned();
13274
13275 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13276 }
13277
13278 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13279 let mut working_dir = self.worktree_root_path().to_path_buf();
13280 if self.fs.is_file(&working_dir).await {
13281 working_dir.pop();
13282 }
13283 let output = util::command::new_smol_command(&command.path)
13284 .args(command.arguments)
13285 .envs(command.env.clone().unwrap_or_default())
13286 .current_dir(working_dir)
13287 .output()
13288 .await?;
13289
13290 anyhow::ensure!(
13291 output.status.success(),
13292 "{}, stdout: {:?}, stderr: {:?}",
13293 output.status,
13294 String::from_utf8_lossy(&output.stdout),
13295 String::from_utf8_lossy(&output.stderr)
13296 );
13297 Ok(())
13298 }
13299
13300 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13301 self.language_registry
13302 .update_lsp_binary_status(server_name, status);
13303 }
13304
13305 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13306 self.language_registry
13307 .all_lsp_adapters()
13308 .into_iter()
13309 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13310 .collect()
13311 }
13312
13313 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13314 let dir = self.language_registry.language_server_download_dir(name)?;
13315
13316 if !dir.exists() {
13317 smol::fs::create_dir_all(&dir)
13318 .await
13319 .context("failed to create container directory")
13320 .log_err()?;
13321 }
13322
13323 Some(dir)
13324 }
13325
13326 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13327 let entry = self
13328 .worktree
13329 .entry_for_path(path)
13330 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13331 let abs_path = self.worktree.absolutize(&entry.path);
13332 self.fs.load(&abs_path).await
13333 }
13334}
13335
13336async fn populate_labels_for_symbols(
13337 symbols: Vec<CoreSymbol>,
13338 language_registry: &Arc<LanguageRegistry>,
13339 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13340 output: &mut Vec<Symbol>,
13341) {
13342 #[allow(clippy::mutable_key_type)]
13343 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13344
13345 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13346 for symbol in symbols {
13347 let Some(file_name) = symbol.path.file_name() else {
13348 continue;
13349 };
13350 let language = language_registry
13351 .load_language_for_file_path(Path::new(file_name))
13352 .await
13353 .ok()
13354 .or_else(|| {
13355 unknown_paths.insert(file_name.into());
13356 None
13357 });
13358 symbols_by_language
13359 .entry(language)
13360 .or_default()
13361 .push(symbol);
13362 }
13363
13364 for unknown_path in unknown_paths {
13365 log::info!("no language found for symbol in file {unknown_path:?}");
13366 }
13367
13368 let mut label_params = Vec::new();
13369 for (language, mut symbols) in symbols_by_language {
13370 label_params.clear();
13371 label_params.extend(
13372 symbols
13373 .iter_mut()
13374 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13375 );
13376
13377 let mut labels = Vec::new();
13378 if let Some(language) = language {
13379 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13380 language_registry
13381 .lsp_adapters(&language.name())
13382 .first()
13383 .cloned()
13384 });
13385 if let Some(lsp_adapter) = lsp_adapter {
13386 labels = lsp_adapter
13387 .labels_for_symbols(&label_params, &language)
13388 .await
13389 .log_err()
13390 .unwrap_or_default();
13391 }
13392 }
13393
13394 for ((symbol, (name, _)), label) in symbols
13395 .into_iter()
13396 .zip(label_params.drain(..))
13397 .zip(labels.into_iter().chain(iter::repeat(None)))
13398 {
13399 output.push(Symbol {
13400 language_server_name: symbol.language_server_name,
13401 source_worktree_id: symbol.source_worktree_id,
13402 source_language_server_id: symbol.source_language_server_id,
13403 path: symbol.path,
13404 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13405 name,
13406 kind: symbol.kind,
13407 range: symbol.range,
13408 });
13409 }
13410 }
13411}
13412
13413fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13414 match server.capabilities().text_document_sync.as_ref()? {
13415 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13416 // Server wants didSave but didn't specify includeText.
13417 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13418 // Server doesn't want didSave at all.
13419 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13420 // Server provided SaveOptions.
13421 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13422 Some(save_options.include_text.unwrap_or(false))
13423 }
13424 },
13425 // We do not have any save info. Kind affects didChange only.
13426 lsp::TextDocumentSyncCapability::Kind(_) => None,
13427 }
13428}
13429
13430/// Completion items are displayed in a `UniformList`.
13431/// Usually, those items are single-line strings, but in LSP responses,
13432/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13433/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13434/// 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,
13435/// breaking the completions menu presentation.
13436///
13437/// 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.
13438fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13439 let mut new_text = String::with_capacity(label.text.len());
13440 let mut offset_map = vec![0; label.text.len() + 1];
13441 let mut last_char_was_space = false;
13442 let mut new_idx = 0;
13443 let chars = label.text.char_indices().fuse();
13444 let mut newlines_removed = false;
13445
13446 for (idx, c) in chars {
13447 offset_map[idx] = new_idx;
13448
13449 match c {
13450 '\n' if last_char_was_space => {
13451 newlines_removed = true;
13452 }
13453 '\t' | ' ' if last_char_was_space => {}
13454 '\n' if !last_char_was_space => {
13455 new_text.push(' ');
13456 new_idx += 1;
13457 last_char_was_space = true;
13458 newlines_removed = true;
13459 }
13460 ' ' | '\t' => {
13461 new_text.push(' ');
13462 new_idx += 1;
13463 last_char_was_space = true;
13464 }
13465 _ => {
13466 new_text.push(c);
13467 new_idx += c.len_utf8();
13468 last_char_was_space = false;
13469 }
13470 }
13471 }
13472 offset_map[label.text.len()] = new_idx;
13473
13474 // Only modify the label if newlines were removed.
13475 if !newlines_removed {
13476 return;
13477 }
13478
13479 let last_index = new_idx;
13480 let mut run_ranges_errors = Vec::new();
13481 label.runs.retain_mut(|(range, _)| {
13482 match offset_map.get(range.start) {
13483 Some(&start) => range.start = start,
13484 None => {
13485 run_ranges_errors.push(range.clone());
13486 return false;
13487 }
13488 }
13489
13490 match offset_map.get(range.end) {
13491 Some(&end) => range.end = end,
13492 None => {
13493 run_ranges_errors.push(range.clone());
13494 range.end = last_index;
13495 }
13496 }
13497 true
13498 });
13499 if !run_ranges_errors.is_empty() {
13500 log::error!(
13501 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13502 label.text
13503 );
13504 }
13505
13506 let mut wrong_filter_range = None;
13507 if label.filter_range == (0..label.text.len()) {
13508 label.filter_range = 0..new_text.len();
13509 } else {
13510 let mut original_filter_range = Some(label.filter_range.clone());
13511 match offset_map.get(label.filter_range.start) {
13512 Some(&start) => label.filter_range.start = start,
13513 None => {
13514 wrong_filter_range = original_filter_range.take();
13515 label.filter_range.start = last_index;
13516 }
13517 }
13518
13519 match offset_map.get(label.filter_range.end) {
13520 Some(&end) => label.filter_range.end = end,
13521 None => {
13522 wrong_filter_range = original_filter_range.take();
13523 label.filter_range.end = last_index;
13524 }
13525 }
13526 }
13527 if let Some(wrong_filter_range) = wrong_filter_range {
13528 log::error!(
13529 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13530 label.text
13531 );
13532 }
13533
13534 label.text = new_text;
13535}
13536
13537#[cfg(test)]
13538mod tests {
13539 use language::HighlightId;
13540
13541 use super::*;
13542
13543 #[test]
13544 fn test_glob_literal_prefix() {
13545 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13546 assert_eq!(
13547 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13548 Path::new("node_modules")
13549 );
13550 assert_eq!(
13551 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13552 Path::new("foo")
13553 );
13554 assert_eq!(
13555 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13556 Path::new("foo/bar/baz.js")
13557 );
13558
13559 #[cfg(target_os = "windows")]
13560 {
13561 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13562 assert_eq!(
13563 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13564 Path::new("node_modules")
13565 );
13566 assert_eq!(
13567 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13568 Path::new("foo")
13569 );
13570 assert_eq!(
13571 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13572 Path::new("foo/bar/baz.js")
13573 );
13574 }
13575 }
13576
13577 #[test]
13578 fn test_multi_len_chars_normalization() {
13579 let mut label = CodeLabel::new(
13580 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13581 0..6,
13582 vec![(0..6, HighlightId(1))],
13583 );
13584 ensure_uniform_list_compatible_label(&mut label);
13585 assert_eq!(
13586 label,
13587 CodeLabel::new(
13588 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13589 0..6,
13590 vec![(0..6, HighlightId(1))],
13591 )
13592 );
13593 }
13594}