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