1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
79 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
80 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
81 LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
82 LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture,
83 MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
84 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
85 WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum FormatTrigger {
144 Save,
145 Manual,
146}
147
148pub enum LspFormatTarget {
149 Buffers,
150 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
151}
152
153pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
154
155impl FormatTrigger {
156 fn from_proto(value: i32) -> FormatTrigger {
157 match value {
158 0 => FormatTrigger::Save,
159 1 => FormatTrigger::Manual,
160 _ => FormatTrigger::Save,
161 }
162 }
163}
164
165#[derive(Clone)]
166struct UnifiedLanguageServer {
167 id: LanguageServerId,
168 project_roots: HashSet<Arc<RelPath>>,
169}
170
171#[derive(Clone, Hash, PartialEq, Eq)]
172struct LanguageServerSeed {
173 worktree_id: WorktreeId,
174 name: LanguageServerName,
175 toolchain: Option<Toolchain>,
176 settings: Arc<LspSettings>,
177}
178
179#[derive(Debug)]
180pub struct DocumentDiagnosticsUpdate<'a, D> {
181 pub diagnostics: D,
182 pub result_id: Option<String>,
183 pub server_id: LanguageServerId,
184 pub disk_based_sources: Cow<'a, [String]>,
185}
186
187pub struct DocumentDiagnostics {
188 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
189 document_abs_path: PathBuf,
190 version: Option<i32>,
191}
192
193pub struct LocalLspStore {
194 weak: WeakEntity<LspStore>,
195 worktree_store: Entity<WorktreeStore>,
196 toolchain_store: Entity<LocalToolchainStore>,
197 http_client: Arc<dyn HttpClient>,
198 environment: Entity<ProjectEnvironment>,
199 fs: Arc<dyn Fs>,
200 languages: Arc<LanguageRegistry>,
201 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
202 yarn: Entity<YarnPathStore>,
203 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
204 buffers_being_formatted: HashSet<BufferId>,
205 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
206 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
207 watched_manifest_filenames: HashSet<ManifestName>,
208 language_server_paths_watched_for_rename:
209 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
210 language_server_watcher_registrations:
211 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
212 supplementary_language_servers:
213 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
214 prettier_store: Entity<PrettierStore>,
215 next_diagnostic_group_id: usize,
216 diagnostics: HashMap<
217 WorktreeId,
218 HashMap<
219 Arc<RelPath>,
220 Vec<(
221 LanguageServerId,
222 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
223 )>,
224 >,
225 >,
226 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
227 _subscription: gpui::Subscription,
228 lsp_tree: LanguageServerTree,
229 registered_buffers: HashMap<BufferId, usize>,
230 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
231 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
232}
233
234impl LocalLspStore {
235 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
236 pub fn running_language_server_for_id(
237 &self,
238 id: LanguageServerId,
239 ) -> Option<&Arc<LanguageServer>> {
240 let language_server_state = self.language_servers.get(&id)?;
241
242 match language_server_state {
243 LanguageServerState::Running { server, .. } => Some(server),
244 LanguageServerState::Starting { .. } => None,
245 }
246 }
247
248 fn get_or_insert_language_server(
249 &mut self,
250 worktree_handle: &Entity<Worktree>,
251 delegate: Arc<LocalLspAdapterDelegate>,
252 disposition: &Arc<LaunchDisposition>,
253 language_name: &LanguageName,
254 cx: &mut App,
255 ) -> LanguageServerId {
256 let key = LanguageServerSeed {
257 worktree_id: worktree_handle.read(cx).id(),
258 name: disposition.server_name.clone(),
259 settings: disposition.settings.clone(),
260 toolchain: disposition.toolchain.clone(),
261 };
262 if let Some(state) = self.language_server_ids.get_mut(&key) {
263 state.project_roots.insert(disposition.path.path.clone());
264 state.id
265 } else {
266 let adapter = self
267 .languages
268 .lsp_adapters(language_name)
269 .into_iter()
270 .find(|adapter| adapter.name() == disposition.server_name)
271 .expect("To find LSP adapter");
272 let new_language_server_id = self.start_language_server(
273 worktree_handle,
274 delegate,
275 adapter,
276 disposition.settings.clone(),
277 key.clone(),
278 cx,
279 );
280 if let Some(state) = self.language_server_ids.get_mut(&key) {
281 state.project_roots.insert(disposition.path.path.clone());
282 } else {
283 debug_assert!(
284 false,
285 "Expected `start_language_server` to ensure that `key` exists in a map"
286 );
287 }
288 new_language_server_id
289 }
290 }
291
292 fn start_language_server(
293 &mut self,
294 worktree_handle: &Entity<Worktree>,
295 delegate: Arc<LocalLspAdapterDelegate>,
296 adapter: Arc<CachedLspAdapter>,
297 settings: Arc<LspSettings>,
298 key: LanguageServerSeed,
299 cx: &mut App,
300 ) -> LanguageServerId {
301 let worktree = worktree_handle.read(cx);
302
303 let root_path = worktree.abs_path();
304 let toolchain = key.toolchain.clone();
305 let override_options = settings.initialization_options.clone();
306
307 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
308
309 let server_id = self.languages.next_language_server_id();
310 log::trace!(
311 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
312 adapter.name.0
313 );
314
315 let binary = self.get_language_server_binary(
316 adapter.clone(),
317 settings,
318 toolchain.clone(),
319 delegate.clone(),
320 true,
321 cx,
322 );
323 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
324
325 let pending_server = cx.spawn({
326 let adapter = adapter.clone();
327 let server_name = adapter.name.clone();
328 let stderr_capture = stderr_capture.clone();
329 #[cfg(any(test, feature = "test-support"))]
330 let lsp_store = self.weak.clone();
331 let pending_workspace_folders = pending_workspace_folders.clone();
332 async move |cx| {
333 let binary = binary.await?;
334 #[cfg(any(test, feature = "test-support"))]
335 if let Some(server) = lsp_store
336 .update(&mut cx.clone(), |this, cx| {
337 this.languages.create_fake_language_server(
338 server_id,
339 &server_name,
340 binary.clone(),
341 &mut cx.to_async(),
342 )
343 })
344 .ok()
345 .flatten()
346 {
347 return Ok(server);
348 }
349
350 let code_action_kinds = adapter.code_action_kinds();
351 lsp::LanguageServer::new(
352 stderr_capture,
353 server_id,
354 server_name,
355 binary,
356 &root_path,
357 code_action_kinds,
358 Some(pending_workspace_folders),
359 cx,
360 )
361 }
362 });
363
364 let startup = {
365 let server_name = adapter.name.0.clone();
366 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
367 let key = key.clone();
368 let adapter = adapter.clone();
369 let lsp_store = self.weak.clone();
370 let pending_workspace_folders = pending_workspace_folders.clone();
371
372 let pull_diagnostics = ProjectSettings::get_global(cx)
373 .diagnostics
374 .lsp_pull_diagnostics
375 .enabled;
376 cx.spawn(async move |cx| {
377 let result = async {
378 let language_server = pending_server.await?;
379
380 let workspace_config = Self::workspace_configuration_for_adapter(
381 adapter.adapter.clone(),
382 &delegate,
383 toolchain,
384 cx,
385 )
386 .await?;
387
388 let mut initialization_options = Self::initialization_options_for_adapter(
389 adapter.adapter.clone(),
390 &delegate,
391 )
392 .await?;
393
394 match (&mut initialization_options, override_options) {
395 (Some(initialization_options), Some(override_options)) => {
396 merge_json_value_into(override_options, initialization_options);
397 }
398 (None, override_options) => initialization_options = override_options,
399 _ => {}
400 }
401
402 let initialization_params = cx.update(|cx| {
403 let mut params =
404 language_server.default_initialize_params(pull_diagnostics, cx);
405 params.initialization_options = initialization_options;
406 adapter.adapter.prepare_initialize_params(params, cx)
407 })??;
408
409 Self::setup_lsp_messages(
410 lsp_store.clone(),
411 &language_server,
412 delegate.clone(),
413 adapter.clone(),
414 );
415
416 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
417 settings: workspace_config,
418 };
419 let language_server = cx
420 .update(|cx| {
421 language_server.initialize(
422 initialization_params,
423 Arc::new(did_change_configuration_params.clone()),
424 cx,
425 )
426 })?
427 .await
428 .inspect_err(|_| {
429 if let Some(lsp_store) = lsp_store.upgrade() {
430 lsp_store
431 .update(cx, |lsp_store, cx| {
432 lsp_store.cleanup_lsp_data(server_id);
433 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
434 })
435 .ok();
436 }
437 })?;
438
439 language_server.notify::<lsp::notification::DidChangeConfiguration>(
440 did_change_configuration_params,
441 )?;
442
443 anyhow::Ok(language_server)
444 }
445 .await;
446
447 match result {
448 Ok(server) => {
449 lsp_store
450 .update(cx, |lsp_store, cx| {
451 lsp_store.insert_newly_running_language_server(
452 adapter,
453 server.clone(),
454 server_id,
455 key,
456 pending_workspace_folders,
457 cx,
458 );
459 })
460 .ok();
461 stderr_capture.lock().take();
462 Some(server)
463 }
464
465 Err(err) => {
466 let log = stderr_capture.lock().take().unwrap_or_default();
467 delegate.update_status(
468 adapter.name(),
469 BinaryStatus::Failed {
470 error: if log.is_empty() {
471 format!("{err:#}")
472 } else {
473 format!("{err:#}\n-- stderr --\n{log}")
474 },
475 },
476 );
477 log::error!("Failed to start language server {server_name:?}: {err:?}");
478 if !log.is_empty() {
479 log::error!("server stderr: {log}");
480 }
481 None
482 }
483 }
484 })
485 };
486 let state = LanguageServerState::Starting {
487 startup,
488 pending_workspace_folders,
489 };
490
491 self.languages
492 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
493
494 self.language_servers.insert(server_id, state);
495 self.language_server_ids
496 .entry(key)
497 .or_insert(UnifiedLanguageServer {
498 id: server_id,
499 project_roots: Default::default(),
500 });
501 server_id
502 }
503
504 fn get_language_server_binary(
505 &self,
506 adapter: Arc<CachedLspAdapter>,
507 settings: Arc<LspSettings>,
508 toolchain: Option<Toolchain>,
509 delegate: Arc<dyn LspAdapterDelegate>,
510 allow_binary_download: bool,
511 cx: &mut App,
512 ) -> Task<Result<LanguageServerBinary>> {
513 if let Some(settings) = settings.binary.as_ref()
514 && settings.path.is_some()
515 {
516 let settings = settings.clone();
517
518 return cx.background_spawn(async move {
519 let mut env = delegate.shell_env().await;
520 env.extend(settings.env.unwrap_or_default());
521
522 Ok(LanguageServerBinary {
523 path: PathBuf::from(&settings.path.unwrap()),
524 env: Some(env),
525 arguments: settings
526 .arguments
527 .unwrap_or_default()
528 .iter()
529 .map(Into::into)
530 .collect(),
531 })
532 });
533 }
534 let lsp_binary_options = LanguageServerBinaryOptions {
535 allow_path_lookup: !settings
536 .binary
537 .as_ref()
538 .and_then(|b| b.ignore_system_version)
539 .unwrap_or_default(),
540 allow_binary_download,
541 pre_release: settings
542 .fetch
543 .as_ref()
544 .and_then(|f| f.pre_release)
545 .unwrap_or(false),
546 };
547
548 cx.spawn(async move |cx| {
549 let binary_result = adapter
550 .clone()
551 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
552 .await;
553
554 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
555
556 let mut binary = binary_result?;
557 let mut shell_env = delegate.shell_env().await;
558
559 shell_env.extend(binary.env.unwrap_or_default());
560
561 if let Some(settings) = settings.binary.as_ref() {
562 if let Some(arguments) = &settings.arguments {
563 binary.arguments = arguments.iter().map(Into::into).collect();
564 }
565 if let Some(env) = &settings.env {
566 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
567 }
568 }
569
570 binary.env = Some(shell_env);
571 Ok(binary)
572 })
573 }
574
575 fn setup_lsp_messages(
576 lsp_store: WeakEntity<LspStore>,
577 language_server: &LanguageServer,
578 delegate: Arc<dyn LspAdapterDelegate>,
579 adapter: Arc<CachedLspAdapter>,
580 ) {
581 let name = language_server.name();
582 let server_id = language_server.server_id();
583 language_server
584 .on_notification::<lsp::notification::PublishDiagnostics, _>({
585 let adapter = adapter.clone();
586 let this = lsp_store.clone();
587 move |mut params, cx| {
588 let adapter = adapter.clone();
589 if let Some(this) = this.upgrade() {
590 this.update(cx, |this, cx| {
591 {
592 let buffer = params
593 .uri
594 .to_file_path()
595 .map(|file_path| this.get_buffer(&file_path, cx))
596 .ok()
597 .flatten();
598 adapter.process_diagnostics(&mut params, server_id, buffer);
599 }
600
601 this.merge_lsp_diagnostics(
602 DiagnosticSourceKind::Pushed,
603 vec![DocumentDiagnosticsUpdate {
604 server_id,
605 diagnostics: params,
606 result_id: None,
607 disk_based_sources: Cow::Borrowed(
608 &adapter.disk_based_diagnostic_sources,
609 ),
610 }],
611 |_, diagnostic, cx| match diagnostic.source_kind {
612 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
613 adapter.retain_old_diagnostic(diagnostic, cx)
614 }
615 DiagnosticSourceKind::Pulled => true,
616 },
617 cx,
618 )
619 .log_err();
620 })
621 .ok();
622 }
623 }
624 })
625 .detach();
626 language_server
627 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
628 let adapter = adapter.adapter.clone();
629 let delegate = delegate.clone();
630 let this = lsp_store.clone();
631 move |params, cx| {
632 let adapter = adapter.clone();
633 let delegate = delegate.clone();
634 let this = this.clone();
635 let mut cx = cx.clone();
636 async move {
637 let toolchain_for_id = this
638 .update(&mut cx, |this, _| {
639 this.as_local()?.language_server_ids.iter().find_map(
640 |(seed, value)| {
641 (value.id == server_id).then(|| seed.toolchain.clone())
642 },
643 )
644 })?
645 .context("Expected the LSP store to be in a local mode")?;
646 let workspace_config = Self::workspace_configuration_for_adapter(
647 adapter.clone(),
648 &delegate,
649 toolchain_for_id,
650 &mut cx,
651 )
652 .await?;
653
654 Ok(params
655 .items
656 .into_iter()
657 .map(|item| {
658 if let Some(section) = &item.section {
659 workspace_config
660 .get(section)
661 .cloned()
662 .unwrap_or(serde_json::Value::Null)
663 } else {
664 workspace_config.clone()
665 }
666 })
667 .collect())
668 }
669 }
670 })
671 .detach();
672
673 language_server
674 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
675 let this = lsp_store.clone();
676 move |_, cx| {
677 let this = this.clone();
678 let cx = cx.clone();
679 async move {
680 let Some(server) =
681 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
682 else {
683 return Ok(None);
684 };
685 let root = server.workspace_folders();
686 Ok(Some(
687 root.into_iter()
688 .map(|uri| WorkspaceFolder {
689 uri,
690 name: Default::default(),
691 })
692 .collect(),
693 ))
694 }
695 }
696 })
697 .detach();
698 // Even though we don't have handling for these requests, respond to them to
699 // avoid stalling any language server like `gopls` which waits for a response
700 // to these requests when initializing.
701 language_server
702 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
703 let this = lsp_store.clone();
704 move |params, cx| {
705 let this = this.clone();
706 let mut cx = cx.clone();
707 async move {
708 this.update(&mut cx, |this, _| {
709 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
710 && let lsp::NumberOrString::String(token) = params.token
711 {
712 status.progress_tokens.insert(token);
713 }
714 })?;
715
716 Ok(())
717 }
718 }
719 })
720 .detach();
721
722 language_server
723 .on_request::<lsp::request::RegisterCapability, _, _>({
724 let lsp_store = lsp_store.clone();
725 move |params, cx| {
726 let lsp_store = lsp_store.clone();
727 let mut cx = cx.clone();
728 async move {
729 lsp_store
730 .update(&mut cx, |lsp_store, cx| {
731 if lsp_store.as_local().is_some() {
732 match lsp_store
733 .register_server_capabilities(server_id, params, cx)
734 {
735 Ok(()) => {}
736 Err(e) => {
737 log::error!(
738 "Failed to register server capabilities: {e:#}"
739 );
740 }
741 };
742 }
743 })
744 .ok();
745 Ok(())
746 }
747 }
748 })
749 .detach();
750
751 language_server
752 .on_request::<lsp::request::UnregisterCapability, _, _>({
753 let lsp_store = lsp_store.clone();
754 move |params, cx| {
755 let lsp_store = lsp_store.clone();
756 let mut cx = cx.clone();
757 async move {
758 lsp_store
759 .update(&mut cx, |lsp_store, cx| {
760 if lsp_store.as_local().is_some() {
761 match lsp_store
762 .unregister_server_capabilities(server_id, params, cx)
763 {
764 Ok(()) => {}
765 Err(e) => {
766 log::error!(
767 "Failed to unregister server capabilities: {e:#}"
768 );
769 }
770 }
771 }
772 })
773 .ok();
774 Ok(())
775 }
776 }
777 })
778 .detach();
779
780 language_server
781 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
782 let this = lsp_store.clone();
783 move |params, cx| {
784 let mut cx = cx.clone();
785 let this = this.clone();
786 async move {
787 LocalLspStore::on_lsp_workspace_edit(
788 this.clone(),
789 params,
790 server_id,
791 &mut cx,
792 )
793 .await
794 }
795 }
796 })
797 .detach();
798
799 language_server
800 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
801 let lsp_store = lsp_store.clone();
802 move |(), cx| {
803 let this = lsp_store.clone();
804 let mut cx = cx.clone();
805 async move {
806 this.update(&mut cx, |lsp_store, cx| {
807 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
808 lsp_store
809 .downstream_client
810 .as_ref()
811 .map(|(client, project_id)| {
812 client.send(proto::RefreshInlayHints {
813 project_id: *project_id,
814 server_id: server_id.to_proto(),
815 })
816 })
817 })?
818 .transpose()?;
819 Ok(())
820 }
821 }
822 })
823 .detach();
824
825 language_server
826 .on_request::<lsp::request::CodeLensRefresh, _, _>({
827 let this = lsp_store.clone();
828 move |(), cx| {
829 let this = this.clone();
830 let mut cx = cx.clone();
831 async move {
832 this.update(&mut cx, |this, cx| {
833 cx.emit(LspStoreEvent::RefreshCodeLens);
834 this.downstream_client.as_ref().map(|(client, project_id)| {
835 client.send(proto::RefreshCodeLens {
836 project_id: *project_id,
837 })
838 })
839 })?
840 .transpose()?;
841 Ok(())
842 }
843 }
844 })
845 .detach();
846
847 language_server
848 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
849 let this = lsp_store.clone();
850 move |(), cx| {
851 let this = this.clone();
852 let mut cx = cx.clone();
853 async move {
854 this.update(&mut cx, |lsp_store, _| {
855 lsp_store.pull_workspace_diagnostics(server_id);
856 lsp_store
857 .downstream_client
858 .as_ref()
859 .map(|(client, project_id)| {
860 client.send(proto::PullWorkspaceDiagnostics {
861 project_id: *project_id,
862 server_id: server_id.to_proto(),
863 })
864 })
865 })?
866 .transpose()?;
867 Ok(())
868 }
869 }
870 })
871 .detach();
872
873 language_server
874 .on_request::<lsp::request::ShowMessageRequest, _, _>({
875 let this = lsp_store.clone();
876 let name = name.to_string();
877 move |params, cx| {
878 let this = this.clone();
879 let name = name.to_string();
880 let mut cx = cx.clone();
881 async move {
882 let actions = params.actions.unwrap_or_default();
883 let (tx, rx) = smol::channel::bounded(1);
884 let request = LanguageServerPromptRequest {
885 level: match params.typ {
886 lsp::MessageType::ERROR => PromptLevel::Critical,
887 lsp::MessageType::WARNING => PromptLevel::Warning,
888 _ => PromptLevel::Info,
889 },
890 message: params.message,
891 actions,
892 response_channel: tx,
893 lsp_name: name.clone(),
894 };
895
896 let did_update = this
897 .update(&mut cx, |_, cx| {
898 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
899 })
900 .is_ok();
901 if did_update {
902 let response = rx.recv().await.ok();
903 Ok(response)
904 } else {
905 Ok(None)
906 }
907 }
908 }
909 })
910 .detach();
911 language_server
912 .on_notification::<lsp::notification::ShowMessage, _>({
913 let this = lsp_store.clone();
914 let name = name.to_string();
915 move |params, cx| {
916 let this = this.clone();
917 let name = name.to_string();
918 let mut cx = cx.clone();
919
920 let (tx, _) = smol::channel::bounded(1);
921 let request = LanguageServerPromptRequest {
922 level: match params.typ {
923 lsp::MessageType::ERROR => PromptLevel::Critical,
924 lsp::MessageType::WARNING => PromptLevel::Warning,
925 _ => PromptLevel::Info,
926 },
927 message: params.message,
928 actions: vec![],
929 response_channel: tx,
930 lsp_name: name,
931 };
932
933 let _ = this.update(&mut cx, |_, cx| {
934 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
935 });
936 }
937 })
938 .detach();
939
940 let disk_based_diagnostics_progress_token =
941 adapter.disk_based_diagnostics_progress_token.clone();
942
943 language_server
944 .on_notification::<lsp::notification::Progress, _>({
945 let this = lsp_store.clone();
946 move |params, cx| {
947 if let Some(this) = this.upgrade() {
948 this.update(cx, |this, cx| {
949 this.on_lsp_progress(
950 params,
951 server_id,
952 disk_based_diagnostics_progress_token.clone(),
953 cx,
954 );
955 })
956 .ok();
957 }
958 }
959 })
960 .detach();
961
962 language_server
963 .on_notification::<lsp::notification::LogMessage, _>({
964 let this = lsp_store.clone();
965 move |params, cx| {
966 if let Some(this) = this.upgrade() {
967 this.update(cx, |_, cx| {
968 cx.emit(LspStoreEvent::LanguageServerLog(
969 server_id,
970 LanguageServerLogType::Log(params.typ),
971 params.message,
972 ));
973 })
974 .ok();
975 }
976 }
977 })
978 .detach();
979
980 language_server
981 .on_notification::<lsp::notification::LogTrace, _>({
982 let this = lsp_store.clone();
983 move |params, cx| {
984 let mut cx = cx.clone();
985 if let Some(this) = this.upgrade() {
986 this.update(&mut cx, |_, cx| {
987 cx.emit(LspStoreEvent::LanguageServerLog(
988 server_id,
989 LanguageServerLogType::Trace {
990 verbose_info: params.verbose,
991 },
992 params.message,
993 ));
994 })
995 .ok();
996 }
997 }
998 })
999 .detach();
1000
1001 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1002 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1003 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1004 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1005 }
1006
1007 fn shutdown_language_servers_on_quit(
1008 &mut self,
1009 _: &mut Context<LspStore>,
1010 ) -> impl Future<Output = ()> + use<> {
1011 let shutdown_futures = self
1012 .language_servers
1013 .drain()
1014 .map(|(_, server_state)| Self::shutdown_server(server_state))
1015 .collect::<Vec<_>>();
1016
1017 async move {
1018 join_all(shutdown_futures).await;
1019 }
1020 }
1021
1022 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1023 match server_state {
1024 LanguageServerState::Running { server, .. } => {
1025 if let Some(shutdown) = server.shutdown() {
1026 shutdown.await;
1027 }
1028 }
1029 LanguageServerState::Starting { startup, .. } => {
1030 if let Some(server) = startup.await
1031 && let Some(shutdown) = server.shutdown()
1032 {
1033 shutdown.await;
1034 }
1035 }
1036 }
1037 Ok(())
1038 }
1039
1040 fn language_servers_for_worktree(
1041 &self,
1042 worktree_id: WorktreeId,
1043 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1044 self.language_server_ids
1045 .iter()
1046 .filter_map(move |(seed, state)| {
1047 if seed.worktree_id != worktree_id {
1048 return None;
1049 }
1050
1051 if let Some(LanguageServerState::Running { server, .. }) =
1052 self.language_servers.get(&state.id)
1053 {
1054 Some(server)
1055 } else {
1056 None
1057 }
1058 })
1059 }
1060
1061 fn language_server_ids_for_project_path(
1062 &self,
1063 project_path: ProjectPath,
1064 language: &Language,
1065 cx: &mut App,
1066 ) -> Vec<LanguageServerId> {
1067 let Some(worktree) = self
1068 .worktree_store
1069 .read(cx)
1070 .worktree_for_id(project_path.worktree_id, cx)
1071 else {
1072 return Vec::new();
1073 };
1074 let delegate: Arc<dyn ManifestDelegate> =
1075 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1076
1077 self.lsp_tree
1078 .get(
1079 project_path,
1080 language.name(),
1081 language.manifest(),
1082 &delegate,
1083 cx,
1084 )
1085 .collect::<Vec<_>>()
1086 }
1087
1088 fn language_server_ids_for_buffer(
1089 &self,
1090 buffer: &Buffer,
1091 cx: &mut App,
1092 ) -> Vec<LanguageServerId> {
1093 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1094 let worktree_id = file.worktree_id(cx);
1095
1096 let path: Arc<RelPath> = file
1097 .path()
1098 .parent()
1099 .map(Arc::from)
1100 .unwrap_or_else(|| file.path().clone());
1101 let worktree_path = ProjectPath { worktree_id, path };
1102 self.language_server_ids_for_project_path(worktree_path, language, cx)
1103 } else {
1104 Vec::new()
1105 }
1106 }
1107
1108 fn language_servers_for_buffer<'a>(
1109 &'a self,
1110 buffer: &'a Buffer,
1111 cx: &'a mut App,
1112 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1113 self.language_server_ids_for_buffer(buffer, cx)
1114 .into_iter()
1115 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1116 LanguageServerState::Running {
1117 adapter, server, ..
1118 } => Some((adapter, server)),
1119 _ => None,
1120 })
1121 }
1122
1123 async fn execute_code_action_kind_locally(
1124 lsp_store: WeakEntity<LspStore>,
1125 mut buffers: Vec<Entity<Buffer>>,
1126 kind: CodeActionKind,
1127 push_to_history: bool,
1128 cx: &mut AsyncApp,
1129 ) -> anyhow::Result<ProjectTransaction> {
1130 // Do not allow multiple concurrent code actions requests for the
1131 // same buffer.
1132 lsp_store.update(cx, |this, cx| {
1133 let this = this.as_local_mut().unwrap();
1134 buffers.retain(|buffer| {
1135 this.buffers_being_formatted
1136 .insert(buffer.read(cx).remote_id())
1137 });
1138 })?;
1139 let _cleanup = defer({
1140 let this = lsp_store.clone();
1141 let mut cx = cx.clone();
1142 let buffers = &buffers;
1143 move || {
1144 this.update(&mut cx, |this, cx| {
1145 let this = this.as_local_mut().unwrap();
1146 for buffer in buffers {
1147 this.buffers_being_formatted
1148 .remove(&buffer.read(cx).remote_id());
1149 }
1150 })
1151 .ok();
1152 }
1153 });
1154 let mut project_transaction = ProjectTransaction::default();
1155
1156 for buffer in &buffers {
1157 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1158 buffer.update(cx, |buffer, cx| {
1159 lsp_store
1160 .as_local()
1161 .unwrap()
1162 .language_servers_for_buffer(buffer, cx)
1163 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1164 .collect::<Vec<_>>()
1165 })
1166 })?;
1167 for (_, language_server) in adapters_and_servers.iter() {
1168 let actions = Self::get_server_code_actions_from_action_kinds(
1169 &lsp_store,
1170 language_server.server_id(),
1171 vec![kind.clone()],
1172 buffer,
1173 cx,
1174 )
1175 .await?;
1176 Self::execute_code_actions_on_server(
1177 &lsp_store,
1178 language_server,
1179 actions,
1180 push_to_history,
1181 &mut project_transaction,
1182 cx,
1183 )
1184 .await?;
1185 }
1186 }
1187 Ok(project_transaction)
1188 }
1189
1190 async fn format_locally(
1191 lsp_store: WeakEntity<LspStore>,
1192 mut buffers: Vec<FormattableBuffer>,
1193 push_to_history: bool,
1194 trigger: FormatTrigger,
1195 logger: zlog::Logger,
1196 cx: &mut AsyncApp,
1197 ) -> anyhow::Result<ProjectTransaction> {
1198 // Do not allow multiple concurrent formatting requests for the
1199 // same buffer.
1200 lsp_store.update(cx, |this, cx| {
1201 let this = this.as_local_mut().unwrap();
1202 buffers.retain(|buffer| {
1203 this.buffers_being_formatted
1204 .insert(buffer.handle.read(cx).remote_id())
1205 });
1206 })?;
1207
1208 let _cleanup = defer({
1209 let this = lsp_store.clone();
1210 let mut cx = cx.clone();
1211 let buffers = &buffers;
1212 move || {
1213 this.update(&mut cx, |this, cx| {
1214 let this = this.as_local_mut().unwrap();
1215 for buffer in buffers {
1216 this.buffers_being_formatted
1217 .remove(&buffer.handle.read(cx).remote_id());
1218 }
1219 })
1220 .ok();
1221 }
1222 });
1223
1224 let mut project_transaction = ProjectTransaction::default();
1225
1226 for buffer in &buffers {
1227 zlog::debug!(
1228 logger =>
1229 "formatting buffer '{:?}'",
1230 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1231 );
1232 // Create an empty transaction to hold all of the formatting edits.
1233 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1234 // ensure no transactions created while formatting are
1235 // grouped with the previous transaction in the history
1236 // based on the transaction group interval
1237 buffer.finalize_last_transaction();
1238 buffer
1239 .start_transaction()
1240 .context("transaction already open")?;
1241 buffer.end_transaction(cx);
1242 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1243 buffer.finalize_last_transaction();
1244 anyhow::Ok(transaction_id)
1245 })??;
1246
1247 let result = Self::format_buffer_locally(
1248 lsp_store.clone(),
1249 buffer,
1250 formatting_transaction_id,
1251 trigger,
1252 logger,
1253 cx,
1254 )
1255 .await;
1256
1257 buffer.handle.update(cx, |buffer, cx| {
1258 let Some(formatting_transaction) =
1259 buffer.get_transaction(formatting_transaction_id).cloned()
1260 else {
1261 zlog::warn!(logger => "no formatting transaction");
1262 return;
1263 };
1264 if formatting_transaction.edit_ids.is_empty() {
1265 zlog::debug!(logger => "no changes made while formatting");
1266 buffer.forget_transaction(formatting_transaction_id);
1267 return;
1268 }
1269 if !push_to_history {
1270 zlog::trace!(logger => "forgetting format transaction");
1271 buffer.forget_transaction(formatting_transaction.id);
1272 }
1273 project_transaction
1274 .0
1275 .insert(cx.entity(), formatting_transaction);
1276 })?;
1277
1278 result?;
1279 }
1280
1281 Ok(project_transaction)
1282 }
1283
1284 async fn format_buffer_locally(
1285 lsp_store: WeakEntity<LspStore>,
1286 buffer: &FormattableBuffer,
1287 formatting_transaction_id: clock::Lamport,
1288 trigger: FormatTrigger,
1289 logger: zlog::Logger,
1290 cx: &mut AsyncApp,
1291 ) -> Result<()> {
1292 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1293 buffer.handle.update(cx, |buffer, cx| {
1294 let adapters_and_servers = lsp_store
1295 .as_local()
1296 .unwrap()
1297 .language_servers_for_buffer(buffer, cx)
1298 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1299 .collect::<Vec<_>>();
1300 let settings =
1301 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1302 .into_owned();
1303 (adapters_and_servers, settings)
1304 })
1305 })?;
1306
1307 /// Apply edits to the buffer that will become part of the formatting transaction.
1308 /// Fails if the buffer has been edited since the start of that transaction.
1309 fn extend_formatting_transaction(
1310 buffer: &FormattableBuffer,
1311 formatting_transaction_id: text::TransactionId,
1312 cx: &mut AsyncApp,
1313 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1314 ) -> anyhow::Result<()> {
1315 buffer.handle.update(cx, |buffer, cx| {
1316 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1317 if last_transaction_id != Some(formatting_transaction_id) {
1318 anyhow::bail!("Buffer edited while formatting. Aborting")
1319 }
1320 buffer.start_transaction();
1321 operation(buffer, cx);
1322 if let Some(transaction_id) = buffer.end_transaction(cx) {
1323 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1324 }
1325 Ok(())
1326 })?
1327 }
1328
1329 // handle whitespace formatting
1330 if settings.remove_trailing_whitespace_on_save {
1331 zlog::trace!(logger => "removing trailing whitespace");
1332 let diff = buffer
1333 .handle
1334 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1335 .await;
1336 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1337 buffer.apply_diff(diff, cx);
1338 })?;
1339 }
1340
1341 if settings.ensure_final_newline_on_save {
1342 zlog::trace!(logger => "ensuring final newline");
1343 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1344 buffer.ensure_final_newline(cx);
1345 })?;
1346 }
1347
1348 // Formatter for `code_actions_on_format` that runs before
1349 // the rest of the formatters
1350 let mut code_actions_on_format_formatters = None;
1351 let should_run_code_actions_on_format = !matches!(
1352 (trigger, &settings.format_on_save),
1353 (FormatTrigger::Save, &FormatOnSave::Off)
1354 );
1355 if should_run_code_actions_on_format {
1356 let have_code_actions_to_run_on_format = settings
1357 .code_actions_on_format
1358 .values()
1359 .any(|enabled| *enabled);
1360 if have_code_actions_to_run_on_format {
1361 zlog::trace!(logger => "going to run code actions on format");
1362 code_actions_on_format_formatters = Some(
1363 settings
1364 .code_actions_on_format
1365 .iter()
1366 .filter_map(|(action, enabled)| enabled.then_some(action))
1367 .cloned()
1368 .map(Formatter::CodeAction)
1369 .collect::<Vec<_>>(),
1370 );
1371 }
1372 }
1373
1374 let formatters = match (trigger, &settings.format_on_save) {
1375 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1376 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1377 settings.formatter.as_ref()
1378 }
1379 };
1380
1381 let formatters = code_actions_on_format_formatters
1382 .iter()
1383 .flatten()
1384 .chain(formatters);
1385
1386 for formatter in formatters {
1387 let formatter = if formatter == &Formatter::Auto {
1388 if settings.prettier.allowed {
1389 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1390 &Formatter::Prettier
1391 } else {
1392 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1393 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1394 }
1395 } else {
1396 formatter
1397 };
1398 match formatter {
1399 Formatter::Auto => unreachable!("Auto resolved above"),
1400 Formatter::Prettier => {
1401 let logger = zlog::scoped!(logger => "prettier");
1402 zlog::trace!(logger => "formatting");
1403 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1404
1405 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1406 lsp_store.prettier_store().unwrap().downgrade()
1407 })?;
1408 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1409 .await
1410 .transpose()?;
1411 let Some(diff) = diff else {
1412 zlog::trace!(logger => "No changes");
1413 continue;
1414 };
1415
1416 extend_formatting_transaction(
1417 buffer,
1418 formatting_transaction_id,
1419 cx,
1420 |buffer, cx| {
1421 buffer.apply_diff(diff, cx);
1422 },
1423 )?;
1424 }
1425 Formatter::External { command, arguments } => {
1426 let logger = zlog::scoped!(logger => "command");
1427 zlog::trace!(logger => "formatting");
1428 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1429
1430 let diff = Self::format_via_external_command(
1431 buffer,
1432 command.as_ref(),
1433 arguments.as_deref(),
1434 cx,
1435 )
1436 .await
1437 .with_context(|| {
1438 format!("Failed to format buffer via external command: {}", command)
1439 })?;
1440 let Some(diff) = diff else {
1441 zlog::trace!(logger => "No changes");
1442 continue;
1443 };
1444
1445 extend_formatting_transaction(
1446 buffer,
1447 formatting_transaction_id,
1448 cx,
1449 |buffer, cx| {
1450 buffer.apply_diff(diff, cx);
1451 },
1452 )?;
1453 }
1454 Formatter::LanguageServer(specifier) => {
1455 let logger = zlog::scoped!(logger => "language-server");
1456 zlog::trace!(logger => "formatting");
1457 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1458
1459 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1460 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1461 continue;
1462 };
1463
1464 let language_server = match specifier {
1465 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1466 adapters_and_servers.iter().find_map(|(adapter, server)| {
1467 if adapter.name.0.as_ref() == name {
1468 Some(server.clone())
1469 } else {
1470 None
1471 }
1472 })
1473 }
1474 settings::LanguageServerFormatterSpecifier::Current => {
1475 adapters_and_servers.first().map(|e| e.1.clone())
1476 }
1477 };
1478
1479 let Some(language_server) = language_server else {
1480 log::debug!(
1481 "No language server found to format buffer '{:?}'. Skipping",
1482 buffer_path_abs.as_path().to_string_lossy()
1483 );
1484 continue;
1485 };
1486
1487 zlog::trace!(
1488 logger =>
1489 "Formatting buffer '{:?}' using language server '{:?}'",
1490 buffer_path_abs.as_path().to_string_lossy(),
1491 language_server.name()
1492 );
1493
1494 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1495 zlog::trace!(logger => "formatting ranges");
1496 Self::format_ranges_via_lsp(
1497 &lsp_store,
1498 &buffer.handle,
1499 ranges,
1500 buffer_path_abs,
1501 &language_server,
1502 &settings,
1503 cx,
1504 )
1505 .await
1506 .context("Failed to format ranges via language server")?
1507 } else {
1508 zlog::trace!(logger => "formatting full");
1509 Self::format_via_lsp(
1510 &lsp_store,
1511 &buffer.handle,
1512 buffer_path_abs,
1513 &language_server,
1514 &settings,
1515 cx,
1516 )
1517 .await
1518 .context("failed to format via language server")?
1519 };
1520
1521 if edits.is_empty() {
1522 zlog::trace!(logger => "No changes");
1523 continue;
1524 }
1525 extend_formatting_transaction(
1526 buffer,
1527 formatting_transaction_id,
1528 cx,
1529 |buffer, cx| {
1530 buffer.edit(edits, None, cx);
1531 },
1532 )?;
1533 }
1534 Formatter::CodeAction(code_action_name) => {
1535 let logger = zlog::scoped!(logger => "code-actions");
1536 zlog::trace!(logger => "formatting");
1537 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1538
1539 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1540 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1541 continue;
1542 };
1543
1544 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1545 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1546
1547 let mut actions_and_servers = Vec::new();
1548
1549 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1550 let actions_result = Self::get_server_code_actions_from_action_kinds(
1551 &lsp_store,
1552 language_server.server_id(),
1553 vec![code_action_kind.clone()],
1554 &buffer.handle,
1555 cx,
1556 )
1557 .await
1558 .with_context(|| {
1559 format!(
1560 "Failed to resolve code action {:?} with language server {}",
1561 code_action_kind,
1562 language_server.name()
1563 )
1564 });
1565 let Ok(actions) = actions_result else {
1566 // note: it may be better to set result to the error and break formatters here
1567 // but for now we try to execute the actions that we can resolve and skip the rest
1568 zlog::error!(
1569 logger =>
1570 "Failed to resolve code action {:?} with language server {}",
1571 code_action_kind,
1572 language_server.name()
1573 );
1574 continue;
1575 };
1576 for action in actions {
1577 actions_and_servers.push((action, index));
1578 }
1579 }
1580
1581 if actions_and_servers.is_empty() {
1582 zlog::warn!(logger => "No code actions were resolved, continuing");
1583 continue;
1584 }
1585
1586 'actions: for (mut action, server_index) in actions_and_servers {
1587 let server = &adapters_and_servers[server_index].1;
1588
1589 let describe_code_action = |action: &CodeAction| {
1590 format!(
1591 "code action '{}' with title \"{}\" on server {}",
1592 action
1593 .lsp_action
1594 .action_kind()
1595 .unwrap_or("unknown".into())
1596 .as_str(),
1597 action.lsp_action.title(),
1598 server.name(),
1599 )
1600 };
1601
1602 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1603
1604 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1605 zlog::error!(
1606 logger =>
1607 "Failed to resolve {}. Error: {}",
1608 describe_code_action(&action),
1609 err
1610 );
1611 continue;
1612 }
1613
1614 if let Some(edit) = action.lsp_action.edit().cloned() {
1615 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1616 // but filters out and logs warnings for code actions that require unreasonably
1617 // difficult handling on our part, such as:
1618 // - applying edits that call commands
1619 // which can result in arbitrary workspace edits being sent from the server that
1620 // have no way of being tied back to the command that initiated them (i.e. we
1621 // can't know which edits are part of the format request, or if the server is done sending
1622 // actions in response to the command)
1623 // - actions that create/delete/modify/rename files other than the one we are formatting
1624 // as we then would need to handle such changes correctly in the local history as well
1625 // as the remote history through the ProjectTransaction
1626 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1627 // Supporting these actions is not impossible, but not supported as of yet.
1628 if edit.changes.is_none() && edit.document_changes.is_none() {
1629 zlog::trace!(
1630 logger =>
1631 "No changes for code action. Skipping {}",
1632 describe_code_action(&action),
1633 );
1634 continue;
1635 }
1636
1637 let mut operations = Vec::new();
1638 if let Some(document_changes) = edit.document_changes {
1639 match document_changes {
1640 lsp::DocumentChanges::Edits(edits) => operations.extend(
1641 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1642 ),
1643 lsp::DocumentChanges::Operations(ops) => operations = ops,
1644 }
1645 } else if let Some(changes) = edit.changes {
1646 operations.extend(changes.into_iter().map(|(uri, edits)| {
1647 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1648 text_document:
1649 lsp::OptionalVersionedTextDocumentIdentifier {
1650 uri,
1651 version: None,
1652 },
1653 edits: edits.into_iter().map(Edit::Plain).collect(),
1654 })
1655 }));
1656 }
1657
1658 let mut edits = Vec::with_capacity(operations.len());
1659
1660 if operations.is_empty() {
1661 zlog::trace!(
1662 logger =>
1663 "No changes for code action. Skipping {}",
1664 describe_code_action(&action),
1665 );
1666 continue;
1667 }
1668 for operation in operations {
1669 let op = match operation {
1670 lsp::DocumentChangeOperation::Edit(op) => op,
1671 lsp::DocumentChangeOperation::Op(_) => {
1672 zlog::warn!(
1673 logger =>
1674 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1675 describe_code_action(&action),
1676 );
1677 continue 'actions;
1678 }
1679 };
1680 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1681 zlog::warn!(
1682 logger =>
1683 "Failed to convert URI '{:?}' to file path. Skipping {}",
1684 &op.text_document.uri,
1685 describe_code_action(&action),
1686 );
1687 continue 'actions;
1688 };
1689 if &file_path != buffer_path_abs {
1690 zlog::warn!(
1691 logger =>
1692 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1693 file_path,
1694 buffer_path_abs,
1695 describe_code_action(&action),
1696 );
1697 continue 'actions;
1698 }
1699
1700 let mut lsp_edits = Vec::new();
1701 for edit in op.edits {
1702 match edit {
1703 Edit::Plain(edit) => {
1704 if !lsp_edits.contains(&edit) {
1705 lsp_edits.push(edit);
1706 }
1707 }
1708 Edit::Annotated(edit) => {
1709 if !lsp_edits.contains(&edit.text_edit) {
1710 lsp_edits.push(edit.text_edit);
1711 }
1712 }
1713 Edit::Snippet(_) => {
1714 zlog::warn!(
1715 logger =>
1716 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1717 describe_code_action(&action),
1718 );
1719 continue 'actions;
1720 }
1721 }
1722 }
1723 let edits_result = lsp_store
1724 .update(cx, |lsp_store, cx| {
1725 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1726 &buffer.handle,
1727 lsp_edits,
1728 server.server_id(),
1729 op.text_document.version,
1730 cx,
1731 )
1732 })?
1733 .await;
1734 let Ok(resolved_edits) = edits_result else {
1735 zlog::warn!(
1736 logger =>
1737 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1738 buffer_path_abs.as_path(),
1739 describe_code_action(&action),
1740 );
1741 continue 'actions;
1742 };
1743 edits.extend(resolved_edits);
1744 }
1745
1746 if edits.is_empty() {
1747 zlog::warn!(logger => "No edits resolved from LSP");
1748 continue;
1749 }
1750
1751 extend_formatting_transaction(
1752 buffer,
1753 formatting_transaction_id,
1754 cx,
1755 |buffer, cx| {
1756 zlog::info!(
1757 "Applying edits {edits:?}. Content: {:?}",
1758 buffer.text()
1759 );
1760 buffer.edit(edits, None, cx);
1761 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1762 },
1763 )?;
1764 }
1765
1766 if let Some(command) = action.lsp_action.command() {
1767 zlog::warn!(
1768 logger =>
1769 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1770 &command.command,
1771 );
1772
1773 // bail early if command is invalid
1774 let server_capabilities = server.capabilities();
1775 let available_commands = server_capabilities
1776 .execute_command_provider
1777 .as_ref()
1778 .map(|options| options.commands.as_slice())
1779 .unwrap_or_default();
1780 if !available_commands.contains(&command.command) {
1781 zlog::warn!(
1782 logger =>
1783 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1784 command.command,
1785 server.name(),
1786 );
1787 continue;
1788 }
1789
1790 // noop so we just ensure buffer hasn't been edited since resolving code actions
1791 extend_formatting_transaction(
1792 buffer,
1793 formatting_transaction_id,
1794 cx,
1795 |_, _| {},
1796 )?;
1797 zlog::info!(logger => "Executing command {}", &command.command);
1798
1799 lsp_store.update(cx, |this, _| {
1800 this.as_local_mut()
1801 .unwrap()
1802 .last_workspace_edits_by_language_server
1803 .remove(&server.server_id());
1804 })?;
1805
1806 let execute_command_result = server
1807 .request::<lsp::request::ExecuteCommand>(
1808 lsp::ExecuteCommandParams {
1809 command: command.command.clone(),
1810 arguments: command.arguments.clone().unwrap_or_default(),
1811 ..Default::default()
1812 },
1813 )
1814 .await
1815 .into_response();
1816
1817 if execute_command_result.is_err() {
1818 zlog::error!(
1819 logger =>
1820 "Failed to execute command '{}' as part of {}",
1821 &command.command,
1822 describe_code_action(&action),
1823 );
1824 continue 'actions;
1825 }
1826
1827 let mut project_transaction_command =
1828 lsp_store.update(cx, |this, _| {
1829 this.as_local_mut()
1830 .unwrap()
1831 .last_workspace_edits_by_language_server
1832 .remove(&server.server_id())
1833 .unwrap_or_default()
1834 })?;
1835
1836 if let Some(transaction) =
1837 project_transaction_command.0.remove(&buffer.handle)
1838 {
1839 zlog::trace!(
1840 logger =>
1841 "Successfully captured {} edits that resulted from command {}",
1842 transaction.edit_ids.len(),
1843 &command.command,
1844 );
1845 let transaction_id_project_transaction = transaction.id;
1846 buffer.handle.update(cx, |buffer, _| {
1847 // it may have been removed from history if push_to_history was
1848 // false in deserialize_workspace_edit. If so push it so we
1849 // can merge it with the format transaction
1850 // and pop the combined transaction off the history stack
1851 // later if push_to_history is false
1852 if buffer.get_transaction(transaction.id).is_none() {
1853 buffer.push_transaction(transaction, Instant::now());
1854 }
1855 buffer.merge_transactions(
1856 transaction_id_project_transaction,
1857 formatting_transaction_id,
1858 );
1859 })?;
1860 }
1861
1862 if !project_transaction_command.0.is_empty() {
1863 let mut extra_buffers = String::new();
1864 for buffer in project_transaction_command.0.keys() {
1865 buffer
1866 .read_with(cx, |b, cx| {
1867 if let Some(path) = b.project_path(cx) {
1868 if !extra_buffers.is_empty() {
1869 extra_buffers.push_str(", ");
1870 }
1871 extra_buffers.push_str(path.path.as_unix_str());
1872 }
1873 })
1874 .ok();
1875 }
1876 zlog::warn!(
1877 logger =>
1878 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1879 &command.command,
1880 extra_buffers,
1881 );
1882 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1883 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1884 // add it so it's included, and merge it into the format transaction when its created later
1885 }
1886 }
1887 }
1888 }
1889 }
1890 }
1891
1892 Ok(())
1893 }
1894
1895 pub async fn format_ranges_via_lsp(
1896 this: &WeakEntity<LspStore>,
1897 buffer_handle: &Entity<Buffer>,
1898 ranges: &[Range<Anchor>],
1899 abs_path: &Path,
1900 language_server: &Arc<LanguageServer>,
1901 settings: &LanguageSettings,
1902 cx: &mut AsyncApp,
1903 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1904 let capabilities = &language_server.capabilities();
1905 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1906 if range_formatting_provider == Some(&OneOf::Left(false)) {
1907 anyhow::bail!(
1908 "{} language server does not support range formatting",
1909 language_server.name()
1910 );
1911 }
1912
1913 let uri = file_path_to_lsp_url(abs_path)?;
1914 let text_document = lsp::TextDocumentIdentifier::new(uri);
1915
1916 let lsp_edits = {
1917 let mut lsp_ranges = Vec::new();
1918 this.update(cx, |_this, cx| {
1919 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1920 // not have been sent to the language server. This seems like a fairly systemic
1921 // issue, though, the resolution probably is not specific to formatting.
1922 //
1923 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1924 // LSP.
1925 let snapshot = buffer_handle.read(cx).snapshot();
1926 for range in ranges {
1927 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1928 }
1929 anyhow::Ok(())
1930 })??;
1931
1932 let mut edits = None;
1933 for range in lsp_ranges {
1934 if let Some(mut edit) = language_server
1935 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1936 text_document: text_document.clone(),
1937 range,
1938 options: lsp_command::lsp_formatting_options(settings),
1939 work_done_progress_params: Default::default(),
1940 })
1941 .await
1942 .into_response()?
1943 {
1944 edits.get_or_insert_with(Vec::new).append(&mut edit);
1945 }
1946 }
1947 edits
1948 };
1949
1950 if let Some(lsp_edits) = lsp_edits {
1951 this.update(cx, |this, cx| {
1952 this.as_local_mut().unwrap().edits_from_lsp(
1953 buffer_handle,
1954 lsp_edits,
1955 language_server.server_id(),
1956 None,
1957 cx,
1958 )
1959 })?
1960 .await
1961 } else {
1962 Ok(Vec::with_capacity(0))
1963 }
1964 }
1965
1966 async fn format_via_lsp(
1967 this: &WeakEntity<LspStore>,
1968 buffer: &Entity<Buffer>,
1969 abs_path: &Path,
1970 language_server: &Arc<LanguageServer>,
1971 settings: &LanguageSettings,
1972 cx: &mut AsyncApp,
1973 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1974 let logger = zlog::scoped!("lsp_format");
1975 zlog::info!(logger => "Formatting via LSP");
1976
1977 let uri = file_path_to_lsp_url(abs_path)?;
1978 let text_document = lsp::TextDocumentIdentifier::new(uri);
1979 let capabilities = &language_server.capabilities();
1980
1981 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1982 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1983
1984 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1985 let _timer = zlog::time!(logger => "format-full");
1986 language_server
1987 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1988 text_document,
1989 options: lsp_command::lsp_formatting_options(settings),
1990 work_done_progress_params: Default::default(),
1991 })
1992 .await
1993 .into_response()?
1994 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1995 let _timer = zlog::time!(logger => "format-range");
1996 let buffer_start = lsp::Position::new(0, 0);
1997 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1998 language_server
1999 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2000 text_document: text_document.clone(),
2001 range: lsp::Range::new(buffer_start, buffer_end),
2002 options: lsp_command::lsp_formatting_options(settings),
2003 work_done_progress_params: Default::default(),
2004 })
2005 .await
2006 .into_response()?
2007 } else {
2008 None
2009 };
2010
2011 if let Some(lsp_edits) = lsp_edits {
2012 this.update(cx, |this, cx| {
2013 this.as_local_mut().unwrap().edits_from_lsp(
2014 buffer,
2015 lsp_edits,
2016 language_server.server_id(),
2017 None,
2018 cx,
2019 )
2020 })?
2021 .await
2022 } else {
2023 Ok(Vec::with_capacity(0))
2024 }
2025 }
2026
2027 async fn format_via_external_command(
2028 buffer: &FormattableBuffer,
2029 command: &str,
2030 arguments: Option<&[String]>,
2031 cx: &mut AsyncApp,
2032 ) -> Result<Option<Diff>> {
2033 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2034 let file = File::from_dyn(buffer.file())?;
2035 let worktree = file.worktree.read(cx);
2036 let mut worktree_path = worktree.abs_path().to_path_buf();
2037 if worktree.root_entry()?.is_file() {
2038 worktree_path.pop();
2039 }
2040 Some(worktree_path)
2041 })?;
2042
2043 let mut child = util::command::new_smol_command(command);
2044
2045 if let Some(buffer_env) = buffer.env.as_ref() {
2046 child.envs(buffer_env);
2047 }
2048
2049 if let Some(working_dir_path) = working_dir_path {
2050 child.current_dir(working_dir_path);
2051 }
2052
2053 if let Some(arguments) = arguments {
2054 child.args(arguments.iter().map(|arg| {
2055 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2056 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2057 } else {
2058 arg.replace("{buffer_path}", "Untitled")
2059 }
2060 }));
2061 }
2062
2063 let mut child = child
2064 .stdin(smol::process::Stdio::piped())
2065 .stdout(smol::process::Stdio::piped())
2066 .stderr(smol::process::Stdio::piped())
2067 .spawn()?;
2068
2069 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2070 let text = buffer
2071 .handle
2072 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2073 for chunk in text.chunks() {
2074 stdin.write_all(chunk.as_bytes()).await?;
2075 }
2076 stdin.flush().await?;
2077
2078 let output = child.output().await?;
2079 anyhow::ensure!(
2080 output.status.success(),
2081 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2082 output.status.code(),
2083 String::from_utf8_lossy(&output.stdout),
2084 String::from_utf8_lossy(&output.stderr),
2085 );
2086
2087 let stdout = String::from_utf8(output.stdout)?;
2088 Ok(Some(
2089 buffer
2090 .handle
2091 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2092 .await,
2093 ))
2094 }
2095
2096 async fn try_resolve_code_action(
2097 lang_server: &LanguageServer,
2098 action: &mut CodeAction,
2099 ) -> anyhow::Result<()> {
2100 match &mut action.lsp_action {
2101 LspAction::Action(lsp_action) => {
2102 if !action.resolved
2103 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2104 && lsp_action.data.is_some()
2105 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2106 {
2107 *lsp_action = Box::new(
2108 lang_server
2109 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2110 .await
2111 .into_response()?,
2112 );
2113 }
2114 }
2115 LspAction::CodeLens(lens) => {
2116 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2117 *lens = lang_server
2118 .request::<lsp::request::CodeLensResolve>(lens.clone())
2119 .await
2120 .into_response()?;
2121 }
2122 }
2123 LspAction::Command(_) => {}
2124 }
2125
2126 action.resolved = true;
2127 anyhow::Ok(())
2128 }
2129
2130 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2131 let buffer = buffer_handle.read(cx);
2132
2133 let file = buffer.file().cloned();
2134
2135 let Some(file) = File::from_dyn(file.as_ref()) else {
2136 return;
2137 };
2138 if !file.is_local() {
2139 return;
2140 }
2141 let path = ProjectPath::from_file(file, cx);
2142 let worktree_id = file.worktree_id(cx);
2143 let language = buffer.language().cloned();
2144
2145 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2146 for (server_id, diagnostics) in
2147 diagnostics.get(file.path()).cloned().unwrap_or_default()
2148 {
2149 self.update_buffer_diagnostics(
2150 buffer_handle,
2151 server_id,
2152 None,
2153 None,
2154 diagnostics,
2155 Vec::new(),
2156 cx,
2157 )
2158 .log_err();
2159 }
2160 }
2161 let Some(language) = language else {
2162 return;
2163 };
2164 let Some(snapshot) = self
2165 .worktree_store
2166 .read(cx)
2167 .worktree_for_id(worktree_id, cx)
2168 .map(|worktree| worktree.read(cx).snapshot())
2169 else {
2170 return;
2171 };
2172 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2173
2174 for server_id in
2175 self.lsp_tree
2176 .get(path, language.name(), language.manifest(), &delegate, cx)
2177 {
2178 let server = self
2179 .language_servers
2180 .get(&server_id)
2181 .and_then(|server_state| {
2182 if let LanguageServerState::Running { server, .. } = server_state {
2183 Some(server.clone())
2184 } else {
2185 None
2186 }
2187 });
2188 let server = match server {
2189 Some(server) => server,
2190 None => continue,
2191 };
2192
2193 buffer_handle.update(cx, |buffer, cx| {
2194 buffer.set_completion_triggers(
2195 server.server_id(),
2196 server
2197 .capabilities()
2198 .completion_provider
2199 .as_ref()
2200 .and_then(|provider| {
2201 provider
2202 .trigger_characters
2203 .as_ref()
2204 .map(|characters| characters.iter().cloned().collect())
2205 })
2206 .unwrap_or_default(),
2207 cx,
2208 );
2209 });
2210 }
2211 }
2212
2213 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2214 buffer.update(cx, |buffer, cx| {
2215 let Some(language) = buffer.language() else {
2216 return;
2217 };
2218 let path = ProjectPath {
2219 worktree_id: old_file.worktree_id(cx),
2220 path: old_file.path.clone(),
2221 };
2222 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2223 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2224 buffer.set_completion_triggers(server_id, Default::default(), cx);
2225 }
2226 });
2227 }
2228
2229 fn update_buffer_diagnostics(
2230 &mut self,
2231 buffer: &Entity<Buffer>,
2232 server_id: LanguageServerId,
2233 result_id: Option<String>,
2234 version: Option<i32>,
2235 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2236 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2237 cx: &mut Context<LspStore>,
2238 ) -> Result<()> {
2239 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2240 Ordering::Equal
2241 .then_with(|| b.is_primary.cmp(&a.is_primary))
2242 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2243 .then_with(|| a.severity.cmp(&b.severity))
2244 .then_with(|| a.message.cmp(&b.message))
2245 }
2246
2247 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2248 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2249 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2250
2251 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2252 Ordering::Equal
2253 .then_with(|| a.range.start.cmp(&b.range.start))
2254 .then_with(|| b.range.end.cmp(&a.range.end))
2255 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2256 });
2257
2258 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2259
2260 let edits_since_save = std::cell::LazyCell::new(|| {
2261 let saved_version = buffer.read(cx).saved_version();
2262 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2263 });
2264
2265 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2266
2267 for (new_diagnostic, entry) in diagnostics {
2268 let start;
2269 let end;
2270 if new_diagnostic && entry.diagnostic.is_disk_based {
2271 // Some diagnostics are based on files on disk instead of buffers'
2272 // current contents. Adjust these diagnostics' ranges to reflect
2273 // any unsaved edits.
2274 // Do not alter the reused ones though, as their coordinates were stored as anchors
2275 // and were properly adjusted on reuse.
2276 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2277 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2278 } else {
2279 start = entry.range.start;
2280 end = entry.range.end;
2281 }
2282
2283 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2284 ..snapshot.clip_point_utf16(end, Bias::Right);
2285
2286 // Expand empty ranges by one codepoint
2287 if range.start == range.end {
2288 // This will be go to the next boundary when being clipped
2289 range.end.column += 1;
2290 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2291 if range.start == range.end && range.end.column > 0 {
2292 range.start.column -= 1;
2293 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2294 }
2295 }
2296
2297 sanitized_diagnostics.push(DiagnosticEntry {
2298 range,
2299 diagnostic: entry.diagnostic,
2300 });
2301 }
2302 drop(edits_since_save);
2303
2304 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2305 buffer.update(cx, |buffer, cx| {
2306 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2307 self.buffer_pull_diagnostics_result_ids
2308 .entry(server_id)
2309 .or_default()
2310 .insert(abs_path, result_id);
2311 }
2312
2313 buffer.update_diagnostics(server_id, set, cx)
2314 });
2315
2316 Ok(())
2317 }
2318
2319 fn register_language_server_for_invisible_worktree(
2320 &mut self,
2321 worktree: &Entity<Worktree>,
2322 language_server_id: LanguageServerId,
2323 cx: &mut App,
2324 ) {
2325 let worktree = worktree.read(cx);
2326 let worktree_id = worktree.id();
2327 debug_assert!(!worktree.is_visible());
2328 let Some(mut origin_seed) = self
2329 .language_server_ids
2330 .iter()
2331 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2332 else {
2333 return;
2334 };
2335 origin_seed.worktree_id = worktree_id;
2336 self.language_server_ids
2337 .entry(origin_seed)
2338 .or_insert_with(|| UnifiedLanguageServer {
2339 id: language_server_id,
2340 project_roots: Default::default(),
2341 });
2342 }
2343
2344 fn register_buffer_with_language_servers(
2345 &mut self,
2346 buffer_handle: &Entity<Buffer>,
2347 only_register_servers: HashSet<LanguageServerSelector>,
2348 cx: &mut Context<LspStore>,
2349 ) {
2350 let buffer = buffer_handle.read(cx);
2351 let buffer_id = buffer.remote_id();
2352
2353 let Some(file) = File::from_dyn(buffer.file()) else {
2354 return;
2355 };
2356 if !file.is_local() {
2357 return;
2358 }
2359
2360 let abs_path = file.abs_path(cx);
2361 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2362 return;
2363 };
2364 let initial_snapshot = buffer.text_snapshot();
2365 let worktree_id = file.worktree_id(cx);
2366
2367 let Some(language) = buffer.language().cloned() else {
2368 return;
2369 };
2370 let path: Arc<RelPath> = file
2371 .path()
2372 .parent()
2373 .map(Arc::from)
2374 .unwrap_or_else(|| file.path().clone());
2375 let Some(worktree) = self
2376 .worktree_store
2377 .read(cx)
2378 .worktree_for_id(worktree_id, cx)
2379 else {
2380 return;
2381 };
2382 let language_name = language.name();
2383 let (reused, delegate, servers) = self
2384 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2385 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2386 .unwrap_or_else(|| {
2387 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2388 let delegate: Arc<dyn ManifestDelegate> =
2389 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2390
2391 let servers = self
2392 .lsp_tree
2393 .walk(
2394 ProjectPath { worktree_id, path },
2395 language.name(),
2396 language.manifest(),
2397 &delegate,
2398 cx,
2399 )
2400 .collect::<Vec<_>>();
2401 (false, lsp_delegate, servers)
2402 });
2403 let servers_and_adapters = servers
2404 .into_iter()
2405 .filter_map(|server_node| {
2406 if reused && server_node.server_id().is_none() {
2407 return None;
2408 }
2409 if !only_register_servers.is_empty() {
2410 if let Some(server_id) = server_node.server_id()
2411 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2412 {
2413 return None;
2414 }
2415 if let Some(name) = server_node.name()
2416 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2417 {
2418 return None;
2419 }
2420 }
2421
2422 let server_id = server_node.server_id_or_init(|disposition| {
2423 let path = &disposition.path;
2424
2425 {
2426 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2427
2428 let server_id = self.get_or_insert_language_server(
2429 &worktree,
2430 delegate.clone(),
2431 disposition,
2432 &language_name,
2433 cx,
2434 );
2435
2436 if let Some(state) = self.language_servers.get(&server_id)
2437 && let Ok(uri) = uri
2438 {
2439 state.add_workspace_folder(uri);
2440 };
2441 server_id
2442 }
2443 })?;
2444 let server_state = self.language_servers.get(&server_id)?;
2445 if let LanguageServerState::Running {
2446 server, adapter, ..
2447 } = server_state
2448 {
2449 Some((server.clone(), adapter.clone()))
2450 } else {
2451 None
2452 }
2453 })
2454 .collect::<Vec<_>>();
2455 for (server, adapter) in servers_and_adapters {
2456 buffer_handle.update(cx, |buffer, cx| {
2457 buffer.set_completion_triggers(
2458 server.server_id(),
2459 server
2460 .capabilities()
2461 .completion_provider
2462 .as_ref()
2463 .and_then(|provider| {
2464 provider
2465 .trigger_characters
2466 .as_ref()
2467 .map(|characters| characters.iter().cloned().collect())
2468 })
2469 .unwrap_or_default(),
2470 cx,
2471 );
2472 });
2473
2474 let snapshot = LspBufferSnapshot {
2475 version: 0,
2476 snapshot: initial_snapshot.clone(),
2477 };
2478
2479 let mut registered = false;
2480 self.buffer_snapshots
2481 .entry(buffer_id)
2482 .or_default()
2483 .entry(server.server_id())
2484 .or_insert_with(|| {
2485 registered = true;
2486 server.register_buffer(
2487 uri.clone(),
2488 adapter.language_id(&language.name()),
2489 0,
2490 initial_snapshot.text_with_original_line_endings(),
2491 );
2492
2493 vec![snapshot]
2494 });
2495
2496 self.buffers_opened_in_servers
2497 .entry(buffer_id)
2498 .or_default()
2499 .insert(server.server_id());
2500 if registered {
2501 cx.emit(LspStoreEvent::LanguageServerUpdate {
2502 language_server_id: server.server_id(),
2503 name: None,
2504 message: proto::update_language_server::Variant::RegisteredForBuffer(
2505 proto::RegisteredForBuffer {
2506 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2507 buffer_id: buffer_id.to_proto(),
2508 },
2509 ),
2510 });
2511 }
2512 }
2513 }
2514
2515 fn reuse_existing_language_server<'lang_name>(
2516 &self,
2517 server_tree: &LanguageServerTree,
2518 worktree: &Entity<Worktree>,
2519 language_name: &'lang_name LanguageName,
2520 cx: &mut App,
2521 ) -> Option<(
2522 Arc<LocalLspAdapterDelegate>,
2523 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2524 )> {
2525 if worktree.read(cx).is_visible() {
2526 return None;
2527 }
2528
2529 let worktree_store = self.worktree_store.read(cx);
2530 let servers = server_tree
2531 .instances
2532 .iter()
2533 .filter(|(worktree_id, _)| {
2534 worktree_store
2535 .worktree_for_id(**worktree_id, cx)
2536 .is_some_and(|worktree| worktree.read(cx).is_visible())
2537 })
2538 .flat_map(|(worktree_id, servers)| {
2539 servers
2540 .roots
2541 .iter()
2542 .flat_map(|(_, language_servers)| language_servers)
2543 .map(move |(_, (server_node, server_languages))| {
2544 (worktree_id, server_node, server_languages)
2545 })
2546 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2547 .map(|(worktree_id, server_node, _)| {
2548 (
2549 *worktree_id,
2550 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2551 )
2552 })
2553 })
2554 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2555 acc.entry(worktree_id)
2556 .or_insert_with(Vec::new)
2557 .push(server_node);
2558 acc
2559 })
2560 .into_values()
2561 .max_by_key(|servers| servers.len())?;
2562
2563 let worktree_id = worktree.read(cx).id();
2564 let apply = move |tree: &mut LanguageServerTree| {
2565 for server_node in &servers {
2566 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2567 }
2568 servers
2569 };
2570
2571 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2572 Some((delegate, apply))
2573 }
2574
2575 pub(crate) fn unregister_old_buffer_from_language_servers(
2576 &mut self,
2577 buffer: &Entity<Buffer>,
2578 old_file: &File,
2579 cx: &mut App,
2580 ) {
2581 let old_path = match old_file.as_local() {
2582 Some(local) => local.abs_path(cx),
2583 None => return,
2584 };
2585
2586 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2587 debug_panic!("{old_path:?} is not parseable as an URI");
2588 return;
2589 };
2590 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2591 }
2592
2593 pub(crate) fn unregister_buffer_from_language_servers(
2594 &mut self,
2595 buffer: &Entity<Buffer>,
2596 file_url: &lsp::Uri,
2597 cx: &mut App,
2598 ) {
2599 buffer.update(cx, |buffer, cx| {
2600 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2601
2602 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2603 language_server.unregister_buffer(file_url.clone());
2604 }
2605 });
2606 }
2607
2608 fn buffer_snapshot_for_lsp_version(
2609 &mut self,
2610 buffer: &Entity<Buffer>,
2611 server_id: LanguageServerId,
2612 version: Option<i32>,
2613 cx: &App,
2614 ) -> Result<TextBufferSnapshot> {
2615 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2616
2617 if let Some(version) = version {
2618 let buffer_id = buffer.read(cx).remote_id();
2619 let snapshots = if let Some(snapshots) = self
2620 .buffer_snapshots
2621 .get_mut(&buffer_id)
2622 .and_then(|m| m.get_mut(&server_id))
2623 {
2624 snapshots
2625 } else if version == 0 {
2626 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2627 // We detect this case and treat it as if the version was `None`.
2628 return Ok(buffer.read(cx).text_snapshot());
2629 } else {
2630 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2631 };
2632
2633 let found_snapshot = snapshots
2634 .binary_search_by_key(&version, |e| e.version)
2635 .map(|ix| snapshots[ix].snapshot.clone())
2636 .map_err(|_| {
2637 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2638 })?;
2639
2640 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2641 Ok(found_snapshot)
2642 } else {
2643 Ok((buffer.read(cx)).text_snapshot())
2644 }
2645 }
2646
2647 async fn get_server_code_actions_from_action_kinds(
2648 lsp_store: &WeakEntity<LspStore>,
2649 language_server_id: LanguageServerId,
2650 code_action_kinds: Vec<lsp::CodeActionKind>,
2651 buffer: &Entity<Buffer>,
2652 cx: &mut AsyncApp,
2653 ) -> Result<Vec<CodeAction>> {
2654 let actions = lsp_store
2655 .update(cx, move |this, cx| {
2656 let request = GetCodeActions {
2657 range: text::Anchor::MIN..text::Anchor::MAX,
2658 kinds: Some(code_action_kinds),
2659 };
2660 let server = LanguageServerToQuery::Other(language_server_id);
2661 this.request_lsp(buffer.clone(), server, request, cx)
2662 })?
2663 .await?;
2664 Ok(actions)
2665 }
2666
2667 pub async fn execute_code_actions_on_server(
2668 lsp_store: &WeakEntity<LspStore>,
2669 language_server: &Arc<LanguageServer>,
2670
2671 actions: Vec<CodeAction>,
2672 push_to_history: bool,
2673 project_transaction: &mut ProjectTransaction,
2674 cx: &mut AsyncApp,
2675 ) -> anyhow::Result<()> {
2676 for mut action in actions {
2677 Self::try_resolve_code_action(language_server, &mut action)
2678 .await
2679 .context("resolving a formatting code action")?;
2680
2681 if let Some(edit) = action.lsp_action.edit() {
2682 if edit.changes.is_none() && edit.document_changes.is_none() {
2683 continue;
2684 }
2685
2686 let new = Self::deserialize_workspace_edit(
2687 lsp_store.upgrade().context("project dropped")?,
2688 edit.clone(),
2689 push_to_history,
2690 language_server.clone(),
2691 cx,
2692 )
2693 .await?;
2694 project_transaction.0.extend(new.0);
2695 }
2696
2697 if let Some(command) = action.lsp_action.command() {
2698 let server_capabilities = language_server.capabilities();
2699 let available_commands = server_capabilities
2700 .execute_command_provider
2701 .as_ref()
2702 .map(|options| options.commands.as_slice())
2703 .unwrap_or_default();
2704 if available_commands.contains(&command.command) {
2705 lsp_store.update(cx, |lsp_store, _| {
2706 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2707 mode.last_workspace_edits_by_language_server
2708 .remove(&language_server.server_id());
2709 }
2710 })?;
2711
2712 language_server
2713 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2714 command: command.command.clone(),
2715 arguments: command.arguments.clone().unwrap_or_default(),
2716 ..Default::default()
2717 })
2718 .await
2719 .into_response()
2720 .context("execute command")?;
2721
2722 lsp_store.update(cx, |this, _| {
2723 if let LspStoreMode::Local(mode) = &mut this.mode {
2724 project_transaction.0.extend(
2725 mode.last_workspace_edits_by_language_server
2726 .remove(&language_server.server_id())
2727 .unwrap_or_default()
2728 .0,
2729 )
2730 }
2731 })?;
2732 } else {
2733 log::warn!(
2734 "Cannot execute a command {} not listed in the language server capabilities",
2735 command.command
2736 )
2737 }
2738 }
2739 }
2740 Ok(())
2741 }
2742
2743 pub async fn deserialize_text_edits(
2744 this: Entity<LspStore>,
2745 buffer_to_edit: Entity<Buffer>,
2746 edits: Vec<lsp::TextEdit>,
2747 push_to_history: bool,
2748 _: Arc<CachedLspAdapter>,
2749 language_server: Arc<LanguageServer>,
2750 cx: &mut AsyncApp,
2751 ) -> Result<Option<Transaction>> {
2752 let edits = this
2753 .update(cx, |this, cx| {
2754 this.as_local_mut().unwrap().edits_from_lsp(
2755 &buffer_to_edit,
2756 edits,
2757 language_server.server_id(),
2758 None,
2759 cx,
2760 )
2761 })?
2762 .await?;
2763
2764 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2765 buffer.finalize_last_transaction();
2766 buffer.start_transaction();
2767 for (range, text) in edits {
2768 buffer.edit([(range, text)], None, cx);
2769 }
2770
2771 if buffer.end_transaction(cx).is_some() {
2772 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2773 if !push_to_history {
2774 buffer.forget_transaction(transaction.id);
2775 }
2776 Some(transaction)
2777 } else {
2778 None
2779 }
2780 })?;
2781
2782 Ok(transaction)
2783 }
2784
2785 #[allow(clippy::type_complexity)]
2786 pub(crate) fn edits_from_lsp(
2787 &mut self,
2788 buffer: &Entity<Buffer>,
2789 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2790 server_id: LanguageServerId,
2791 version: Option<i32>,
2792 cx: &mut Context<LspStore>,
2793 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2794 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2795 cx.background_spawn(async move {
2796 let snapshot = snapshot?;
2797 let mut lsp_edits = lsp_edits
2798 .into_iter()
2799 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2800 .collect::<Vec<_>>();
2801
2802 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2803
2804 let mut lsp_edits = lsp_edits.into_iter().peekable();
2805 let mut edits = Vec::new();
2806 while let Some((range, mut new_text)) = lsp_edits.next() {
2807 // Clip invalid ranges provided by the language server.
2808 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2809 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2810
2811 // Combine any LSP edits that are adjacent.
2812 //
2813 // Also, combine LSP edits that are separated from each other by only
2814 // a newline. This is important because for some code actions,
2815 // Rust-analyzer rewrites the entire buffer via a series of edits that
2816 // are separated by unchanged newline characters.
2817 //
2818 // In order for the diffing logic below to work properly, any edits that
2819 // cancel each other out must be combined into one.
2820 while let Some((next_range, next_text)) = lsp_edits.peek() {
2821 if next_range.start.0 > range.end {
2822 if next_range.start.0.row > range.end.row + 1
2823 || next_range.start.0.column > 0
2824 || snapshot.clip_point_utf16(
2825 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2826 Bias::Left,
2827 ) > range.end
2828 {
2829 break;
2830 }
2831 new_text.push('\n');
2832 }
2833 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2834 new_text.push_str(next_text);
2835 lsp_edits.next();
2836 }
2837
2838 // For multiline edits, perform a diff of the old and new text so that
2839 // we can identify the changes more precisely, preserving the locations
2840 // of any anchors positioned in the unchanged regions.
2841 if range.end.row > range.start.row {
2842 let offset = range.start.to_offset(&snapshot);
2843 let old_text = snapshot.text_for_range(range).collect::<String>();
2844 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2845 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2846 (
2847 snapshot.anchor_after(offset + range.start)
2848 ..snapshot.anchor_before(offset + range.end),
2849 replacement,
2850 )
2851 }));
2852 } else if range.end == range.start {
2853 let anchor = snapshot.anchor_after(range.start);
2854 edits.push((anchor..anchor, new_text.into()));
2855 } else {
2856 let edit_start = snapshot.anchor_after(range.start);
2857 let edit_end = snapshot.anchor_before(range.end);
2858 edits.push((edit_start..edit_end, new_text.into()));
2859 }
2860 }
2861
2862 Ok(edits)
2863 })
2864 }
2865
2866 pub(crate) async fn deserialize_workspace_edit(
2867 this: Entity<LspStore>,
2868 edit: lsp::WorkspaceEdit,
2869 push_to_history: bool,
2870 language_server: Arc<LanguageServer>,
2871 cx: &mut AsyncApp,
2872 ) -> Result<ProjectTransaction> {
2873 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2874
2875 let mut operations = Vec::new();
2876 if let Some(document_changes) = edit.document_changes {
2877 match document_changes {
2878 lsp::DocumentChanges::Edits(edits) => {
2879 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2880 }
2881 lsp::DocumentChanges::Operations(ops) => operations = ops,
2882 }
2883 } else if let Some(changes) = edit.changes {
2884 operations.extend(changes.into_iter().map(|(uri, edits)| {
2885 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2886 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2887 uri,
2888 version: None,
2889 },
2890 edits: edits.into_iter().map(Edit::Plain).collect(),
2891 })
2892 }));
2893 }
2894
2895 let mut project_transaction = ProjectTransaction::default();
2896 for operation in operations {
2897 match operation {
2898 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2899 let abs_path = op
2900 .uri
2901 .to_file_path()
2902 .map_err(|()| anyhow!("can't convert URI to path"))?;
2903
2904 if let Some(parent_path) = abs_path.parent() {
2905 fs.create_dir(parent_path).await?;
2906 }
2907 if abs_path.ends_with("/") {
2908 fs.create_dir(&abs_path).await?;
2909 } else {
2910 fs.create_file(
2911 &abs_path,
2912 op.options
2913 .map(|options| fs::CreateOptions {
2914 overwrite: options.overwrite.unwrap_or(false),
2915 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2916 })
2917 .unwrap_or_default(),
2918 )
2919 .await?;
2920 }
2921 }
2922
2923 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2924 let source_abs_path = op
2925 .old_uri
2926 .to_file_path()
2927 .map_err(|()| anyhow!("can't convert URI to path"))?;
2928 let target_abs_path = op
2929 .new_uri
2930 .to_file_path()
2931 .map_err(|()| anyhow!("can't convert URI to path"))?;
2932 fs.rename(
2933 &source_abs_path,
2934 &target_abs_path,
2935 op.options
2936 .map(|options| fs::RenameOptions {
2937 overwrite: options.overwrite.unwrap_or(false),
2938 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2939 })
2940 .unwrap_or_default(),
2941 )
2942 .await?;
2943 }
2944
2945 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
2946 let abs_path = op
2947 .uri
2948 .to_file_path()
2949 .map_err(|()| anyhow!("can't convert URI to path"))?;
2950 let options = op
2951 .options
2952 .map(|options| fs::RemoveOptions {
2953 recursive: options.recursive.unwrap_or(false),
2954 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
2955 })
2956 .unwrap_or_default();
2957 if abs_path.ends_with("/") {
2958 fs.remove_dir(&abs_path, options).await?;
2959 } else {
2960 fs.remove_file(&abs_path, options).await?;
2961 }
2962 }
2963
2964 lsp::DocumentChangeOperation::Edit(op) => {
2965 let buffer_to_edit = this
2966 .update(cx, |this, cx| {
2967 this.open_local_buffer_via_lsp(
2968 op.text_document.uri.clone(),
2969 language_server.server_id(),
2970 cx,
2971 )
2972 })?
2973 .await?;
2974
2975 let edits = this
2976 .update(cx, |this, cx| {
2977 let path = buffer_to_edit.read(cx).project_path(cx);
2978 let active_entry = this.active_entry;
2979 let is_active_entry = path.is_some_and(|project_path| {
2980 this.worktree_store
2981 .read(cx)
2982 .entry_for_path(&project_path, cx)
2983 .is_some_and(|entry| Some(entry.id) == active_entry)
2984 });
2985 let local = this.as_local_mut().unwrap();
2986
2987 let (mut edits, mut snippet_edits) = (vec![], vec![]);
2988 for edit in op.edits {
2989 match edit {
2990 Edit::Plain(edit) => {
2991 if !edits.contains(&edit) {
2992 edits.push(edit)
2993 }
2994 }
2995 Edit::Annotated(edit) => {
2996 if !edits.contains(&edit.text_edit) {
2997 edits.push(edit.text_edit)
2998 }
2999 }
3000 Edit::Snippet(edit) => {
3001 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3002 else {
3003 continue;
3004 };
3005
3006 if is_active_entry {
3007 snippet_edits.push((edit.range, snippet));
3008 } else {
3009 // Since this buffer is not focused, apply a normal edit.
3010 let new_edit = TextEdit {
3011 range: edit.range,
3012 new_text: snippet.text,
3013 };
3014 if !edits.contains(&new_edit) {
3015 edits.push(new_edit);
3016 }
3017 }
3018 }
3019 }
3020 }
3021 if !snippet_edits.is_empty() {
3022 let buffer_id = buffer_to_edit.read(cx).remote_id();
3023 let version = if let Some(buffer_version) = op.text_document.version
3024 {
3025 local
3026 .buffer_snapshot_for_lsp_version(
3027 &buffer_to_edit,
3028 language_server.server_id(),
3029 Some(buffer_version),
3030 cx,
3031 )
3032 .ok()
3033 .map(|snapshot| snapshot.version)
3034 } else {
3035 Some(buffer_to_edit.read(cx).saved_version().clone())
3036 };
3037
3038 let most_recent_edit =
3039 version.and_then(|version| version.most_recent());
3040 // Check if the edit that triggered that edit has been made by this participant.
3041
3042 if let Some(most_recent_edit) = most_recent_edit {
3043 cx.emit(LspStoreEvent::SnippetEdit {
3044 buffer_id,
3045 edits: snippet_edits,
3046 most_recent_edit,
3047 });
3048 }
3049 }
3050
3051 local.edits_from_lsp(
3052 &buffer_to_edit,
3053 edits,
3054 language_server.server_id(),
3055 op.text_document.version,
3056 cx,
3057 )
3058 })?
3059 .await?;
3060
3061 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3062 buffer.finalize_last_transaction();
3063 buffer.start_transaction();
3064 for (range, text) in edits {
3065 buffer.edit([(range, text)], None, cx);
3066 }
3067
3068 buffer.end_transaction(cx).and_then(|transaction_id| {
3069 if push_to_history {
3070 buffer.finalize_last_transaction();
3071 buffer.get_transaction(transaction_id).cloned()
3072 } else {
3073 buffer.forget_transaction(transaction_id)
3074 }
3075 })
3076 })?;
3077 if let Some(transaction) = transaction {
3078 project_transaction.0.insert(buffer_to_edit, transaction);
3079 }
3080 }
3081 }
3082 }
3083
3084 Ok(project_transaction)
3085 }
3086
3087 async fn on_lsp_workspace_edit(
3088 this: WeakEntity<LspStore>,
3089 params: lsp::ApplyWorkspaceEditParams,
3090 server_id: LanguageServerId,
3091 cx: &mut AsyncApp,
3092 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3093 let this = this.upgrade().context("project project closed")?;
3094 let language_server = this
3095 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3096 .context("language server not found")?;
3097 let transaction = Self::deserialize_workspace_edit(
3098 this.clone(),
3099 params.edit,
3100 true,
3101 language_server.clone(),
3102 cx,
3103 )
3104 .await
3105 .log_err();
3106 this.update(cx, |this, _| {
3107 if let Some(transaction) = transaction {
3108 this.as_local_mut()
3109 .unwrap()
3110 .last_workspace_edits_by_language_server
3111 .insert(server_id, transaction);
3112 }
3113 })?;
3114 Ok(lsp::ApplyWorkspaceEditResponse {
3115 applied: true,
3116 failed_change: None,
3117 failure_reason: None,
3118 })
3119 }
3120
3121 fn remove_worktree(
3122 &mut self,
3123 id_to_remove: WorktreeId,
3124 cx: &mut Context<LspStore>,
3125 ) -> Vec<LanguageServerId> {
3126 self.diagnostics.remove(&id_to_remove);
3127 self.prettier_store.update(cx, |prettier_store, cx| {
3128 prettier_store.remove_worktree(id_to_remove, cx);
3129 });
3130
3131 let mut servers_to_remove = BTreeSet::default();
3132 let mut servers_to_preserve = HashSet::default();
3133 for (seed, state) in &self.language_server_ids {
3134 if seed.worktree_id == id_to_remove {
3135 servers_to_remove.insert(state.id);
3136 } else {
3137 servers_to_preserve.insert(state.id);
3138 }
3139 }
3140 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3141 self.language_server_ids
3142 .retain(|_, state| !servers_to_remove.contains(&state.id));
3143 for server_id_to_remove in &servers_to_remove {
3144 self.language_server_watched_paths
3145 .remove(server_id_to_remove);
3146 self.language_server_paths_watched_for_rename
3147 .remove(server_id_to_remove);
3148 self.last_workspace_edits_by_language_server
3149 .remove(server_id_to_remove);
3150 self.language_servers.remove(server_id_to_remove);
3151 self.buffer_pull_diagnostics_result_ids
3152 .remove(server_id_to_remove);
3153 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3154 buffer_servers.remove(server_id_to_remove);
3155 }
3156 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3157 }
3158 servers_to_remove.into_iter().collect()
3159 }
3160
3161 fn rebuild_watched_paths_inner<'a>(
3162 &'a self,
3163 language_server_id: LanguageServerId,
3164 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3165 cx: &mut Context<LspStore>,
3166 ) -> LanguageServerWatchedPathsBuilder {
3167 let worktrees = self
3168 .worktree_store
3169 .read(cx)
3170 .worktrees()
3171 .filter_map(|worktree| {
3172 self.language_servers_for_worktree(worktree.read(cx).id())
3173 .find(|server| server.server_id() == language_server_id)
3174 .map(|_| worktree)
3175 })
3176 .collect::<Vec<_>>();
3177
3178 let mut worktree_globs = HashMap::default();
3179 let mut abs_globs = HashMap::default();
3180 log::trace!(
3181 "Processing new watcher paths for language server with id {}",
3182 language_server_id
3183 );
3184
3185 for watcher in watchers {
3186 if let Some((worktree, literal_prefix, pattern)) =
3187 self.worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3188 {
3189 worktree.update(cx, |worktree, _| {
3190 if let Some((tree, glob)) =
3191 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3192 {
3193 tree.add_path_prefix_to_scan(literal_prefix);
3194 worktree_globs
3195 .entry(tree.id())
3196 .or_insert_with(GlobSetBuilder::new)
3197 .add(glob);
3198 }
3199 });
3200 } else {
3201 let (path, pattern) = match &watcher.glob_pattern {
3202 lsp::GlobPattern::String(s) => {
3203 let watcher_path = SanitizedPath::new(s);
3204 let path = glob_literal_prefix(watcher_path.as_path());
3205 let pattern = watcher_path
3206 .as_path()
3207 .strip_prefix(&path)
3208 .map(|p| p.to_string_lossy().into_owned())
3209 .unwrap_or_else(|e| {
3210 debug_panic!(
3211 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3212 s,
3213 path.display(),
3214 e
3215 );
3216 watcher_path.as_path().to_string_lossy().into_owned()
3217 });
3218 (path, pattern)
3219 }
3220 lsp::GlobPattern::Relative(rp) => {
3221 let Ok(mut base_uri) = match &rp.base_uri {
3222 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3223 lsp::OneOf::Right(base_uri) => base_uri,
3224 }
3225 .to_file_path() else {
3226 continue;
3227 };
3228
3229 let path = glob_literal_prefix(Path::new(&rp.pattern));
3230 let pattern = Path::new(&rp.pattern)
3231 .strip_prefix(&path)
3232 .map(|p| p.to_string_lossy().into_owned())
3233 .unwrap_or_else(|e| {
3234 debug_panic!(
3235 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3236 rp.pattern,
3237 path.display(),
3238 e
3239 );
3240 rp.pattern.clone()
3241 });
3242 base_uri.push(path);
3243 (base_uri, pattern)
3244 }
3245 };
3246
3247 if let Some(glob) = Glob::new(&pattern).log_err() {
3248 if !path
3249 .components()
3250 .any(|c| matches!(c, path::Component::Normal(_)))
3251 {
3252 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3253 // rather than adding a new watcher for `/`.
3254 for worktree in &worktrees {
3255 worktree_globs
3256 .entry(worktree.read(cx).id())
3257 .or_insert_with(GlobSetBuilder::new)
3258 .add(glob.clone());
3259 }
3260 } else {
3261 abs_globs
3262 .entry(path.into())
3263 .or_insert_with(GlobSetBuilder::new)
3264 .add(glob);
3265 }
3266 }
3267 }
3268 }
3269
3270 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3271 for (worktree_id, builder) in worktree_globs {
3272 if let Ok(globset) = builder.build() {
3273 watch_builder.watch_worktree(worktree_id, globset);
3274 }
3275 }
3276 for (abs_path, builder) in abs_globs {
3277 if let Ok(globset) = builder.build() {
3278 watch_builder.watch_abs_path(abs_path, globset);
3279 }
3280 }
3281 watch_builder
3282 }
3283
3284 fn worktree_and_path_for_file_watcher(
3285 &self,
3286 worktrees: &[Entity<Worktree>],
3287 watcher: &FileSystemWatcher,
3288 cx: &App,
3289 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3290 worktrees.iter().find_map(|worktree| {
3291 let tree = worktree.read(cx);
3292 let worktree_root_path = tree.abs_path();
3293 let path_style = tree.path_style();
3294 match &watcher.glob_pattern {
3295 lsp::GlobPattern::String(s) => {
3296 let watcher_path = SanitizedPath::new(s);
3297 let relative = watcher_path
3298 .as_path()
3299 .strip_prefix(&worktree_root_path)
3300 .ok()?;
3301 let literal_prefix = glob_literal_prefix(relative);
3302 Some((
3303 worktree.clone(),
3304 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3305 relative.to_string_lossy().into_owned(),
3306 ))
3307 }
3308 lsp::GlobPattern::Relative(rp) => {
3309 let base_uri = match &rp.base_uri {
3310 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3311 lsp::OneOf::Right(base_uri) => base_uri,
3312 }
3313 .to_file_path()
3314 .ok()?;
3315 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3316 let mut literal_prefix = relative.to_owned();
3317 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3318 Some((
3319 worktree.clone(),
3320 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3321 rp.pattern.clone(),
3322 ))
3323 }
3324 }
3325 })
3326 }
3327
3328 fn rebuild_watched_paths(
3329 &mut self,
3330 language_server_id: LanguageServerId,
3331 cx: &mut Context<LspStore>,
3332 ) {
3333 let Some(watchers) = self
3334 .language_server_watcher_registrations
3335 .get(&language_server_id)
3336 else {
3337 return;
3338 };
3339
3340 let watch_builder =
3341 self.rebuild_watched_paths_inner(language_server_id, watchers.values().flatten(), cx);
3342 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3343 self.language_server_watched_paths
3344 .insert(language_server_id, watcher);
3345
3346 cx.notify();
3347 }
3348
3349 fn on_lsp_did_change_watched_files(
3350 &mut self,
3351 language_server_id: LanguageServerId,
3352 registration_id: &str,
3353 params: DidChangeWatchedFilesRegistrationOptions,
3354 cx: &mut Context<LspStore>,
3355 ) {
3356 let registrations = self
3357 .language_server_watcher_registrations
3358 .entry(language_server_id)
3359 .or_default();
3360
3361 registrations.insert(registration_id.to_string(), params.watchers);
3362
3363 self.rebuild_watched_paths(language_server_id, cx);
3364 }
3365
3366 fn on_lsp_unregister_did_change_watched_files(
3367 &mut self,
3368 language_server_id: LanguageServerId,
3369 registration_id: &str,
3370 cx: &mut Context<LspStore>,
3371 ) {
3372 let registrations = self
3373 .language_server_watcher_registrations
3374 .entry(language_server_id)
3375 .or_default();
3376
3377 if registrations.remove(registration_id).is_some() {
3378 log::info!(
3379 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3380 language_server_id,
3381 registration_id
3382 );
3383 } else {
3384 log::warn!(
3385 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3386 language_server_id,
3387 registration_id
3388 );
3389 }
3390
3391 self.rebuild_watched_paths(language_server_id, cx);
3392 }
3393
3394 async fn initialization_options_for_adapter(
3395 adapter: Arc<dyn LspAdapter>,
3396 delegate: &Arc<dyn LspAdapterDelegate>,
3397 ) -> Result<Option<serde_json::Value>> {
3398 let Some(mut initialization_config) =
3399 adapter.clone().initialization_options(delegate).await?
3400 else {
3401 return Ok(None);
3402 };
3403
3404 for other_adapter in delegate.registered_lsp_adapters() {
3405 if other_adapter.name() == adapter.name() {
3406 continue;
3407 }
3408 if let Ok(Some(target_config)) = other_adapter
3409 .clone()
3410 .additional_initialization_options(adapter.name(), delegate)
3411 .await
3412 {
3413 merge_json_value_into(target_config.clone(), &mut initialization_config);
3414 }
3415 }
3416
3417 Ok(Some(initialization_config))
3418 }
3419
3420 async fn workspace_configuration_for_adapter(
3421 adapter: Arc<dyn LspAdapter>,
3422 delegate: &Arc<dyn LspAdapterDelegate>,
3423 toolchain: Option<Toolchain>,
3424 cx: &mut AsyncApp,
3425 ) -> Result<serde_json::Value> {
3426 let mut workspace_config = adapter
3427 .clone()
3428 .workspace_configuration(delegate, toolchain, cx)
3429 .await?;
3430
3431 for other_adapter in delegate.registered_lsp_adapters() {
3432 if other_adapter.name() == adapter.name() {
3433 continue;
3434 }
3435 if let Ok(Some(target_config)) = other_adapter
3436 .clone()
3437 .additional_workspace_configuration(adapter.name(), delegate, cx)
3438 .await
3439 {
3440 merge_json_value_into(target_config.clone(), &mut workspace_config);
3441 }
3442 }
3443
3444 Ok(workspace_config)
3445 }
3446
3447 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3448 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3449 Some(server.clone())
3450 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3451 Some(Arc::clone(server))
3452 } else {
3453 None
3454 }
3455 }
3456}
3457
3458fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3459 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3460 cx.emit(LspStoreEvent::LanguageServerUpdate {
3461 language_server_id: server.server_id(),
3462 name: Some(server.name()),
3463 message: proto::update_language_server::Variant::MetadataUpdated(
3464 proto::ServerMetadataUpdated {
3465 capabilities: Some(capabilities),
3466 },
3467 ),
3468 });
3469 }
3470}
3471
3472#[derive(Debug)]
3473pub struct FormattableBuffer {
3474 handle: Entity<Buffer>,
3475 abs_path: Option<PathBuf>,
3476 env: Option<HashMap<String, String>>,
3477 ranges: Option<Vec<Range<Anchor>>>,
3478}
3479
3480pub struct RemoteLspStore {
3481 upstream_client: Option<AnyProtoClient>,
3482 upstream_project_id: u64,
3483}
3484
3485pub(crate) enum LspStoreMode {
3486 Local(LocalLspStore), // ssh host and collab host
3487 Remote(RemoteLspStore), // collab guest
3488}
3489
3490impl LspStoreMode {
3491 fn is_local(&self) -> bool {
3492 matches!(self, LspStoreMode::Local(_))
3493 }
3494}
3495
3496pub struct LspStore {
3497 mode: LspStoreMode,
3498 last_formatting_failure: Option<String>,
3499 downstream_client: Option<(AnyProtoClient, u64)>,
3500 nonce: u128,
3501 buffer_store: Entity<BufferStore>,
3502 worktree_store: Entity<WorktreeStore>,
3503 pub languages: Arc<LanguageRegistry>,
3504 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3505 active_entry: Option<ProjectEntryId>,
3506 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3507 _maintain_buffer_languages: Task<()>,
3508 diagnostic_summaries:
3509 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3510 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3511 lsp_data: HashMap<BufferId, BufferLspData>,
3512 next_hint_id: Arc<AtomicUsize>,
3513}
3514
3515#[derive(Debug)]
3516pub struct BufferLspData {
3517 buffer_version: Global,
3518 document_colors: Option<DocumentColorData>,
3519 code_lens: Option<CodeLensData>,
3520 inlay_hints: BufferInlayHints,
3521 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3522 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3523}
3524
3525#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3526struct LspKey {
3527 request_type: TypeId,
3528 server_queried: Option<LanguageServerId>,
3529}
3530
3531impl BufferLspData {
3532 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3533 Self {
3534 buffer_version: buffer.read(cx).version(),
3535 document_colors: None,
3536 code_lens: None,
3537 inlay_hints: BufferInlayHints::new(buffer, cx),
3538 lsp_requests: HashMap::default(),
3539 chunk_lsp_requests: HashMap::default(),
3540 }
3541 }
3542
3543 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3544 if let Some(document_colors) = &mut self.document_colors {
3545 document_colors.colors.remove(&for_server);
3546 document_colors.cache_version += 1;
3547 }
3548
3549 if let Some(code_lens) = &mut self.code_lens {
3550 code_lens.lens.remove(&for_server);
3551 }
3552
3553 self.inlay_hints.remove_server_data(for_server);
3554 }
3555
3556 #[cfg(any(test, feature = "test-support"))]
3557 pub fn inlay_hints(&self) -> &BufferInlayHints {
3558 &self.inlay_hints
3559 }
3560}
3561
3562#[derive(Debug, Default, Clone)]
3563pub struct DocumentColors {
3564 pub colors: HashSet<DocumentColor>,
3565 pub cache_version: Option<usize>,
3566}
3567
3568type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3569type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3570
3571#[derive(Debug, Default)]
3572struct DocumentColorData {
3573 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3574 cache_version: usize,
3575 colors_update: Option<(Global, DocumentColorTask)>,
3576}
3577
3578#[derive(Debug, Default)]
3579struct CodeLensData {
3580 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3581 update: Option<(Global, CodeLensTask)>,
3582}
3583
3584#[derive(Debug)]
3585pub enum LspStoreEvent {
3586 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3587 LanguageServerRemoved(LanguageServerId),
3588 LanguageServerUpdate {
3589 language_server_id: LanguageServerId,
3590 name: Option<LanguageServerName>,
3591 message: proto::update_language_server::Variant,
3592 },
3593 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3594 LanguageServerPrompt(LanguageServerPromptRequest),
3595 LanguageDetected {
3596 buffer: Entity<Buffer>,
3597 new_language: Option<Arc<Language>>,
3598 },
3599 Notification(String),
3600 RefreshInlayHints(LanguageServerId),
3601 RefreshCodeLens,
3602 DiagnosticsUpdated {
3603 server_id: LanguageServerId,
3604 paths: Vec<ProjectPath>,
3605 },
3606 DiskBasedDiagnosticsStarted {
3607 language_server_id: LanguageServerId,
3608 },
3609 DiskBasedDiagnosticsFinished {
3610 language_server_id: LanguageServerId,
3611 },
3612 SnippetEdit {
3613 buffer_id: BufferId,
3614 edits: Vec<(lsp::Range, Snippet)>,
3615 most_recent_edit: clock::Lamport,
3616 },
3617}
3618
3619#[derive(Clone, Debug, Serialize)]
3620pub struct LanguageServerStatus {
3621 pub name: LanguageServerName,
3622 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3623 pub has_pending_diagnostic_updates: bool,
3624 progress_tokens: HashSet<String>,
3625 pub worktree: Option<WorktreeId>,
3626}
3627
3628#[derive(Clone, Debug)]
3629struct CoreSymbol {
3630 pub language_server_name: LanguageServerName,
3631 pub source_worktree_id: WorktreeId,
3632 pub source_language_server_id: LanguageServerId,
3633 pub path: SymbolLocation,
3634 pub name: String,
3635 pub kind: lsp::SymbolKind,
3636 pub range: Range<Unclipped<PointUtf16>>,
3637}
3638
3639#[derive(Clone, Debug, PartialEq, Eq)]
3640pub enum SymbolLocation {
3641 InProject(ProjectPath),
3642 OutsideProject {
3643 abs_path: Arc<Path>,
3644 signature: [u8; 32],
3645 },
3646}
3647
3648impl SymbolLocation {
3649 fn file_name(&self) -> Option<&str> {
3650 match self {
3651 Self::InProject(path) => path.path.file_name(),
3652 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3653 }
3654 }
3655}
3656
3657impl LspStore {
3658 pub fn init(client: &AnyProtoClient) {
3659 client.add_entity_request_handler(Self::handle_lsp_query);
3660 client.add_entity_message_handler(Self::handle_lsp_query_response);
3661 client.add_entity_request_handler(Self::handle_restart_language_servers);
3662 client.add_entity_request_handler(Self::handle_stop_language_servers);
3663 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3664 client.add_entity_message_handler(Self::handle_start_language_server);
3665 client.add_entity_message_handler(Self::handle_update_language_server);
3666 client.add_entity_message_handler(Self::handle_language_server_log);
3667 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3668 client.add_entity_request_handler(Self::handle_format_buffers);
3669 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3670 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3671 client.add_entity_request_handler(Self::handle_apply_code_action);
3672 client.add_entity_request_handler(Self::handle_get_project_symbols);
3673 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3674 client.add_entity_request_handler(Self::handle_get_color_presentation);
3675 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3676 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3677 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3678 client.add_entity_request_handler(Self::handle_on_type_formatting);
3679 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3680 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3681 client.add_entity_request_handler(Self::handle_rename_project_entry);
3682 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3683 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3684 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3685 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3686 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3687 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3688 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3689
3690 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3691 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3692 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3693 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3694 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3695 client.add_entity_request_handler(
3696 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3697 );
3698 client.add_entity_request_handler(
3699 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3700 );
3701 client.add_entity_request_handler(
3702 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3703 );
3704 }
3705
3706 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3707 match &self.mode {
3708 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3709 _ => None,
3710 }
3711 }
3712
3713 pub fn as_local(&self) -> Option<&LocalLspStore> {
3714 match &self.mode {
3715 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3716 _ => None,
3717 }
3718 }
3719
3720 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3721 match &mut self.mode {
3722 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3723 _ => None,
3724 }
3725 }
3726
3727 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3728 match &self.mode {
3729 LspStoreMode::Remote(RemoteLspStore {
3730 upstream_client: Some(upstream_client),
3731 upstream_project_id,
3732 ..
3733 }) => Some((upstream_client.clone(), *upstream_project_id)),
3734
3735 LspStoreMode::Remote(RemoteLspStore {
3736 upstream_client: None,
3737 ..
3738 }) => None,
3739 LspStoreMode::Local(_) => None,
3740 }
3741 }
3742
3743 pub fn new_local(
3744 buffer_store: Entity<BufferStore>,
3745 worktree_store: Entity<WorktreeStore>,
3746 prettier_store: Entity<PrettierStore>,
3747 toolchain_store: Entity<LocalToolchainStore>,
3748 environment: Entity<ProjectEnvironment>,
3749 manifest_tree: Entity<ManifestTree>,
3750 languages: Arc<LanguageRegistry>,
3751 http_client: Arc<dyn HttpClient>,
3752 fs: Arc<dyn Fs>,
3753 cx: &mut Context<Self>,
3754 ) -> Self {
3755 let yarn = YarnPathStore::new(fs.clone(), cx);
3756 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3757 .detach();
3758 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3759 .detach();
3760 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3761 .detach();
3762 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3763 .detach();
3764 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3765 .detach();
3766 subscribe_to_binary_statuses(&languages, cx).detach();
3767
3768 let _maintain_workspace_config = {
3769 let (sender, receiver) = watch::channel();
3770 (Self::maintain_workspace_config(receiver, cx), sender)
3771 };
3772
3773 Self {
3774 mode: LspStoreMode::Local(LocalLspStore {
3775 weak: cx.weak_entity(),
3776 worktree_store: worktree_store.clone(),
3777
3778 supplementary_language_servers: Default::default(),
3779 languages: languages.clone(),
3780 language_server_ids: Default::default(),
3781 language_servers: Default::default(),
3782 last_workspace_edits_by_language_server: Default::default(),
3783 language_server_watched_paths: Default::default(),
3784 language_server_paths_watched_for_rename: Default::default(),
3785 language_server_watcher_registrations: Default::default(),
3786 buffers_being_formatted: Default::default(),
3787 buffer_snapshots: Default::default(),
3788 prettier_store,
3789 environment,
3790 http_client,
3791 fs,
3792 yarn,
3793 next_diagnostic_group_id: Default::default(),
3794 diagnostics: Default::default(),
3795 _subscription: cx.on_app_quit(|this, cx| {
3796 this.as_local_mut()
3797 .unwrap()
3798 .shutdown_language_servers_on_quit(cx)
3799 }),
3800 lsp_tree: LanguageServerTree::new(
3801 manifest_tree,
3802 languages.clone(),
3803 toolchain_store.clone(),
3804 ),
3805 toolchain_store,
3806 registered_buffers: HashMap::default(),
3807 buffers_opened_in_servers: HashMap::default(),
3808 buffer_pull_diagnostics_result_ids: HashMap::default(),
3809 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3810 .manifest_file_names(),
3811 }),
3812 last_formatting_failure: None,
3813 downstream_client: None,
3814 buffer_store,
3815 worktree_store,
3816 languages: languages.clone(),
3817 language_server_statuses: Default::default(),
3818 nonce: StdRng::from_os_rng().random(),
3819 diagnostic_summaries: HashMap::default(),
3820 lsp_server_capabilities: HashMap::default(),
3821 lsp_data: HashMap::default(),
3822 next_hint_id: Arc::default(),
3823 active_entry: None,
3824 _maintain_workspace_config,
3825 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3826 }
3827 }
3828
3829 fn send_lsp_proto_request<R: LspCommand>(
3830 &self,
3831 buffer: Entity<Buffer>,
3832 client: AnyProtoClient,
3833 upstream_project_id: u64,
3834 request: R,
3835 cx: &mut Context<LspStore>,
3836 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3837 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3838 return Task::ready(Ok(R::Response::default()));
3839 }
3840 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3841 cx.spawn(async move |this, cx| {
3842 let response = client.request(message).await?;
3843 let this = this.upgrade().context("project dropped")?;
3844 request
3845 .response_from_proto(response, this, buffer, cx.clone())
3846 .await
3847 })
3848 }
3849
3850 pub(super) fn new_remote(
3851 buffer_store: Entity<BufferStore>,
3852 worktree_store: Entity<WorktreeStore>,
3853 languages: Arc<LanguageRegistry>,
3854 upstream_client: AnyProtoClient,
3855 project_id: u64,
3856 cx: &mut Context<Self>,
3857 ) -> Self {
3858 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3859 .detach();
3860 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3861 .detach();
3862 subscribe_to_binary_statuses(&languages, cx).detach();
3863 let _maintain_workspace_config = {
3864 let (sender, receiver) = watch::channel();
3865 (Self::maintain_workspace_config(receiver, cx), sender)
3866 };
3867 Self {
3868 mode: LspStoreMode::Remote(RemoteLspStore {
3869 upstream_client: Some(upstream_client),
3870 upstream_project_id: project_id,
3871 }),
3872 downstream_client: None,
3873 last_formatting_failure: None,
3874 buffer_store,
3875 worktree_store,
3876 languages: languages.clone(),
3877 language_server_statuses: Default::default(),
3878 nonce: StdRng::from_os_rng().random(),
3879 diagnostic_summaries: HashMap::default(),
3880 lsp_server_capabilities: HashMap::default(),
3881 next_hint_id: Arc::default(),
3882 lsp_data: HashMap::default(),
3883 active_entry: None,
3884
3885 _maintain_workspace_config,
3886 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3887 }
3888 }
3889
3890 fn on_buffer_store_event(
3891 &mut self,
3892 _: Entity<BufferStore>,
3893 event: &BufferStoreEvent,
3894 cx: &mut Context<Self>,
3895 ) {
3896 match event {
3897 BufferStoreEvent::BufferAdded(buffer) => {
3898 self.on_buffer_added(buffer, cx).log_err();
3899 }
3900 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3901 let buffer_id = buffer.read(cx).remote_id();
3902 if let Some(local) = self.as_local_mut()
3903 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3904 {
3905 local.reset_buffer(buffer, old_file, cx);
3906
3907 if local.registered_buffers.contains_key(&buffer_id) {
3908 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3909 }
3910 }
3911
3912 self.detect_language_for_buffer(buffer, cx);
3913 if let Some(local) = self.as_local_mut() {
3914 local.initialize_buffer(buffer, cx);
3915 if local.registered_buffers.contains_key(&buffer_id) {
3916 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3917 }
3918 }
3919 }
3920 _ => {}
3921 }
3922 }
3923
3924 fn on_worktree_store_event(
3925 &mut self,
3926 _: Entity<WorktreeStore>,
3927 event: &WorktreeStoreEvent,
3928 cx: &mut Context<Self>,
3929 ) {
3930 match event {
3931 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3932 if !worktree.read(cx).is_local() {
3933 return;
3934 }
3935 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3936 worktree::Event::UpdatedEntries(changes) => {
3937 this.update_local_worktree_language_servers(&worktree, changes, cx);
3938 }
3939 worktree::Event::UpdatedGitRepositories(_)
3940 | worktree::Event::DeletedEntry(_) => {}
3941 })
3942 .detach()
3943 }
3944 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3945 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3946 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3947 }
3948 WorktreeStoreEvent::WorktreeReleased(..)
3949 | WorktreeStoreEvent::WorktreeOrderChanged
3950 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3951 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3952 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3953 }
3954 }
3955
3956 fn on_prettier_store_event(
3957 &mut self,
3958 _: Entity<PrettierStore>,
3959 event: &PrettierStoreEvent,
3960 cx: &mut Context<Self>,
3961 ) {
3962 match event {
3963 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3964 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3965 }
3966 PrettierStoreEvent::LanguageServerAdded {
3967 new_server_id,
3968 name,
3969 prettier_server,
3970 } => {
3971 self.register_supplementary_language_server(
3972 *new_server_id,
3973 name.clone(),
3974 prettier_server.clone(),
3975 cx,
3976 );
3977 }
3978 }
3979 }
3980
3981 fn on_toolchain_store_event(
3982 &mut self,
3983 _: Entity<LocalToolchainStore>,
3984 event: &ToolchainStoreEvent,
3985 _: &mut Context<Self>,
3986 ) {
3987 if let ToolchainStoreEvent::ToolchainActivated = event {
3988 self.request_workspace_config_refresh()
3989 }
3990 }
3991
3992 fn request_workspace_config_refresh(&mut self) {
3993 *self._maintain_workspace_config.1.borrow_mut() = ();
3994 }
3995
3996 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
3997 self.as_local().map(|local| local.prettier_store.clone())
3998 }
3999
4000 fn on_buffer_event(
4001 &mut self,
4002 buffer: Entity<Buffer>,
4003 event: &language::BufferEvent,
4004 cx: &mut Context<Self>,
4005 ) {
4006 match event {
4007 language::BufferEvent::Edited => {
4008 self.on_buffer_edited(buffer, cx);
4009 }
4010
4011 language::BufferEvent::Saved => {
4012 self.on_buffer_saved(buffer, cx);
4013 }
4014
4015 _ => {}
4016 }
4017 }
4018
4019 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4020 buffer
4021 .read(cx)
4022 .set_language_registry(self.languages.clone());
4023
4024 cx.subscribe(buffer, |this, buffer, event, cx| {
4025 this.on_buffer_event(buffer, event, cx);
4026 })
4027 .detach();
4028
4029 self.detect_language_for_buffer(buffer, cx);
4030 if let Some(local) = self.as_local_mut() {
4031 local.initialize_buffer(buffer, cx);
4032 }
4033
4034 Ok(())
4035 }
4036
4037 pub(crate) fn register_buffer_with_language_servers(
4038 &mut self,
4039 buffer: &Entity<Buffer>,
4040 only_register_servers: HashSet<LanguageServerSelector>,
4041 ignore_refcounts: bool,
4042 cx: &mut Context<Self>,
4043 ) -> OpenLspBufferHandle {
4044 let buffer_id = buffer.read(cx).remote_id();
4045 let handle = cx.new(|_| buffer.clone());
4046 if let Some(local) = self.as_local_mut() {
4047 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4048 if !ignore_refcounts {
4049 *refcount += 1;
4050 }
4051
4052 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4053 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4054 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4055 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4056 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4057 return handle;
4058 };
4059 if !file.is_local() {
4060 return handle;
4061 }
4062
4063 if ignore_refcounts || *refcount == 1 {
4064 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4065 }
4066 if !ignore_refcounts {
4067 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4068 let refcount = {
4069 let local = lsp_store.as_local_mut().unwrap();
4070 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4071 debug_panic!("bad refcounting");
4072 return;
4073 };
4074
4075 *refcount -= 1;
4076 *refcount
4077 };
4078 if refcount == 0 {
4079 lsp_store.lsp_data.remove(&buffer_id);
4080 let local = lsp_store.as_local_mut().unwrap();
4081 local.registered_buffers.remove(&buffer_id);
4082 local.buffers_opened_in_servers.remove(&buffer_id);
4083 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4084 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4085 }
4086 }
4087 })
4088 .detach();
4089 }
4090 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4091 let buffer_id = buffer.read(cx).remote_id().to_proto();
4092 cx.background_spawn(async move {
4093 upstream_client
4094 .request(proto::RegisterBufferWithLanguageServers {
4095 project_id: upstream_project_id,
4096 buffer_id,
4097 only_servers: only_register_servers
4098 .into_iter()
4099 .map(|selector| {
4100 let selector = match selector {
4101 LanguageServerSelector::Id(language_server_id) => {
4102 proto::language_server_selector::Selector::ServerId(
4103 language_server_id.to_proto(),
4104 )
4105 }
4106 LanguageServerSelector::Name(language_server_name) => {
4107 proto::language_server_selector::Selector::Name(
4108 language_server_name.to_string(),
4109 )
4110 }
4111 };
4112 proto::LanguageServerSelector {
4113 selector: Some(selector),
4114 }
4115 })
4116 .collect(),
4117 })
4118 .await
4119 })
4120 .detach();
4121 } else {
4122 panic!("oops!");
4123 }
4124 handle
4125 }
4126
4127 fn maintain_buffer_languages(
4128 languages: Arc<LanguageRegistry>,
4129 cx: &mut Context<Self>,
4130 ) -> Task<()> {
4131 let mut subscription = languages.subscribe();
4132 let mut prev_reload_count = languages.reload_count();
4133 cx.spawn(async move |this, cx| {
4134 while let Some(()) = subscription.next().await {
4135 if let Some(this) = this.upgrade() {
4136 // If the language registry has been reloaded, then remove and
4137 // re-assign the languages on all open buffers.
4138 let reload_count = languages.reload_count();
4139 if reload_count > prev_reload_count {
4140 prev_reload_count = reload_count;
4141 this.update(cx, |this, cx| {
4142 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4143 for buffer in buffer_store.buffers() {
4144 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4145 {
4146 buffer
4147 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4148 if let Some(local) = this.as_local_mut() {
4149 local.reset_buffer(&buffer, &f, cx);
4150
4151 if local
4152 .registered_buffers
4153 .contains_key(&buffer.read(cx).remote_id())
4154 && let Some(file_url) =
4155 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4156 {
4157 local.unregister_buffer_from_language_servers(
4158 &buffer, &file_url, cx,
4159 );
4160 }
4161 }
4162 }
4163 }
4164 });
4165 })
4166 .ok();
4167 }
4168
4169 this.update(cx, |this, cx| {
4170 let mut plain_text_buffers = Vec::new();
4171 let mut buffers_with_unknown_injections = Vec::new();
4172 for handle in this.buffer_store.read(cx).buffers() {
4173 let buffer = handle.read(cx);
4174 if buffer.language().is_none()
4175 || buffer.language() == Some(&*language::PLAIN_TEXT)
4176 {
4177 plain_text_buffers.push(handle);
4178 } else if buffer.contains_unknown_injections() {
4179 buffers_with_unknown_injections.push(handle);
4180 }
4181 }
4182
4183 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4184 // and reused later in the invisible worktrees.
4185 plain_text_buffers.sort_by_key(|buffer| {
4186 Reverse(
4187 File::from_dyn(buffer.read(cx).file())
4188 .map(|file| file.worktree.read(cx).is_visible()),
4189 )
4190 });
4191
4192 for buffer in plain_text_buffers {
4193 this.detect_language_for_buffer(&buffer, cx);
4194 if let Some(local) = this.as_local_mut() {
4195 local.initialize_buffer(&buffer, cx);
4196 if local
4197 .registered_buffers
4198 .contains_key(&buffer.read(cx).remote_id())
4199 {
4200 local.register_buffer_with_language_servers(
4201 &buffer,
4202 HashSet::default(),
4203 cx,
4204 );
4205 }
4206 }
4207 }
4208
4209 for buffer in buffers_with_unknown_injections {
4210 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4211 }
4212 })
4213 .ok();
4214 }
4215 }
4216 })
4217 }
4218
4219 fn detect_language_for_buffer(
4220 &mut self,
4221 buffer_handle: &Entity<Buffer>,
4222 cx: &mut Context<Self>,
4223 ) -> Option<language::AvailableLanguage> {
4224 // If the buffer has a language, set it and start the language server if we haven't already.
4225 let buffer = buffer_handle.read(cx);
4226 let file = buffer.file()?;
4227
4228 let content = buffer.as_rope();
4229 let available_language = self.languages.language_for_file(file, Some(content), cx);
4230 if let Some(available_language) = &available_language {
4231 if let Some(Ok(Ok(new_language))) = self
4232 .languages
4233 .load_language(available_language)
4234 .now_or_never()
4235 {
4236 self.set_language_for_buffer(buffer_handle, new_language, cx);
4237 }
4238 } else {
4239 cx.emit(LspStoreEvent::LanguageDetected {
4240 buffer: buffer_handle.clone(),
4241 new_language: None,
4242 });
4243 }
4244
4245 available_language
4246 }
4247
4248 pub(crate) fn set_language_for_buffer(
4249 &mut self,
4250 buffer_entity: &Entity<Buffer>,
4251 new_language: Arc<Language>,
4252 cx: &mut Context<Self>,
4253 ) {
4254 let buffer = buffer_entity.read(cx);
4255 let buffer_file = buffer.file().cloned();
4256 let buffer_id = buffer.remote_id();
4257 if let Some(local_store) = self.as_local_mut()
4258 && local_store.registered_buffers.contains_key(&buffer_id)
4259 && let Some(abs_path) =
4260 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4261 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4262 {
4263 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4264 }
4265 buffer_entity.update(cx, |buffer, cx| {
4266 if buffer
4267 .language()
4268 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4269 {
4270 buffer.set_language(Some(new_language.clone()), cx);
4271 }
4272 });
4273
4274 let settings =
4275 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4276 let buffer_file = File::from_dyn(buffer_file.as_ref());
4277
4278 let worktree_id = if let Some(file) = buffer_file {
4279 let worktree = file.worktree.clone();
4280
4281 if let Some(local) = self.as_local_mut()
4282 && local.registered_buffers.contains_key(&buffer_id)
4283 {
4284 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4285 }
4286 Some(worktree.read(cx).id())
4287 } else {
4288 None
4289 };
4290
4291 if settings.prettier.allowed
4292 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4293 {
4294 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4295 if let Some(prettier_store) = prettier_store {
4296 prettier_store.update(cx, |prettier_store, cx| {
4297 prettier_store.install_default_prettier(
4298 worktree_id,
4299 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4300 cx,
4301 )
4302 })
4303 }
4304 }
4305
4306 cx.emit(LspStoreEvent::LanguageDetected {
4307 buffer: buffer_entity.clone(),
4308 new_language: Some(new_language),
4309 })
4310 }
4311
4312 pub fn buffer_store(&self) -> Entity<BufferStore> {
4313 self.buffer_store.clone()
4314 }
4315
4316 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4317 self.active_entry = active_entry;
4318 }
4319
4320 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4321 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4322 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4323 {
4324 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4325 summaries
4326 .iter()
4327 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4328 });
4329 if let Some(summary) = summaries.next() {
4330 client
4331 .send(proto::UpdateDiagnosticSummary {
4332 project_id: downstream_project_id,
4333 worktree_id: worktree.id().to_proto(),
4334 summary: Some(summary),
4335 more_summaries: summaries.collect(),
4336 })
4337 .log_err();
4338 }
4339 }
4340 }
4341
4342 fn is_capable_for_proto_request<R>(
4343 &self,
4344 buffer: &Entity<Buffer>,
4345 request: &R,
4346 cx: &App,
4347 ) -> bool
4348 where
4349 R: LspCommand,
4350 {
4351 self.check_if_capable_for_proto_request(
4352 buffer,
4353 |capabilities| {
4354 request.check_capabilities(AdapterServerCapabilities {
4355 server_capabilities: capabilities.clone(),
4356 code_action_kinds: None,
4357 })
4358 },
4359 cx,
4360 )
4361 }
4362
4363 fn check_if_capable_for_proto_request<F>(
4364 &self,
4365 buffer: &Entity<Buffer>,
4366 check: F,
4367 cx: &App,
4368 ) -> bool
4369 where
4370 F: Fn(&lsp::ServerCapabilities) -> bool,
4371 {
4372 let Some(language) = buffer.read(cx).language().cloned() else {
4373 return false;
4374 };
4375 let relevant_language_servers = self
4376 .languages
4377 .lsp_adapters(&language.name())
4378 .into_iter()
4379 .map(|lsp_adapter| lsp_adapter.name())
4380 .collect::<HashSet<_>>();
4381 self.language_server_statuses
4382 .iter()
4383 .filter_map(|(server_id, server_status)| {
4384 relevant_language_servers
4385 .contains(&server_status.name)
4386 .then_some(server_id)
4387 })
4388 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4389 .any(check)
4390 }
4391
4392 pub fn request_lsp<R>(
4393 &mut self,
4394 buffer: Entity<Buffer>,
4395 server: LanguageServerToQuery,
4396 request: R,
4397 cx: &mut Context<Self>,
4398 ) -> Task<Result<R::Response>>
4399 where
4400 R: LspCommand,
4401 <R::LspRequest as lsp::request::Request>::Result: Send,
4402 <R::LspRequest as lsp::request::Request>::Params: Send,
4403 {
4404 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4405 return self.send_lsp_proto_request(
4406 buffer,
4407 upstream_client,
4408 upstream_project_id,
4409 request,
4410 cx,
4411 );
4412 }
4413
4414 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4415 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4416 local
4417 .language_servers_for_buffer(buffer, cx)
4418 .find(|(_, server)| {
4419 request.check_capabilities(server.adapter_server_capabilities())
4420 })
4421 .map(|(_, server)| server.clone())
4422 }),
4423 LanguageServerToQuery::Other(id) => self
4424 .language_server_for_local_buffer(buffer, id, cx)
4425 .and_then(|(_, server)| {
4426 request
4427 .check_capabilities(server.adapter_server_capabilities())
4428 .then(|| Arc::clone(server))
4429 }),
4430 }) else {
4431 return Task::ready(Ok(Default::default()));
4432 };
4433
4434 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4435
4436 let Some(file) = file else {
4437 return Task::ready(Ok(Default::default()));
4438 };
4439
4440 let lsp_params = match request.to_lsp_params_or_response(
4441 &file.abs_path(cx),
4442 buffer.read(cx),
4443 &language_server,
4444 cx,
4445 ) {
4446 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4447 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4448
4449 Err(err) => {
4450 let message = format!(
4451 "{} via {} failed: {}",
4452 request.display_name(),
4453 language_server.name(),
4454 err
4455 );
4456 log::warn!("{message}");
4457 return Task::ready(Err(anyhow!(message)));
4458 }
4459 };
4460
4461 let status = request.status();
4462 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4463 return Task::ready(Ok(Default::default()));
4464 }
4465 cx.spawn(async move |this, cx| {
4466 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4467
4468 let id = lsp_request.id();
4469 let _cleanup = if status.is_some() {
4470 cx.update(|cx| {
4471 this.update(cx, |this, cx| {
4472 this.on_lsp_work_start(
4473 language_server.server_id(),
4474 id.to_string(),
4475 LanguageServerProgress {
4476 is_disk_based_diagnostics_progress: false,
4477 is_cancellable: false,
4478 title: None,
4479 message: status.clone(),
4480 percentage: None,
4481 last_update_at: cx.background_executor().now(),
4482 },
4483 cx,
4484 );
4485 })
4486 })
4487 .log_err();
4488
4489 Some(defer(|| {
4490 cx.update(|cx| {
4491 this.update(cx, |this, cx| {
4492 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4493 })
4494 })
4495 .log_err();
4496 }))
4497 } else {
4498 None
4499 };
4500
4501 let result = lsp_request.await.into_response();
4502
4503 let response = result.map_err(|err| {
4504 let message = format!(
4505 "{} via {} failed: {}",
4506 request.display_name(),
4507 language_server.name(),
4508 err
4509 );
4510 log::warn!("{message}");
4511 anyhow::anyhow!(message)
4512 })?;
4513
4514 request
4515 .response_from_lsp(
4516 response,
4517 this.upgrade().context("no app context")?,
4518 buffer,
4519 language_server.server_id(),
4520 cx.clone(),
4521 )
4522 .await
4523 })
4524 }
4525
4526 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4527 let mut language_formatters_to_check = Vec::new();
4528 for buffer in self.buffer_store.read(cx).buffers() {
4529 let buffer = buffer.read(cx);
4530 let buffer_file = File::from_dyn(buffer.file());
4531 let buffer_language = buffer.language();
4532 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4533 if buffer_language.is_some() {
4534 language_formatters_to_check.push((
4535 buffer_file.map(|f| f.worktree_id(cx)),
4536 settings.into_owned(),
4537 ));
4538 }
4539 }
4540
4541 self.request_workspace_config_refresh();
4542
4543 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4544 prettier_store.update(cx, |prettier_store, cx| {
4545 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4546 })
4547 }
4548
4549 cx.notify();
4550 }
4551
4552 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4553 let buffer_store = self.buffer_store.clone();
4554 let Some(local) = self.as_local_mut() else {
4555 return;
4556 };
4557 let mut adapters = BTreeMap::default();
4558 let get_adapter = {
4559 let languages = local.languages.clone();
4560 let environment = local.environment.clone();
4561 let weak = local.weak.clone();
4562 let worktree_store = local.worktree_store.clone();
4563 let http_client = local.http_client.clone();
4564 let fs = local.fs.clone();
4565 move |worktree_id, cx: &mut App| {
4566 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4567 Some(LocalLspAdapterDelegate::new(
4568 languages.clone(),
4569 &environment,
4570 weak.clone(),
4571 &worktree,
4572 http_client.clone(),
4573 fs.clone(),
4574 cx,
4575 ))
4576 }
4577 };
4578
4579 let mut messages_to_report = Vec::new();
4580 let (new_tree, to_stop) = {
4581 let mut rebase = local.lsp_tree.rebase();
4582 let buffers = buffer_store
4583 .read(cx)
4584 .buffers()
4585 .filter_map(|buffer| {
4586 let raw_buffer = buffer.read(cx);
4587 if !local
4588 .registered_buffers
4589 .contains_key(&raw_buffer.remote_id())
4590 {
4591 return None;
4592 }
4593 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4594 let language = raw_buffer.language().cloned()?;
4595 Some((file, language, raw_buffer.remote_id()))
4596 })
4597 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4598 for (file, language, buffer_id) in buffers {
4599 let worktree_id = file.worktree_id(cx);
4600 let Some(worktree) = local
4601 .worktree_store
4602 .read(cx)
4603 .worktree_for_id(worktree_id, cx)
4604 else {
4605 continue;
4606 };
4607
4608 if let Some((_, apply)) = local.reuse_existing_language_server(
4609 rebase.server_tree(),
4610 &worktree,
4611 &language.name(),
4612 cx,
4613 ) {
4614 (apply)(rebase.server_tree());
4615 } else if let Some(lsp_delegate) = adapters
4616 .entry(worktree_id)
4617 .or_insert_with(|| get_adapter(worktree_id, cx))
4618 .clone()
4619 {
4620 let delegate =
4621 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4622 let path = file
4623 .path()
4624 .parent()
4625 .map(Arc::from)
4626 .unwrap_or_else(|| file.path().clone());
4627 let worktree_path = ProjectPath { worktree_id, path };
4628 let abs_path = file.abs_path(cx);
4629 let nodes = rebase
4630 .walk(
4631 worktree_path,
4632 language.name(),
4633 language.manifest(),
4634 delegate.clone(),
4635 cx,
4636 )
4637 .collect::<Vec<_>>();
4638 for node in nodes {
4639 let server_id = node.server_id_or_init(|disposition| {
4640 let path = &disposition.path;
4641 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4642 let key = LanguageServerSeed {
4643 worktree_id,
4644 name: disposition.server_name.clone(),
4645 settings: disposition.settings.clone(),
4646 toolchain: local.toolchain_store.read(cx).active_toolchain(
4647 path.worktree_id,
4648 &path.path,
4649 language.name(),
4650 ),
4651 };
4652 local.language_server_ids.remove(&key);
4653
4654 let server_id = local.get_or_insert_language_server(
4655 &worktree,
4656 lsp_delegate.clone(),
4657 disposition,
4658 &language.name(),
4659 cx,
4660 );
4661 if let Some(state) = local.language_servers.get(&server_id)
4662 && let Ok(uri) = uri
4663 {
4664 state.add_workspace_folder(uri);
4665 };
4666 server_id
4667 });
4668
4669 if let Some(language_server_id) = server_id {
4670 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4671 language_server_id,
4672 name: node.name(),
4673 message:
4674 proto::update_language_server::Variant::RegisteredForBuffer(
4675 proto::RegisteredForBuffer {
4676 buffer_abs_path: abs_path
4677 .to_string_lossy()
4678 .into_owned(),
4679 buffer_id: buffer_id.to_proto(),
4680 },
4681 ),
4682 });
4683 }
4684 }
4685 } else {
4686 continue;
4687 }
4688 }
4689 rebase.finish()
4690 };
4691 for message in messages_to_report {
4692 cx.emit(message);
4693 }
4694 local.lsp_tree = new_tree;
4695 for (id, _) in to_stop {
4696 self.stop_local_language_server(id, cx).detach();
4697 }
4698 }
4699
4700 pub fn apply_code_action(
4701 &self,
4702 buffer_handle: Entity<Buffer>,
4703 mut action: CodeAction,
4704 push_to_history: bool,
4705 cx: &mut Context<Self>,
4706 ) -> Task<Result<ProjectTransaction>> {
4707 if let Some((upstream_client, project_id)) = self.upstream_client() {
4708 let request = proto::ApplyCodeAction {
4709 project_id,
4710 buffer_id: buffer_handle.read(cx).remote_id().into(),
4711 action: Some(Self::serialize_code_action(&action)),
4712 };
4713 let buffer_store = self.buffer_store();
4714 cx.spawn(async move |_, cx| {
4715 let response = upstream_client
4716 .request(request)
4717 .await?
4718 .transaction
4719 .context("missing transaction")?;
4720
4721 buffer_store
4722 .update(cx, |buffer_store, cx| {
4723 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4724 })?
4725 .await
4726 })
4727 } else if self.mode.is_local() {
4728 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4729 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4730 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4731 }) else {
4732 return Task::ready(Ok(ProjectTransaction::default()));
4733 };
4734 cx.spawn(async move |this, cx| {
4735 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4736 .await
4737 .context("resolving a code action")?;
4738 if let Some(edit) = action.lsp_action.edit()
4739 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4740 return LocalLspStore::deserialize_workspace_edit(
4741 this.upgrade().context("no app present")?,
4742 edit.clone(),
4743 push_to_history,
4744
4745 lang_server.clone(),
4746 cx,
4747 )
4748 .await;
4749 }
4750
4751 if let Some(command) = action.lsp_action.command() {
4752 let server_capabilities = lang_server.capabilities();
4753 let available_commands = server_capabilities
4754 .execute_command_provider
4755 .as_ref()
4756 .map(|options| options.commands.as_slice())
4757 .unwrap_or_default();
4758 if available_commands.contains(&command.command) {
4759 this.update(cx, |this, _| {
4760 this.as_local_mut()
4761 .unwrap()
4762 .last_workspace_edits_by_language_server
4763 .remove(&lang_server.server_id());
4764 })?;
4765
4766 let _result = lang_server
4767 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4768 command: command.command.clone(),
4769 arguments: command.arguments.clone().unwrap_or_default(),
4770 ..lsp::ExecuteCommandParams::default()
4771 })
4772 .await.into_response()
4773 .context("execute command")?;
4774
4775 return this.update(cx, |this, _| {
4776 this.as_local_mut()
4777 .unwrap()
4778 .last_workspace_edits_by_language_server
4779 .remove(&lang_server.server_id())
4780 .unwrap_or_default()
4781 });
4782 } else {
4783 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4784 }
4785 }
4786
4787 Ok(ProjectTransaction::default())
4788 })
4789 } else {
4790 Task::ready(Err(anyhow!("no upstream client and not local")))
4791 }
4792 }
4793
4794 pub fn apply_code_action_kind(
4795 &mut self,
4796 buffers: HashSet<Entity<Buffer>>,
4797 kind: CodeActionKind,
4798 push_to_history: bool,
4799 cx: &mut Context<Self>,
4800 ) -> Task<anyhow::Result<ProjectTransaction>> {
4801 if self.as_local().is_some() {
4802 cx.spawn(async move |lsp_store, cx| {
4803 let buffers = buffers.into_iter().collect::<Vec<_>>();
4804 let result = LocalLspStore::execute_code_action_kind_locally(
4805 lsp_store.clone(),
4806 buffers,
4807 kind,
4808 push_to_history,
4809 cx,
4810 )
4811 .await;
4812 lsp_store.update(cx, |lsp_store, _| {
4813 lsp_store.update_last_formatting_failure(&result);
4814 })?;
4815 result
4816 })
4817 } else if let Some((client, project_id)) = self.upstream_client() {
4818 let buffer_store = self.buffer_store();
4819 cx.spawn(async move |lsp_store, cx| {
4820 let result = client
4821 .request(proto::ApplyCodeActionKind {
4822 project_id,
4823 kind: kind.as_str().to_owned(),
4824 buffer_ids: buffers
4825 .iter()
4826 .map(|buffer| {
4827 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4828 })
4829 .collect::<Result<_>>()?,
4830 })
4831 .await
4832 .and_then(|result| result.transaction.context("missing transaction"));
4833 lsp_store.update(cx, |lsp_store, _| {
4834 lsp_store.update_last_formatting_failure(&result);
4835 })?;
4836
4837 let transaction_response = result?;
4838 buffer_store
4839 .update(cx, |buffer_store, cx| {
4840 buffer_store.deserialize_project_transaction(
4841 transaction_response,
4842 push_to_history,
4843 cx,
4844 )
4845 })?
4846 .await
4847 })
4848 } else {
4849 Task::ready(Ok(ProjectTransaction::default()))
4850 }
4851 }
4852
4853 pub fn resolved_hint(
4854 &mut self,
4855 buffer_id: BufferId,
4856 id: InlayId,
4857 cx: &mut Context<Self>,
4858 ) -> Option<ResolvedHint> {
4859 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4860
4861 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4862 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4863 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4864 let (server_id, resolve_data) = match &hint.resolve_state {
4865 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4866 ResolveState::Resolving => {
4867 return Some(ResolvedHint::Resolving(
4868 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4869 ));
4870 }
4871 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4872 };
4873
4874 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4875 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4876 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4877 id,
4878 cx.spawn(async move |lsp_store, cx| {
4879 let resolved_hint = resolve_task.await;
4880 lsp_store
4881 .update(cx, |lsp_store, _| {
4882 if let Some(old_inlay_hint) = lsp_store
4883 .lsp_data
4884 .get_mut(&buffer_id)
4885 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4886 {
4887 match resolved_hint {
4888 Ok(resolved_hint) => {
4889 *old_inlay_hint = resolved_hint;
4890 }
4891 Err(e) => {
4892 old_inlay_hint.resolve_state =
4893 ResolveState::CanResolve(server_id, resolve_data);
4894 log::error!("Inlay hint resolve failed: {e:#}");
4895 }
4896 }
4897 }
4898 })
4899 .ok();
4900 })
4901 .shared(),
4902 );
4903 debug_assert!(
4904 previous_task.is_none(),
4905 "Did not change hint's resolve state after spawning its resolve"
4906 );
4907 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4908 None
4909 }
4910
4911 fn resolve_inlay_hint(
4912 &self,
4913 mut hint: InlayHint,
4914 buffer: Entity<Buffer>,
4915 server_id: LanguageServerId,
4916 cx: &mut Context<Self>,
4917 ) -> Task<anyhow::Result<InlayHint>> {
4918 if let Some((upstream_client, project_id)) = self.upstream_client() {
4919 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4920 {
4921 hint.resolve_state = ResolveState::Resolved;
4922 return Task::ready(Ok(hint));
4923 }
4924 let request = proto::ResolveInlayHint {
4925 project_id,
4926 buffer_id: buffer.read(cx).remote_id().into(),
4927 language_server_id: server_id.0 as u64,
4928 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4929 };
4930 cx.background_spawn(async move {
4931 let response = upstream_client
4932 .request(request)
4933 .await
4934 .context("inlay hints proto request")?;
4935 match response.hint {
4936 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4937 .context("inlay hints proto resolve response conversion"),
4938 None => Ok(hint),
4939 }
4940 })
4941 } else {
4942 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4943 self.language_server_for_local_buffer(buffer, server_id, cx)
4944 .map(|(_, server)| server.clone())
4945 }) else {
4946 return Task::ready(Ok(hint));
4947 };
4948 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4949 return Task::ready(Ok(hint));
4950 }
4951 let buffer_snapshot = buffer.read(cx).snapshot();
4952 cx.spawn(async move |_, cx| {
4953 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4954 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4955 );
4956 let resolved_hint = resolve_task
4957 .await
4958 .into_response()
4959 .context("inlay hint resolve LSP request")?;
4960 let resolved_hint = InlayHints::lsp_to_project_hint(
4961 resolved_hint,
4962 &buffer,
4963 server_id,
4964 ResolveState::Resolved,
4965 false,
4966 cx,
4967 )
4968 .await?;
4969 Ok(resolved_hint)
4970 })
4971 }
4972 }
4973
4974 pub fn resolve_color_presentation(
4975 &mut self,
4976 mut color: DocumentColor,
4977 buffer: Entity<Buffer>,
4978 server_id: LanguageServerId,
4979 cx: &mut Context<Self>,
4980 ) -> Task<Result<DocumentColor>> {
4981 if color.resolved {
4982 return Task::ready(Ok(color));
4983 }
4984
4985 if let Some((upstream_client, project_id)) = self.upstream_client() {
4986 let start = color.lsp_range.start;
4987 let end = color.lsp_range.end;
4988 let request = proto::GetColorPresentation {
4989 project_id,
4990 server_id: server_id.to_proto(),
4991 buffer_id: buffer.read(cx).remote_id().into(),
4992 color: Some(proto::ColorInformation {
4993 red: color.color.red,
4994 green: color.color.green,
4995 blue: color.color.blue,
4996 alpha: color.color.alpha,
4997 lsp_range_start: Some(proto::PointUtf16 {
4998 row: start.line,
4999 column: start.character,
5000 }),
5001 lsp_range_end: Some(proto::PointUtf16 {
5002 row: end.line,
5003 column: end.character,
5004 }),
5005 }),
5006 };
5007 cx.background_spawn(async move {
5008 let response = upstream_client
5009 .request(request)
5010 .await
5011 .context("color presentation proto request")?;
5012 color.resolved = true;
5013 color.color_presentations = response
5014 .presentations
5015 .into_iter()
5016 .map(|presentation| ColorPresentation {
5017 label: SharedString::from(presentation.label),
5018 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5019 additional_text_edits: presentation
5020 .additional_text_edits
5021 .into_iter()
5022 .filter_map(deserialize_lsp_edit)
5023 .collect(),
5024 })
5025 .collect();
5026 Ok(color)
5027 })
5028 } else {
5029 let path = match buffer
5030 .update(cx, |buffer, cx| {
5031 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5032 })
5033 .context("buffer with the missing path")
5034 {
5035 Ok(path) => path,
5036 Err(e) => return Task::ready(Err(e)),
5037 };
5038 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5039 self.language_server_for_local_buffer(buffer, server_id, cx)
5040 .map(|(_, server)| server.clone())
5041 }) else {
5042 return Task::ready(Ok(color));
5043 };
5044 cx.background_spawn(async move {
5045 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5046 lsp::ColorPresentationParams {
5047 text_document: make_text_document_identifier(&path)?,
5048 color: color.color,
5049 range: color.lsp_range,
5050 work_done_progress_params: Default::default(),
5051 partial_result_params: Default::default(),
5052 },
5053 );
5054 color.color_presentations = resolve_task
5055 .await
5056 .into_response()
5057 .context("color presentation resolve LSP request")?
5058 .into_iter()
5059 .map(|presentation| ColorPresentation {
5060 label: SharedString::from(presentation.label),
5061 text_edit: presentation.text_edit,
5062 additional_text_edits: presentation
5063 .additional_text_edits
5064 .unwrap_or_default(),
5065 })
5066 .collect();
5067 color.resolved = true;
5068 Ok(color)
5069 })
5070 }
5071 }
5072
5073 pub(crate) fn linked_edits(
5074 &mut self,
5075 buffer: &Entity<Buffer>,
5076 position: Anchor,
5077 cx: &mut Context<Self>,
5078 ) -> Task<Result<Vec<Range<Anchor>>>> {
5079 let snapshot = buffer.read(cx).snapshot();
5080 let scope = snapshot.language_scope_at(position);
5081 let Some(server_id) = self
5082 .as_local()
5083 .and_then(|local| {
5084 buffer.update(cx, |buffer, cx| {
5085 local
5086 .language_servers_for_buffer(buffer, cx)
5087 .filter(|(_, server)| {
5088 LinkedEditingRange::check_server_capabilities(server.capabilities())
5089 })
5090 .filter(|(adapter, _)| {
5091 scope
5092 .as_ref()
5093 .map(|scope| scope.language_allowed(&adapter.name))
5094 .unwrap_or(true)
5095 })
5096 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5097 .next()
5098 })
5099 })
5100 .or_else(|| {
5101 self.upstream_client()
5102 .is_some()
5103 .then_some(LanguageServerToQuery::FirstCapable)
5104 })
5105 .filter(|_| {
5106 maybe!({
5107 let language = buffer.read(cx).language_at(position)?;
5108 Some(
5109 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5110 .linked_edits,
5111 )
5112 }) == Some(true)
5113 })
5114 else {
5115 return Task::ready(Ok(Vec::new()));
5116 };
5117
5118 self.request_lsp(
5119 buffer.clone(),
5120 server_id,
5121 LinkedEditingRange { position },
5122 cx,
5123 )
5124 }
5125
5126 fn apply_on_type_formatting(
5127 &mut self,
5128 buffer: Entity<Buffer>,
5129 position: Anchor,
5130 trigger: String,
5131 cx: &mut Context<Self>,
5132 ) -> Task<Result<Option<Transaction>>> {
5133 if let Some((client, project_id)) = self.upstream_client() {
5134 if !self.check_if_capable_for_proto_request(
5135 &buffer,
5136 |capabilities| {
5137 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5138 },
5139 cx,
5140 ) {
5141 return Task::ready(Ok(None));
5142 }
5143 let request = proto::OnTypeFormatting {
5144 project_id,
5145 buffer_id: buffer.read(cx).remote_id().into(),
5146 position: Some(serialize_anchor(&position)),
5147 trigger,
5148 version: serialize_version(&buffer.read(cx).version()),
5149 };
5150 cx.background_spawn(async move {
5151 client
5152 .request(request)
5153 .await?
5154 .transaction
5155 .map(language::proto::deserialize_transaction)
5156 .transpose()
5157 })
5158 } else if let Some(local) = self.as_local_mut() {
5159 let buffer_id = buffer.read(cx).remote_id();
5160 local.buffers_being_formatted.insert(buffer_id);
5161 cx.spawn(async move |this, cx| {
5162 let _cleanup = defer({
5163 let this = this.clone();
5164 let mut cx = cx.clone();
5165 move || {
5166 this.update(&mut cx, |this, _| {
5167 if let Some(local) = this.as_local_mut() {
5168 local.buffers_being_formatted.remove(&buffer_id);
5169 }
5170 })
5171 .ok();
5172 }
5173 });
5174
5175 buffer
5176 .update(cx, |buffer, _| {
5177 buffer.wait_for_edits(Some(position.timestamp))
5178 })?
5179 .await?;
5180 this.update(cx, |this, cx| {
5181 let position = position.to_point_utf16(buffer.read(cx));
5182 this.on_type_format(buffer, position, trigger, false, cx)
5183 })?
5184 .await
5185 })
5186 } else {
5187 Task::ready(Err(anyhow!("No upstream client or local language server")))
5188 }
5189 }
5190
5191 pub fn on_type_format<T: ToPointUtf16>(
5192 &mut self,
5193 buffer: Entity<Buffer>,
5194 position: T,
5195 trigger: String,
5196 push_to_history: bool,
5197 cx: &mut Context<Self>,
5198 ) -> Task<Result<Option<Transaction>>> {
5199 let position = position.to_point_utf16(buffer.read(cx));
5200 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5201 }
5202
5203 fn on_type_format_impl(
5204 &mut self,
5205 buffer: Entity<Buffer>,
5206 position: PointUtf16,
5207 trigger: String,
5208 push_to_history: bool,
5209 cx: &mut Context<Self>,
5210 ) -> Task<Result<Option<Transaction>>> {
5211 let options = buffer.update(cx, |buffer, cx| {
5212 lsp_command::lsp_formatting_options(
5213 language_settings(
5214 buffer.language_at(position).map(|l| l.name()),
5215 buffer.file(),
5216 cx,
5217 )
5218 .as_ref(),
5219 )
5220 });
5221
5222 cx.spawn(async move |this, cx| {
5223 if let Some(waiter) =
5224 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5225 {
5226 waiter.await?;
5227 }
5228 cx.update(|cx| {
5229 this.update(cx, |this, cx| {
5230 this.request_lsp(
5231 buffer.clone(),
5232 LanguageServerToQuery::FirstCapable,
5233 OnTypeFormatting {
5234 position,
5235 trigger,
5236 options,
5237 push_to_history,
5238 },
5239 cx,
5240 )
5241 })
5242 })??
5243 .await
5244 })
5245 }
5246
5247 pub fn definitions(
5248 &mut self,
5249 buffer: &Entity<Buffer>,
5250 position: PointUtf16,
5251 cx: &mut Context<Self>,
5252 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5253 if let Some((upstream_client, project_id)) = self.upstream_client() {
5254 let request = GetDefinitions { position };
5255 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5256 return Task::ready(Ok(None));
5257 }
5258 let request_task = upstream_client.request_lsp(
5259 project_id,
5260 None,
5261 LSP_REQUEST_TIMEOUT,
5262 cx.background_executor().clone(),
5263 request.to_proto(project_id, buffer.read(cx)),
5264 );
5265 let buffer = buffer.clone();
5266 cx.spawn(async move |weak_project, cx| {
5267 let Some(project) = weak_project.upgrade() else {
5268 return Ok(None);
5269 };
5270 let Some(responses) = request_task.await? else {
5271 return Ok(None);
5272 };
5273 let actions = join_all(responses.payload.into_iter().map(|response| {
5274 GetDefinitions { position }.response_from_proto(
5275 response.response,
5276 project.clone(),
5277 buffer.clone(),
5278 cx.clone(),
5279 )
5280 }))
5281 .await;
5282
5283 Ok(Some(
5284 actions
5285 .into_iter()
5286 .collect::<Result<Vec<Vec<_>>>>()?
5287 .into_iter()
5288 .flatten()
5289 .dedup()
5290 .collect(),
5291 ))
5292 })
5293 } else {
5294 let definitions_task = self.request_multiple_lsp_locally(
5295 buffer,
5296 Some(position),
5297 GetDefinitions { position },
5298 cx,
5299 );
5300 cx.background_spawn(async move {
5301 Ok(Some(
5302 definitions_task
5303 .await
5304 .into_iter()
5305 .flat_map(|(_, definitions)| definitions)
5306 .dedup()
5307 .collect(),
5308 ))
5309 })
5310 }
5311 }
5312
5313 pub fn declarations(
5314 &mut self,
5315 buffer: &Entity<Buffer>,
5316 position: PointUtf16,
5317 cx: &mut Context<Self>,
5318 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5319 if let Some((upstream_client, project_id)) = self.upstream_client() {
5320 let request = GetDeclarations { position };
5321 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5322 return Task::ready(Ok(None));
5323 }
5324 let request_task = upstream_client.request_lsp(
5325 project_id,
5326 None,
5327 LSP_REQUEST_TIMEOUT,
5328 cx.background_executor().clone(),
5329 request.to_proto(project_id, buffer.read(cx)),
5330 );
5331 let buffer = buffer.clone();
5332 cx.spawn(async move |weak_project, cx| {
5333 let Some(project) = weak_project.upgrade() else {
5334 return Ok(None);
5335 };
5336 let Some(responses) = request_task.await? else {
5337 return Ok(None);
5338 };
5339 let actions = join_all(responses.payload.into_iter().map(|response| {
5340 GetDeclarations { position }.response_from_proto(
5341 response.response,
5342 project.clone(),
5343 buffer.clone(),
5344 cx.clone(),
5345 )
5346 }))
5347 .await;
5348
5349 Ok(Some(
5350 actions
5351 .into_iter()
5352 .collect::<Result<Vec<Vec<_>>>>()?
5353 .into_iter()
5354 .flatten()
5355 .dedup()
5356 .collect(),
5357 ))
5358 })
5359 } else {
5360 let declarations_task = self.request_multiple_lsp_locally(
5361 buffer,
5362 Some(position),
5363 GetDeclarations { position },
5364 cx,
5365 );
5366 cx.background_spawn(async move {
5367 Ok(Some(
5368 declarations_task
5369 .await
5370 .into_iter()
5371 .flat_map(|(_, declarations)| declarations)
5372 .dedup()
5373 .collect(),
5374 ))
5375 })
5376 }
5377 }
5378
5379 pub fn type_definitions(
5380 &mut self,
5381 buffer: &Entity<Buffer>,
5382 position: PointUtf16,
5383 cx: &mut Context<Self>,
5384 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5385 if let Some((upstream_client, project_id)) = self.upstream_client() {
5386 let request = GetTypeDefinitions { position };
5387 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5388 return Task::ready(Ok(None));
5389 }
5390 let request_task = upstream_client.request_lsp(
5391 project_id,
5392 None,
5393 LSP_REQUEST_TIMEOUT,
5394 cx.background_executor().clone(),
5395 request.to_proto(project_id, buffer.read(cx)),
5396 );
5397 let buffer = buffer.clone();
5398 cx.spawn(async move |weak_project, cx| {
5399 let Some(project) = weak_project.upgrade() else {
5400 return Ok(None);
5401 };
5402 let Some(responses) = request_task.await? else {
5403 return Ok(None);
5404 };
5405 let actions = join_all(responses.payload.into_iter().map(|response| {
5406 GetTypeDefinitions { position }.response_from_proto(
5407 response.response,
5408 project.clone(),
5409 buffer.clone(),
5410 cx.clone(),
5411 )
5412 }))
5413 .await;
5414
5415 Ok(Some(
5416 actions
5417 .into_iter()
5418 .collect::<Result<Vec<Vec<_>>>>()?
5419 .into_iter()
5420 .flatten()
5421 .dedup()
5422 .collect(),
5423 ))
5424 })
5425 } else {
5426 let type_definitions_task = self.request_multiple_lsp_locally(
5427 buffer,
5428 Some(position),
5429 GetTypeDefinitions { position },
5430 cx,
5431 );
5432 cx.background_spawn(async move {
5433 Ok(Some(
5434 type_definitions_task
5435 .await
5436 .into_iter()
5437 .flat_map(|(_, type_definitions)| type_definitions)
5438 .dedup()
5439 .collect(),
5440 ))
5441 })
5442 }
5443 }
5444
5445 pub fn implementations(
5446 &mut self,
5447 buffer: &Entity<Buffer>,
5448 position: PointUtf16,
5449 cx: &mut Context<Self>,
5450 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5451 if let Some((upstream_client, project_id)) = self.upstream_client() {
5452 let request = GetImplementations { position };
5453 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5454 return Task::ready(Ok(None));
5455 }
5456 let request_task = upstream_client.request_lsp(
5457 project_id,
5458 None,
5459 LSP_REQUEST_TIMEOUT,
5460 cx.background_executor().clone(),
5461 request.to_proto(project_id, buffer.read(cx)),
5462 );
5463 let buffer = buffer.clone();
5464 cx.spawn(async move |weak_project, cx| {
5465 let Some(project) = weak_project.upgrade() else {
5466 return Ok(None);
5467 };
5468 let Some(responses) = request_task.await? else {
5469 return Ok(None);
5470 };
5471 let actions = join_all(responses.payload.into_iter().map(|response| {
5472 GetImplementations { position }.response_from_proto(
5473 response.response,
5474 project.clone(),
5475 buffer.clone(),
5476 cx.clone(),
5477 )
5478 }))
5479 .await;
5480
5481 Ok(Some(
5482 actions
5483 .into_iter()
5484 .collect::<Result<Vec<Vec<_>>>>()?
5485 .into_iter()
5486 .flatten()
5487 .dedup()
5488 .collect(),
5489 ))
5490 })
5491 } else {
5492 let implementations_task = self.request_multiple_lsp_locally(
5493 buffer,
5494 Some(position),
5495 GetImplementations { position },
5496 cx,
5497 );
5498 cx.background_spawn(async move {
5499 Ok(Some(
5500 implementations_task
5501 .await
5502 .into_iter()
5503 .flat_map(|(_, implementations)| implementations)
5504 .dedup()
5505 .collect(),
5506 ))
5507 })
5508 }
5509 }
5510
5511 pub fn references(
5512 &mut self,
5513 buffer: &Entity<Buffer>,
5514 position: PointUtf16,
5515 cx: &mut Context<Self>,
5516 ) -> Task<Result<Option<Vec<Location>>>> {
5517 if let Some((upstream_client, project_id)) = self.upstream_client() {
5518 let request = GetReferences { position };
5519 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5520 return Task::ready(Ok(None));
5521 }
5522
5523 let request_task = upstream_client.request_lsp(
5524 project_id,
5525 None,
5526 LSP_REQUEST_TIMEOUT,
5527 cx.background_executor().clone(),
5528 request.to_proto(project_id, buffer.read(cx)),
5529 );
5530 let buffer = buffer.clone();
5531 cx.spawn(async move |weak_project, cx| {
5532 let Some(project) = weak_project.upgrade() else {
5533 return Ok(None);
5534 };
5535 let Some(responses) = request_task.await? else {
5536 return Ok(None);
5537 };
5538
5539 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5540 GetReferences { position }.response_from_proto(
5541 lsp_response.response,
5542 project.clone(),
5543 buffer.clone(),
5544 cx.clone(),
5545 )
5546 }))
5547 .await
5548 .into_iter()
5549 .collect::<Result<Vec<Vec<_>>>>()?
5550 .into_iter()
5551 .flatten()
5552 .dedup()
5553 .collect();
5554 Ok(Some(locations))
5555 })
5556 } else {
5557 let references_task = self.request_multiple_lsp_locally(
5558 buffer,
5559 Some(position),
5560 GetReferences { position },
5561 cx,
5562 );
5563 cx.background_spawn(async move {
5564 Ok(Some(
5565 references_task
5566 .await
5567 .into_iter()
5568 .flat_map(|(_, references)| references)
5569 .dedup()
5570 .collect(),
5571 ))
5572 })
5573 }
5574 }
5575
5576 pub fn code_actions(
5577 &mut self,
5578 buffer: &Entity<Buffer>,
5579 range: Range<Anchor>,
5580 kinds: Option<Vec<CodeActionKind>>,
5581 cx: &mut Context<Self>,
5582 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5583 if let Some((upstream_client, project_id)) = self.upstream_client() {
5584 let request = GetCodeActions {
5585 range: range.clone(),
5586 kinds: kinds.clone(),
5587 };
5588 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5589 return Task::ready(Ok(None));
5590 }
5591 let request_task = upstream_client.request_lsp(
5592 project_id,
5593 None,
5594 LSP_REQUEST_TIMEOUT,
5595 cx.background_executor().clone(),
5596 request.to_proto(project_id, buffer.read(cx)),
5597 );
5598 let buffer = buffer.clone();
5599 cx.spawn(async move |weak_project, cx| {
5600 let Some(project) = weak_project.upgrade() else {
5601 return Ok(None);
5602 };
5603 let Some(responses) = request_task.await? else {
5604 return Ok(None);
5605 };
5606 let actions = join_all(responses.payload.into_iter().map(|response| {
5607 GetCodeActions {
5608 range: range.clone(),
5609 kinds: kinds.clone(),
5610 }
5611 .response_from_proto(
5612 response.response,
5613 project.clone(),
5614 buffer.clone(),
5615 cx.clone(),
5616 )
5617 }))
5618 .await;
5619
5620 Ok(Some(
5621 actions
5622 .into_iter()
5623 .collect::<Result<Vec<Vec<_>>>>()?
5624 .into_iter()
5625 .flatten()
5626 .collect(),
5627 ))
5628 })
5629 } else {
5630 let all_actions_task = self.request_multiple_lsp_locally(
5631 buffer,
5632 Some(range.start),
5633 GetCodeActions { range, kinds },
5634 cx,
5635 );
5636 cx.background_spawn(async move {
5637 Ok(Some(
5638 all_actions_task
5639 .await
5640 .into_iter()
5641 .flat_map(|(_, actions)| actions)
5642 .collect(),
5643 ))
5644 })
5645 }
5646 }
5647
5648 pub fn code_lens_actions(
5649 &mut self,
5650 buffer: &Entity<Buffer>,
5651 cx: &mut Context<Self>,
5652 ) -> CodeLensTask {
5653 let version_queried_for = buffer.read(cx).version();
5654 let buffer_id = buffer.read(cx).remote_id();
5655 let existing_servers = self.as_local().map(|local| {
5656 local
5657 .buffers_opened_in_servers
5658 .get(&buffer_id)
5659 .cloned()
5660 .unwrap_or_default()
5661 });
5662
5663 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5664 if let Some(cached_lens) = &lsp_data.code_lens {
5665 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5666 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5667 existing_servers != cached_lens.lens.keys().copied().collect()
5668 });
5669 if !has_different_servers {
5670 return Task::ready(Ok(Some(
5671 cached_lens.lens.values().flatten().cloned().collect(),
5672 )))
5673 .shared();
5674 }
5675 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5676 if !version_queried_for.changed_since(updating_for) {
5677 return running_update.clone();
5678 }
5679 }
5680 }
5681 }
5682
5683 let lens_lsp_data = self
5684 .latest_lsp_data(buffer, cx)
5685 .code_lens
5686 .get_or_insert_default();
5687 let buffer = buffer.clone();
5688 let query_version_queried_for = version_queried_for.clone();
5689 let new_task = cx
5690 .spawn(async move |lsp_store, cx| {
5691 cx.background_executor()
5692 .timer(Duration::from_millis(30))
5693 .await;
5694 let fetched_lens = lsp_store
5695 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5696 .map_err(Arc::new)?
5697 .await
5698 .context("fetching code lens")
5699 .map_err(Arc::new);
5700 let fetched_lens = match fetched_lens {
5701 Ok(fetched_lens) => fetched_lens,
5702 Err(e) => {
5703 lsp_store
5704 .update(cx, |lsp_store, _| {
5705 if let Some(lens_lsp_data) = lsp_store
5706 .lsp_data
5707 .get_mut(&buffer_id)
5708 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5709 {
5710 lens_lsp_data.update = None;
5711 }
5712 })
5713 .ok();
5714 return Err(e);
5715 }
5716 };
5717
5718 lsp_store
5719 .update(cx, |lsp_store, _| {
5720 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5721 let code_lens = lsp_data.code_lens.as_mut()?;
5722 if let Some(fetched_lens) = fetched_lens {
5723 if lsp_data.buffer_version == query_version_queried_for {
5724 code_lens.lens.extend(fetched_lens);
5725 } else if !lsp_data
5726 .buffer_version
5727 .changed_since(&query_version_queried_for)
5728 {
5729 lsp_data.buffer_version = query_version_queried_for;
5730 code_lens.lens = fetched_lens;
5731 }
5732 }
5733 code_lens.update = None;
5734 Some(code_lens.lens.values().flatten().cloned().collect())
5735 })
5736 .map_err(Arc::new)
5737 })
5738 .shared();
5739 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5740 new_task
5741 }
5742
5743 fn fetch_code_lens(
5744 &mut self,
5745 buffer: &Entity<Buffer>,
5746 cx: &mut Context<Self>,
5747 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5748 if let Some((upstream_client, project_id)) = self.upstream_client() {
5749 let request = GetCodeLens;
5750 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5751 return Task::ready(Ok(None));
5752 }
5753 let request_task = upstream_client.request_lsp(
5754 project_id,
5755 None,
5756 LSP_REQUEST_TIMEOUT,
5757 cx.background_executor().clone(),
5758 request.to_proto(project_id, buffer.read(cx)),
5759 );
5760 let buffer = buffer.clone();
5761 cx.spawn(async move |weak_lsp_store, cx| {
5762 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5763 return Ok(None);
5764 };
5765 let Some(responses) = request_task.await? else {
5766 return Ok(None);
5767 };
5768
5769 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5770 let lsp_store = lsp_store.clone();
5771 let buffer = buffer.clone();
5772 let cx = cx.clone();
5773 async move {
5774 (
5775 LanguageServerId::from_proto(response.server_id),
5776 GetCodeLens
5777 .response_from_proto(response.response, lsp_store, buffer, cx)
5778 .await,
5779 )
5780 }
5781 }))
5782 .await;
5783
5784 let mut has_errors = false;
5785 let code_lens_actions = code_lens_actions
5786 .into_iter()
5787 .filter_map(|(server_id, code_lens)| match code_lens {
5788 Ok(code_lens) => Some((server_id, code_lens)),
5789 Err(e) => {
5790 has_errors = true;
5791 log::error!("{e:#}");
5792 None
5793 }
5794 })
5795 .collect::<HashMap<_, _>>();
5796 anyhow::ensure!(
5797 !has_errors || !code_lens_actions.is_empty(),
5798 "Failed to fetch code lens"
5799 );
5800 Ok(Some(code_lens_actions))
5801 })
5802 } else {
5803 let code_lens_actions_task =
5804 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5805 cx.background_spawn(async move {
5806 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5807 })
5808 }
5809 }
5810
5811 #[inline(never)]
5812 pub fn completions(
5813 &self,
5814 buffer: &Entity<Buffer>,
5815 position: PointUtf16,
5816 context: CompletionContext,
5817 cx: &mut Context<Self>,
5818 ) -> Task<Result<Vec<CompletionResponse>>> {
5819 let language_registry = self.languages.clone();
5820
5821 if let Some((upstream_client, project_id)) = self.upstream_client() {
5822 let request = GetCompletions { position, context };
5823 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5824 return Task::ready(Ok(Vec::new()));
5825 }
5826 let task = self.send_lsp_proto_request(
5827 buffer.clone(),
5828 upstream_client,
5829 project_id,
5830 request,
5831 cx,
5832 );
5833 let language = buffer.read(cx).language().cloned();
5834
5835 // In the future, we should provide project guests with the names of LSP adapters,
5836 // so that they can use the correct LSP adapter when computing labels. For now,
5837 // guests just use the first LSP adapter associated with the buffer's language.
5838 let lsp_adapter = language.as_ref().and_then(|language| {
5839 language_registry
5840 .lsp_adapters(&language.name())
5841 .first()
5842 .cloned()
5843 });
5844
5845 cx.foreground_executor().spawn(async move {
5846 let completion_response = task.await?;
5847 let completions = populate_labels_for_completions(
5848 completion_response.completions,
5849 language,
5850 lsp_adapter,
5851 )
5852 .await;
5853 Ok(vec![CompletionResponse {
5854 completions,
5855 display_options: CompletionDisplayOptions::default(),
5856 is_incomplete: completion_response.is_incomplete,
5857 }])
5858 })
5859 } else if let Some(local) = self.as_local() {
5860 let snapshot = buffer.read(cx).snapshot();
5861 let offset = position.to_offset(&snapshot);
5862 let scope = snapshot.language_scope_at(offset);
5863 let language = snapshot.language().cloned();
5864 let completion_settings = language_settings(
5865 language.as_ref().map(|language| language.name()),
5866 buffer.read(cx).file(),
5867 cx,
5868 )
5869 .completions
5870 .clone();
5871 if !completion_settings.lsp {
5872 return Task::ready(Ok(Vec::new()));
5873 }
5874
5875 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5876 local
5877 .language_servers_for_buffer(buffer, cx)
5878 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5879 .filter(|(adapter, _)| {
5880 scope
5881 .as_ref()
5882 .map(|scope| scope.language_allowed(&adapter.name))
5883 .unwrap_or(true)
5884 })
5885 .map(|(_, server)| server.server_id())
5886 .collect()
5887 });
5888
5889 let buffer = buffer.clone();
5890 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5891 let lsp_timeout = if lsp_timeout > 0 {
5892 Some(Duration::from_millis(lsp_timeout))
5893 } else {
5894 None
5895 };
5896 cx.spawn(async move |this, cx| {
5897 let mut tasks = Vec::with_capacity(server_ids.len());
5898 this.update(cx, |lsp_store, cx| {
5899 for server_id in server_ids {
5900 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5901 let lsp_timeout = lsp_timeout
5902 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5903 let mut timeout = cx.background_spawn(async move {
5904 match lsp_timeout {
5905 Some(lsp_timeout) => {
5906 lsp_timeout.await;
5907 true
5908 },
5909 None => false,
5910 }
5911 }).fuse();
5912 let mut lsp_request = lsp_store.request_lsp(
5913 buffer.clone(),
5914 LanguageServerToQuery::Other(server_id),
5915 GetCompletions {
5916 position,
5917 context: context.clone(),
5918 },
5919 cx,
5920 ).fuse();
5921 let new_task = cx.background_spawn(async move {
5922 select_biased! {
5923 response = lsp_request => anyhow::Ok(Some(response?)),
5924 timeout_happened = timeout => {
5925 if timeout_happened {
5926 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5927 Ok(None)
5928 } else {
5929 let completions = lsp_request.await?;
5930 Ok(Some(completions))
5931 }
5932 },
5933 }
5934 });
5935 tasks.push((lsp_adapter, new_task));
5936 }
5937 })?;
5938
5939 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5940 let completion_response = task.await.ok()??;
5941 let completions = populate_labels_for_completions(
5942 completion_response.completions,
5943 language.clone(),
5944 lsp_adapter,
5945 )
5946 .await;
5947 Some(CompletionResponse {
5948 completions,
5949 display_options: CompletionDisplayOptions::default(),
5950 is_incomplete: completion_response.is_incomplete,
5951 })
5952 });
5953
5954 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5955
5956 Ok(responses.into_iter().flatten().collect())
5957 })
5958 } else {
5959 Task::ready(Err(anyhow!("No upstream client or local language server")))
5960 }
5961 }
5962
5963 pub fn resolve_completions(
5964 &self,
5965 buffer: Entity<Buffer>,
5966 completion_indices: Vec<usize>,
5967 completions: Rc<RefCell<Box<[Completion]>>>,
5968 cx: &mut Context<Self>,
5969 ) -> Task<Result<bool>> {
5970 let client = self.upstream_client();
5971 let buffer_id = buffer.read(cx).remote_id();
5972 let buffer_snapshot = buffer.read(cx).snapshot();
5973
5974 if !self.check_if_capable_for_proto_request(
5975 &buffer,
5976 GetCompletions::can_resolve_completions,
5977 cx,
5978 ) {
5979 return Task::ready(Ok(false));
5980 }
5981 cx.spawn(async move |lsp_store, cx| {
5982 let mut did_resolve = false;
5983 if let Some((client, project_id)) = client {
5984 for completion_index in completion_indices {
5985 let server_id = {
5986 let completion = &completions.borrow()[completion_index];
5987 completion.source.server_id()
5988 };
5989 if let Some(server_id) = server_id {
5990 if Self::resolve_completion_remote(
5991 project_id,
5992 server_id,
5993 buffer_id,
5994 completions.clone(),
5995 completion_index,
5996 client.clone(),
5997 )
5998 .await
5999 .log_err()
6000 .is_some()
6001 {
6002 did_resolve = true;
6003 }
6004 } else {
6005 resolve_word_completion(
6006 &buffer_snapshot,
6007 &mut completions.borrow_mut()[completion_index],
6008 );
6009 }
6010 }
6011 } else {
6012 for completion_index in completion_indices {
6013 let server_id = {
6014 let completion = &completions.borrow()[completion_index];
6015 completion.source.server_id()
6016 };
6017 if let Some(server_id) = server_id {
6018 let server_and_adapter = lsp_store
6019 .read_with(cx, |lsp_store, _| {
6020 let server = lsp_store.language_server_for_id(server_id)?;
6021 let adapter =
6022 lsp_store.language_server_adapter_for_id(server.server_id())?;
6023 Some((server, adapter))
6024 })
6025 .ok()
6026 .flatten();
6027 let Some((server, adapter)) = server_and_adapter else {
6028 continue;
6029 };
6030
6031 let resolved = Self::resolve_completion_local(
6032 server,
6033 completions.clone(),
6034 completion_index,
6035 )
6036 .await
6037 .log_err()
6038 .is_some();
6039 if resolved {
6040 Self::regenerate_completion_labels(
6041 adapter,
6042 &buffer_snapshot,
6043 completions.clone(),
6044 completion_index,
6045 )
6046 .await
6047 .log_err();
6048 did_resolve = true;
6049 }
6050 } else {
6051 resolve_word_completion(
6052 &buffer_snapshot,
6053 &mut completions.borrow_mut()[completion_index],
6054 );
6055 }
6056 }
6057 }
6058
6059 Ok(did_resolve)
6060 })
6061 }
6062
6063 async fn resolve_completion_local(
6064 server: Arc<lsp::LanguageServer>,
6065 completions: Rc<RefCell<Box<[Completion]>>>,
6066 completion_index: usize,
6067 ) -> Result<()> {
6068 let server_id = server.server_id();
6069 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6070 return Ok(());
6071 }
6072
6073 let request = {
6074 let completion = &completions.borrow()[completion_index];
6075 match &completion.source {
6076 CompletionSource::Lsp {
6077 lsp_completion,
6078 resolved,
6079 server_id: completion_server_id,
6080 ..
6081 } => {
6082 if *resolved {
6083 return Ok(());
6084 }
6085 anyhow::ensure!(
6086 server_id == *completion_server_id,
6087 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6088 );
6089 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6090 }
6091 CompletionSource::BufferWord { .. }
6092 | CompletionSource::Dap { .. }
6093 | CompletionSource::Custom => {
6094 return Ok(());
6095 }
6096 }
6097 };
6098 let resolved_completion = request
6099 .await
6100 .into_response()
6101 .context("resolve completion")?;
6102
6103 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6104 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6105
6106 let mut completions = completions.borrow_mut();
6107 let completion = &mut completions[completion_index];
6108 if let CompletionSource::Lsp {
6109 lsp_completion,
6110 resolved,
6111 server_id: completion_server_id,
6112 ..
6113 } = &mut completion.source
6114 {
6115 if *resolved {
6116 return Ok(());
6117 }
6118 anyhow::ensure!(
6119 server_id == *completion_server_id,
6120 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6121 );
6122 *lsp_completion = Box::new(resolved_completion);
6123 *resolved = true;
6124 }
6125 Ok(())
6126 }
6127
6128 async fn regenerate_completion_labels(
6129 adapter: Arc<CachedLspAdapter>,
6130 snapshot: &BufferSnapshot,
6131 completions: Rc<RefCell<Box<[Completion]>>>,
6132 completion_index: usize,
6133 ) -> Result<()> {
6134 let completion_item = completions.borrow()[completion_index]
6135 .source
6136 .lsp_completion(true)
6137 .map(Cow::into_owned);
6138 if let Some(lsp_documentation) = completion_item
6139 .as_ref()
6140 .and_then(|completion_item| completion_item.documentation.clone())
6141 {
6142 let mut completions = completions.borrow_mut();
6143 let completion = &mut completions[completion_index];
6144 completion.documentation = Some(lsp_documentation.into());
6145 } else {
6146 let mut completions = completions.borrow_mut();
6147 let completion = &mut completions[completion_index];
6148 completion.documentation = Some(CompletionDocumentation::Undocumented);
6149 }
6150
6151 let mut new_label = match completion_item {
6152 Some(completion_item) => {
6153 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6154 // So we have to update the label here anyway...
6155 let language = snapshot.language();
6156 match language {
6157 Some(language) => {
6158 adapter
6159 .labels_for_completions(
6160 std::slice::from_ref(&completion_item),
6161 language,
6162 )
6163 .await?
6164 }
6165 None => Vec::new(),
6166 }
6167 .pop()
6168 .flatten()
6169 .unwrap_or_else(|| {
6170 CodeLabel::fallback_for_completion(
6171 &completion_item,
6172 language.map(|language| language.as_ref()),
6173 )
6174 })
6175 }
6176 None => CodeLabel::plain(
6177 completions.borrow()[completion_index].new_text.clone(),
6178 None,
6179 ),
6180 };
6181 ensure_uniform_list_compatible_label(&mut new_label);
6182
6183 let mut completions = completions.borrow_mut();
6184 let completion = &mut completions[completion_index];
6185 if completion.label.filter_text() == new_label.filter_text() {
6186 completion.label = new_label;
6187 } else {
6188 log::error!(
6189 "Resolved completion changed display label from {} to {}. \
6190 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6191 completion.label.text(),
6192 new_label.text(),
6193 completion.label.filter_text(),
6194 new_label.filter_text()
6195 );
6196 }
6197
6198 Ok(())
6199 }
6200
6201 async fn resolve_completion_remote(
6202 project_id: u64,
6203 server_id: LanguageServerId,
6204 buffer_id: BufferId,
6205 completions: Rc<RefCell<Box<[Completion]>>>,
6206 completion_index: usize,
6207 client: AnyProtoClient,
6208 ) -> Result<()> {
6209 let lsp_completion = {
6210 let completion = &completions.borrow()[completion_index];
6211 match &completion.source {
6212 CompletionSource::Lsp {
6213 lsp_completion,
6214 resolved,
6215 server_id: completion_server_id,
6216 ..
6217 } => {
6218 anyhow::ensure!(
6219 server_id == *completion_server_id,
6220 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6221 );
6222 if *resolved {
6223 return Ok(());
6224 }
6225 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6226 }
6227 CompletionSource::Custom
6228 | CompletionSource::Dap { .. }
6229 | CompletionSource::BufferWord { .. } => {
6230 return Ok(());
6231 }
6232 }
6233 };
6234 let request = proto::ResolveCompletionDocumentation {
6235 project_id,
6236 language_server_id: server_id.0 as u64,
6237 lsp_completion,
6238 buffer_id: buffer_id.into(),
6239 };
6240
6241 let response = client
6242 .request(request)
6243 .await
6244 .context("completion documentation resolve proto request")?;
6245 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6246
6247 let documentation = if response.documentation.is_empty() {
6248 CompletionDocumentation::Undocumented
6249 } else if response.documentation_is_markdown {
6250 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6251 } else if response.documentation.lines().count() <= 1 {
6252 CompletionDocumentation::SingleLine(response.documentation.into())
6253 } else {
6254 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6255 };
6256
6257 let mut completions = completions.borrow_mut();
6258 let completion = &mut completions[completion_index];
6259 completion.documentation = Some(documentation);
6260 if let CompletionSource::Lsp {
6261 insert_range,
6262 lsp_completion,
6263 resolved,
6264 server_id: completion_server_id,
6265 lsp_defaults: _,
6266 } = &mut completion.source
6267 {
6268 let completion_insert_range = response
6269 .old_insert_start
6270 .and_then(deserialize_anchor)
6271 .zip(response.old_insert_end.and_then(deserialize_anchor));
6272 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6273
6274 if *resolved {
6275 return Ok(());
6276 }
6277 anyhow::ensure!(
6278 server_id == *completion_server_id,
6279 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6280 );
6281 *lsp_completion = Box::new(resolved_lsp_completion);
6282 *resolved = true;
6283 }
6284
6285 let replace_range = response
6286 .old_replace_start
6287 .and_then(deserialize_anchor)
6288 .zip(response.old_replace_end.and_then(deserialize_anchor));
6289 if let Some((old_replace_start, old_replace_end)) = replace_range
6290 && !response.new_text.is_empty()
6291 {
6292 completion.new_text = response.new_text;
6293 completion.replace_range = old_replace_start..old_replace_end;
6294 }
6295
6296 Ok(())
6297 }
6298
6299 pub fn apply_additional_edits_for_completion(
6300 &self,
6301 buffer_handle: Entity<Buffer>,
6302 completions: Rc<RefCell<Box<[Completion]>>>,
6303 completion_index: usize,
6304 push_to_history: bool,
6305 cx: &mut Context<Self>,
6306 ) -> Task<Result<Option<Transaction>>> {
6307 if let Some((client, project_id)) = self.upstream_client() {
6308 let buffer = buffer_handle.read(cx);
6309 let buffer_id = buffer.remote_id();
6310 cx.spawn(async move |_, cx| {
6311 let request = {
6312 let completion = completions.borrow()[completion_index].clone();
6313 proto::ApplyCompletionAdditionalEdits {
6314 project_id,
6315 buffer_id: buffer_id.into(),
6316 completion: Some(Self::serialize_completion(&CoreCompletion {
6317 replace_range: completion.replace_range,
6318 new_text: completion.new_text,
6319 source: completion.source,
6320 })),
6321 }
6322 };
6323
6324 if let Some(transaction) = client.request(request).await?.transaction {
6325 let transaction = language::proto::deserialize_transaction(transaction)?;
6326 buffer_handle
6327 .update(cx, |buffer, _| {
6328 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6329 })?
6330 .await?;
6331 if push_to_history {
6332 buffer_handle.update(cx, |buffer, _| {
6333 buffer.push_transaction(transaction.clone(), Instant::now());
6334 buffer.finalize_last_transaction();
6335 })?;
6336 }
6337 Ok(Some(transaction))
6338 } else {
6339 Ok(None)
6340 }
6341 })
6342 } else {
6343 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6344 let completion = &completions.borrow()[completion_index];
6345 let server_id = completion.source.server_id()?;
6346 Some(
6347 self.language_server_for_local_buffer(buffer, server_id, cx)?
6348 .1
6349 .clone(),
6350 )
6351 }) else {
6352 return Task::ready(Ok(None));
6353 };
6354
6355 cx.spawn(async move |this, cx| {
6356 Self::resolve_completion_local(
6357 server.clone(),
6358 completions.clone(),
6359 completion_index,
6360 )
6361 .await
6362 .context("resolving completion")?;
6363 let completion = completions.borrow()[completion_index].clone();
6364 let additional_text_edits = completion
6365 .source
6366 .lsp_completion(true)
6367 .as_ref()
6368 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6369 if let Some(edits) = additional_text_edits {
6370 let edits = this
6371 .update(cx, |this, cx| {
6372 this.as_local_mut().unwrap().edits_from_lsp(
6373 &buffer_handle,
6374 edits,
6375 server.server_id(),
6376 None,
6377 cx,
6378 )
6379 })?
6380 .await?;
6381
6382 buffer_handle.update(cx, |buffer, cx| {
6383 buffer.finalize_last_transaction();
6384 buffer.start_transaction();
6385
6386 for (range, text) in edits {
6387 let primary = &completion.replace_range;
6388
6389 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6390 // and the primary completion is just an insertion (empty range), then this is likely
6391 // an auto-import scenario and should not be considered overlapping
6392 // https://github.com/zed-industries/zed/issues/26136
6393 let is_file_start_auto_import = {
6394 let snapshot = buffer.snapshot();
6395 let primary_start_point = primary.start.to_point(&snapshot);
6396 let range_start_point = range.start.to_point(&snapshot);
6397
6398 let result = primary_start_point.row == 0
6399 && primary_start_point.column == 0
6400 && range_start_point.row == 0
6401 && range_start_point.column == 0;
6402
6403 result
6404 };
6405
6406 let has_overlap = if is_file_start_auto_import {
6407 false
6408 } else {
6409 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6410 && primary.end.cmp(&range.start, buffer).is_ge();
6411 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6412 && range.end.cmp(&primary.end, buffer).is_ge();
6413 let result = start_within || end_within;
6414 result
6415 };
6416
6417 //Skip additional edits which overlap with the primary completion edit
6418 //https://github.com/zed-industries/zed/pull/1871
6419 if !has_overlap {
6420 buffer.edit([(range, text)], None, cx);
6421 }
6422 }
6423
6424 let transaction = if buffer.end_transaction(cx).is_some() {
6425 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6426 if !push_to_history {
6427 buffer.forget_transaction(transaction.id);
6428 }
6429 Some(transaction)
6430 } else {
6431 None
6432 };
6433 Ok(transaction)
6434 })?
6435 } else {
6436 Ok(None)
6437 }
6438 })
6439 }
6440 }
6441
6442 pub fn pull_diagnostics(
6443 &mut self,
6444 buffer: Entity<Buffer>,
6445 cx: &mut Context<Self>,
6446 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6447 let buffer_id = buffer.read(cx).remote_id();
6448
6449 if let Some((client, upstream_project_id)) = self.upstream_client() {
6450 let request = GetDocumentDiagnostics {
6451 previous_result_id: None,
6452 };
6453 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6454 return Task::ready(Ok(None));
6455 }
6456 let request_task = client.request_lsp(
6457 upstream_project_id,
6458 None,
6459 LSP_REQUEST_TIMEOUT,
6460 cx.background_executor().clone(),
6461 request.to_proto(upstream_project_id, buffer.read(cx)),
6462 );
6463 cx.background_spawn(async move {
6464 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6465 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6466 // Do not attempt to further process the dummy responses here.
6467 let _response = request_task.await?;
6468 Ok(None)
6469 })
6470 } else {
6471 let server_ids = buffer.update(cx, |buffer, cx| {
6472 self.language_servers_for_local_buffer(buffer, cx)
6473 .map(|(_, server)| server.server_id())
6474 .collect::<Vec<_>>()
6475 });
6476 let pull_diagnostics = server_ids
6477 .into_iter()
6478 .map(|server_id| {
6479 let result_id = self.result_id(server_id, buffer_id, cx);
6480 self.request_lsp(
6481 buffer.clone(),
6482 LanguageServerToQuery::Other(server_id),
6483 GetDocumentDiagnostics {
6484 previous_result_id: result_id,
6485 },
6486 cx,
6487 )
6488 })
6489 .collect::<Vec<_>>();
6490
6491 cx.background_spawn(async move {
6492 let mut responses = Vec::new();
6493 for diagnostics in join_all(pull_diagnostics).await {
6494 responses.extend(diagnostics?);
6495 }
6496 Ok(Some(responses))
6497 })
6498 }
6499 }
6500
6501 pub fn applicable_inlay_chunks(
6502 &mut self,
6503 buffer: &Entity<Buffer>,
6504 ranges: &[Range<text::Anchor>],
6505 cx: &mut Context<Self>,
6506 ) -> Vec<Range<BufferRow>> {
6507 self.latest_lsp_data(buffer, cx)
6508 .inlay_hints
6509 .applicable_chunks(ranges)
6510 .map(|chunk| chunk.start..chunk.end)
6511 .collect()
6512 }
6513
6514 pub fn invalidate_inlay_hints<'a>(
6515 &'a mut self,
6516 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6517 ) {
6518 for buffer_id in for_buffers {
6519 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6520 lsp_data.inlay_hints.clear();
6521 }
6522 }
6523 }
6524
6525 pub fn inlay_hints(
6526 &mut self,
6527 invalidate: InvalidationStrategy,
6528 buffer: Entity<Buffer>,
6529 ranges: Vec<Range<text::Anchor>>,
6530 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6531 cx: &mut Context<Self>,
6532 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6533 let buffer_snapshot = buffer.read(cx).snapshot();
6534 let for_server = if let InvalidationStrategy::RefreshRequested(server_id) = invalidate {
6535 Some(server_id)
6536 } else {
6537 None
6538 };
6539 let invalidate_cache = invalidate.should_invalidate();
6540 let next_hint_id = self.next_hint_id.clone();
6541 let lsp_data = self.latest_lsp_data(&buffer, cx);
6542 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6543 let known_chunks = known_chunks
6544 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6545 .map(|(_, known_chunks)| known_chunks)
6546 .unwrap_or_default();
6547
6548 let mut hint_fetch_tasks = Vec::new();
6549 let mut cached_inlay_hints = HashMap::default();
6550 let mut ranges_to_query = Vec::new();
6551 let applicable_chunks = existing_inlay_hints
6552 .applicable_chunks(ranges.as_slice())
6553 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6554 .collect::<Vec<_>>();
6555 if applicable_chunks.is_empty() {
6556 return HashMap::default();
6557 }
6558
6559 let last_chunk_number = applicable_chunks.len() - 1;
6560
6561 for (i, row_chunk) in applicable_chunks.into_iter().enumerate() {
6562 match (
6563 existing_inlay_hints
6564 .cached_hints(&row_chunk)
6565 .filter(|_| !invalidate_cache)
6566 .cloned(),
6567 existing_inlay_hints
6568 .fetched_hints(&row_chunk)
6569 .as_ref()
6570 .filter(|_| !invalidate_cache)
6571 .cloned(),
6572 ) {
6573 (None, None) => {
6574 let end = if last_chunk_number == i {
6575 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6576 } else {
6577 Point::new(row_chunk.end, 0)
6578 };
6579 ranges_to_query.push((
6580 row_chunk,
6581 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6582 ..buffer_snapshot.anchor_after(end),
6583 ));
6584 }
6585 (None, Some(fetched_hints)) => {
6586 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()))
6587 }
6588 (Some(cached_hints), None) => {
6589 for (server_id, cached_hints) in cached_hints {
6590 if for_server.is_none_or(|for_server| for_server == server_id) {
6591 cached_inlay_hints
6592 .entry(row_chunk.start..row_chunk.end)
6593 .or_insert_with(HashMap::default)
6594 .entry(server_id)
6595 .or_insert_with(Vec::new)
6596 .extend(cached_hints);
6597 }
6598 }
6599 }
6600 (Some(cached_hints), Some(fetched_hints)) => {
6601 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()));
6602 for (server_id, cached_hints) in cached_hints {
6603 if for_server.is_none_or(|for_server| for_server == server_id) {
6604 cached_inlay_hints
6605 .entry(row_chunk.start..row_chunk.end)
6606 .or_insert_with(HashMap::default)
6607 .entry(server_id)
6608 .or_insert_with(Vec::new)
6609 .extend(cached_hints);
6610 }
6611 }
6612 }
6613 }
6614 }
6615
6616 let cached_chunk_data = cached_inlay_hints
6617 .into_iter()
6618 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6619 .collect();
6620 if hint_fetch_tasks.is_empty() && ranges_to_query.is_empty() {
6621 cached_chunk_data
6622 } else {
6623 if invalidate_cache {
6624 lsp_data.inlay_hints.clear();
6625 }
6626
6627 for (chunk, range_to_query) in ranges_to_query {
6628 let next_hint_id = next_hint_id.clone();
6629 let buffer = buffer.clone();
6630 let new_inlay_hints = cx
6631 .spawn(async move |lsp_store, cx| {
6632 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6633 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6634 })?;
6635 new_fetch_task
6636 .await
6637 .and_then(|new_hints_by_server| {
6638 lsp_store.update(cx, |lsp_store, cx| {
6639 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6640 let update_cache = !lsp_data
6641 .buffer_version
6642 .changed_since(&buffer.read(cx).version());
6643 new_hints_by_server
6644 .into_iter()
6645 .map(|(server_id, new_hints)| {
6646 let new_hints = new_hints
6647 .into_iter()
6648 .map(|new_hint| {
6649 (
6650 InlayId::Hint(next_hint_id.fetch_add(
6651 1,
6652 atomic::Ordering::AcqRel,
6653 )),
6654 new_hint,
6655 )
6656 })
6657 .collect::<Vec<_>>();
6658 if update_cache {
6659 lsp_data.inlay_hints.insert_new_hints(
6660 chunk,
6661 server_id,
6662 new_hints.clone(),
6663 );
6664 }
6665 (server_id, new_hints)
6666 })
6667 .collect()
6668 })
6669 })
6670 .map_err(Arc::new)
6671 })
6672 .shared();
6673
6674 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6675 *fetch_task = Some(new_inlay_hints.clone());
6676 hint_fetch_tasks.push((chunk, new_inlay_hints));
6677 }
6678
6679 let mut combined_data = cached_chunk_data;
6680 combined_data.extend(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6681 (
6682 chunk.start..chunk.end,
6683 cx.spawn(async move |_, _| {
6684 hints_fetch.await.map_err(|e| {
6685 if e.error_code() != ErrorCode::Internal {
6686 anyhow!(e.error_code())
6687 } else {
6688 anyhow!("{e:#}")
6689 }
6690 })
6691 }),
6692 )
6693 }));
6694 combined_data
6695 }
6696 }
6697
6698 fn fetch_inlay_hints(
6699 &mut self,
6700 for_server: Option<LanguageServerId>,
6701 buffer: &Entity<Buffer>,
6702 range: Range<Anchor>,
6703 cx: &mut Context<Self>,
6704 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6705 let request = InlayHints {
6706 range: range.clone(),
6707 };
6708 if let Some((upstream_client, project_id)) = self.upstream_client() {
6709 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6710 return Task::ready(Ok(HashMap::default()));
6711 }
6712 let request_task = upstream_client.request_lsp(
6713 project_id,
6714 for_server.map(|id| id.to_proto()),
6715 LSP_REQUEST_TIMEOUT,
6716 cx.background_executor().clone(),
6717 request.to_proto(project_id, buffer.read(cx)),
6718 );
6719 let buffer = buffer.clone();
6720 cx.spawn(async move |weak_lsp_store, cx| {
6721 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6722 return Ok(HashMap::default());
6723 };
6724 let Some(responses) = request_task.await? else {
6725 return Ok(HashMap::default());
6726 };
6727
6728 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6729 let lsp_store = lsp_store.clone();
6730 let buffer = buffer.clone();
6731 let cx = cx.clone();
6732 let request = request.clone();
6733 async move {
6734 (
6735 LanguageServerId::from_proto(response.server_id),
6736 request
6737 .response_from_proto(response.response, lsp_store, buffer, cx)
6738 .await,
6739 )
6740 }
6741 }))
6742 .await;
6743
6744 let mut has_errors = false;
6745 let inlay_hints = inlay_hints
6746 .into_iter()
6747 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6748 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6749 Err(e) => {
6750 has_errors = true;
6751 log::error!("{e:#}");
6752 None
6753 }
6754 })
6755 .collect::<HashMap<_, _>>();
6756 anyhow::ensure!(
6757 !has_errors || !inlay_hints.is_empty(),
6758 "Failed to fetch inlay hints"
6759 );
6760 Ok(inlay_hints)
6761 })
6762 } else {
6763 let inlay_hints_task = match for_server {
6764 Some(server_id) => {
6765 let server_task = self.request_lsp(
6766 buffer.clone(),
6767 LanguageServerToQuery::Other(server_id),
6768 request,
6769 cx,
6770 );
6771 cx.background_spawn(async move {
6772 let mut responses = Vec::new();
6773 match server_task.await {
6774 Ok(response) => responses.push((server_id, response)),
6775 Err(e) => log::error!(
6776 "Error handling response for inlay hints request: {e:#}"
6777 ),
6778 }
6779 responses
6780 })
6781 }
6782 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6783 };
6784 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6785 cx.background_spawn(async move {
6786 Ok(inlay_hints_task
6787 .await
6788 .into_iter()
6789 .map(|(server_id, mut new_hints)| {
6790 new_hints.retain(|hint| {
6791 hint.position.is_valid(&buffer_snapshot)
6792 && range.start.is_valid(&buffer_snapshot)
6793 && range.end.is_valid(&buffer_snapshot)
6794 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6795 && hint.position.cmp(&range.end, &buffer_snapshot).is_le()
6796 });
6797 (server_id, new_hints)
6798 })
6799 .collect())
6800 })
6801 }
6802 }
6803
6804 pub fn pull_diagnostics_for_buffer(
6805 &mut self,
6806 buffer: Entity<Buffer>,
6807 cx: &mut Context<Self>,
6808 ) -> Task<anyhow::Result<()>> {
6809 let diagnostics = self.pull_diagnostics(buffer, cx);
6810 cx.spawn(async move |lsp_store, cx| {
6811 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6812 return Ok(());
6813 };
6814 lsp_store.update(cx, |lsp_store, cx| {
6815 if lsp_store.as_local().is_none() {
6816 return;
6817 }
6818
6819 let mut unchanged_buffers = HashSet::default();
6820 let mut changed_buffers = HashSet::default();
6821 let server_diagnostics_updates = diagnostics
6822 .into_iter()
6823 .filter_map(|diagnostics_set| match diagnostics_set {
6824 LspPullDiagnostics::Response {
6825 server_id,
6826 uri,
6827 diagnostics,
6828 } => Some((server_id, uri, diagnostics)),
6829 LspPullDiagnostics::Default => None,
6830 })
6831 .fold(
6832 HashMap::default(),
6833 |mut acc, (server_id, uri, diagnostics)| {
6834 let (result_id, diagnostics) = match diagnostics {
6835 PulledDiagnostics::Unchanged { result_id } => {
6836 unchanged_buffers.insert(uri.clone());
6837 (Some(result_id), Vec::new())
6838 }
6839 PulledDiagnostics::Changed {
6840 result_id,
6841 diagnostics,
6842 } => {
6843 changed_buffers.insert(uri.clone());
6844 (result_id, diagnostics)
6845 }
6846 };
6847 let disk_based_sources = Cow::Owned(
6848 lsp_store
6849 .language_server_adapter_for_id(server_id)
6850 .as_ref()
6851 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6852 .unwrap_or(&[])
6853 .to_vec(),
6854 );
6855 acc.entry(server_id).or_insert_with(Vec::new).push(
6856 DocumentDiagnosticsUpdate {
6857 server_id,
6858 diagnostics: lsp::PublishDiagnosticsParams {
6859 uri,
6860 diagnostics,
6861 version: None,
6862 },
6863 result_id,
6864 disk_based_sources,
6865 },
6866 );
6867 acc
6868 },
6869 );
6870
6871 for diagnostic_updates in server_diagnostics_updates.into_values() {
6872 lsp_store
6873 .merge_lsp_diagnostics(
6874 DiagnosticSourceKind::Pulled,
6875 diagnostic_updates,
6876 |buffer, old_diagnostic, cx| {
6877 File::from_dyn(buffer.file())
6878 .and_then(|file| {
6879 let abs_path = file.as_local()?.abs_path(cx);
6880 lsp::Uri::from_file_path(abs_path).ok()
6881 })
6882 .is_none_or(|buffer_uri| {
6883 unchanged_buffers.contains(&buffer_uri)
6884 || match old_diagnostic.source_kind {
6885 DiagnosticSourceKind::Pulled => {
6886 !changed_buffers.contains(&buffer_uri)
6887 }
6888 DiagnosticSourceKind::Other
6889 | DiagnosticSourceKind::Pushed => true,
6890 }
6891 })
6892 },
6893 cx,
6894 )
6895 .log_err();
6896 }
6897 })
6898 })
6899 }
6900
6901 pub fn document_colors(
6902 &mut self,
6903 known_cache_version: Option<usize>,
6904 buffer: Entity<Buffer>,
6905 cx: &mut Context<Self>,
6906 ) -> Option<DocumentColorTask> {
6907 let version_queried_for = buffer.read(cx).version();
6908 let buffer_id = buffer.read(cx).remote_id();
6909
6910 let current_language_servers = self.as_local().map(|local| {
6911 local
6912 .buffers_opened_in_servers
6913 .get(&buffer_id)
6914 .cloned()
6915 .unwrap_or_default()
6916 });
6917
6918 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6919 if let Some(cached_colors) = &lsp_data.document_colors {
6920 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6921 let has_different_servers =
6922 current_language_servers.is_some_and(|current_language_servers| {
6923 current_language_servers
6924 != cached_colors.colors.keys().copied().collect()
6925 });
6926 if !has_different_servers {
6927 let cache_version = cached_colors.cache_version;
6928 if Some(cache_version) == known_cache_version {
6929 return None;
6930 } else {
6931 return Some(
6932 Task::ready(Ok(DocumentColors {
6933 colors: cached_colors
6934 .colors
6935 .values()
6936 .flatten()
6937 .cloned()
6938 .collect(),
6939 cache_version: Some(cache_version),
6940 }))
6941 .shared(),
6942 );
6943 }
6944 }
6945 }
6946 }
6947 }
6948
6949 let color_lsp_data = self
6950 .latest_lsp_data(&buffer, cx)
6951 .document_colors
6952 .get_or_insert_default();
6953 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
6954 && !version_queried_for.changed_since(updating_for)
6955 {
6956 return Some(running_update.clone());
6957 }
6958 let buffer_version_queried_for = version_queried_for.clone();
6959 let new_task = cx
6960 .spawn(async move |lsp_store, cx| {
6961 cx.background_executor()
6962 .timer(Duration::from_millis(30))
6963 .await;
6964 let fetched_colors = lsp_store
6965 .update(cx, |lsp_store, cx| {
6966 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6967 })?
6968 .await
6969 .context("fetching document colors")
6970 .map_err(Arc::new);
6971 let fetched_colors = match fetched_colors {
6972 Ok(fetched_colors) => {
6973 if Some(true)
6974 == buffer
6975 .update(cx, |buffer, _| {
6976 buffer.version() != buffer_version_queried_for
6977 })
6978 .ok()
6979 {
6980 return Ok(DocumentColors::default());
6981 }
6982 fetched_colors
6983 }
6984 Err(e) => {
6985 lsp_store
6986 .update(cx, |lsp_store, _| {
6987 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
6988 if let Some(document_colors) = &mut lsp_data.document_colors {
6989 document_colors.colors_update = None;
6990 }
6991 }
6992 })
6993 .ok();
6994 return Err(e);
6995 }
6996 };
6997
6998 lsp_store
6999 .update(cx, |lsp_store, cx| {
7000 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7001 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7002
7003 if let Some(fetched_colors) = fetched_colors {
7004 if lsp_data.buffer_version == buffer_version_queried_for {
7005 lsp_colors.colors.extend(fetched_colors);
7006 lsp_colors.cache_version += 1;
7007 } else if !lsp_data
7008 .buffer_version
7009 .changed_since(&buffer_version_queried_for)
7010 {
7011 lsp_data.buffer_version = buffer_version_queried_for;
7012 lsp_colors.colors = fetched_colors;
7013 lsp_colors.cache_version += 1;
7014 }
7015 }
7016 lsp_colors.colors_update = None;
7017 let colors = lsp_colors
7018 .colors
7019 .values()
7020 .flatten()
7021 .cloned()
7022 .collect::<HashSet<_>>();
7023 DocumentColors {
7024 colors,
7025 cache_version: Some(lsp_colors.cache_version),
7026 }
7027 })
7028 .map_err(Arc::new)
7029 })
7030 .shared();
7031 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7032 Some(new_task)
7033 }
7034
7035 fn fetch_document_colors_for_buffer(
7036 &mut self,
7037 buffer: &Entity<Buffer>,
7038 cx: &mut Context<Self>,
7039 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7040 if let Some((client, project_id)) = self.upstream_client() {
7041 let request = GetDocumentColor {};
7042 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7043 return Task::ready(Ok(None));
7044 }
7045
7046 let request_task = client.request_lsp(
7047 project_id,
7048 None,
7049 LSP_REQUEST_TIMEOUT,
7050 cx.background_executor().clone(),
7051 request.to_proto(project_id, buffer.read(cx)),
7052 );
7053 let buffer = buffer.clone();
7054 cx.spawn(async move |lsp_store, cx| {
7055 let Some(project) = lsp_store.upgrade() else {
7056 return Ok(None);
7057 };
7058 let colors = join_all(
7059 request_task
7060 .await
7061 .log_err()
7062 .flatten()
7063 .map(|response| response.payload)
7064 .unwrap_or_default()
7065 .into_iter()
7066 .map(|color_response| {
7067 let response = request.response_from_proto(
7068 color_response.response,
7069 project.clone(),
7070 buffer.clone(),
7071 cx.clone(),
7072 );
7073 async move {
7074 (
7075 LanguageServerId::from_proto(color_response.server_id),
7076 response.await.log_err().unwrap_or_default(),
7077 )
7078 }
7079 }),
7080 )
7081 .await
7082 .into_iter()
7083 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7084 acc.entry(server_id)
7085 .or_insert_with(HashSet::default)
7086 .extend(colors);
7087 acc
7088 });
7089 Ok(Some(colors))
7090 })
7091 } else {
7092 let document_colors_task =
7093 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7094 cx.background_spawn(async move {
7095 Ok(Some(
7096 document_colors_task
7097 .await
7098 .into_iter()
7099 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7100 acc.entry(server_id)
7101 .or_insert_with(HashSet::default)
7102 .extend(colors);
7103 acc
7104 })
7105 .into_iter()
7106 .collect(),
7107 ))
7108 })
7109 }
7110 }
7111
7112 pub fn signature_help<T: ToPointUtf16>(
7113 &mut self,
7114 buffer: &Entity<Buffer>,
7115 position: T,
7116 cx: &mut Context<Self>,
7117 ) -> Task<Option<Vec<SignatureHelp>>> {
7118 let position = position.to_point_utf16(buffer.read(cx));
7119
7120 if let Some((client, upstream_project_id)) = self.upstream_client() {
7121 let request = GetSignatureHelp { position };
7122 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7123 return Task::ready(None);
7124 }
7125 let request_task = client.request_lsp(
7126 upstream_project_id,
7127 None,
7128 LSP_REQUEST_TIMEOUT,
7129 cx.background_executor().clone(),
7130 request.to_proto(upstream_project_id, buffer.read(cx)),
7131 );
7132 let buffer = buffer.clone();
7133 cx.spawn(async move |weak_project, cx| {
7134 let project = weak_project.upgrade()?;
7135 let signatures = join_all(
7136 request_task
7137 .await
7138 .log_err()
7139 .flatten()
7140 .map(|response| response.payload)
7141 .unwrap_or_default()
7142 .into_iter()
7143 .map(|response| {
7144 let response = GetSignatureHelp { position }.response_from_proto(
7145 response.response,
7146 project.clone(),
7147 buffer.clone(),
7148 cx.clone(),
7149 );
7150 async move { response.await.log_err().flatten() }
7151 }),
7152 )
7153 .await
7154 .into_iter()
7155 .flatten()
7156 .collect();
7157 Some(signatures)
7158 })
7159 } else {
7160 let all_actions_task = self.request_multiple_lsp_locally(
7161 buffer,
7162 Some(position),
7163 GetSignatureHelp { position },
7164 cx,
7165 );
7166 cx.background_spawn(async move {
7167 Some(
7168 all_actions_task
7169 .await
7170 .into_iter()
7171 .flat_map(|(_, actions)| actions)
7172 .collect::<Vec<_>>(),
7173 )
7174 })
7175 }
7176 }
7177
7178 pub fn hover(
7179 &mut self,
7180 buffer: &Entity<Buffer>,
7181 position: PointUtf16,
7182 cx: &mut Context<Self>,
7183 ) -> Task<Option<Vec<Hover>>> {
7184 if let Some((client, upstream_project_id)) = self.upstream_client() {
7185 let request = GetHover { position };
7186 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7187 return Task::ready(None);
7188 }
7189 let request_task = client.request_lsp(
7190 upstream_project_id,
7191 None,
7192 LSP_REQUEST_TIMEOUT,
7193 cx.background_executor().clone(),
7194 request.to_proto(upstream_project_id, buffer.read(cx)),
7195 );
7196 let buffer = buffer.clone();
7197 cx.spawn(async move |weak_project, cx| {
7198 let project = weak_project.upgrade()?;
7199 let hovers = join_all(
7200 request_task
7201 .await
7202 .log_err()
7203 .flatten()
7204 .map(|response| response.payload)
7205 .unwrap_or_default()
7206 .into_iter()
7207 .map(|response| {
7208 let response = GetHover { position }.response_from_proto(
7209 response.response,
7210 project.clone(),
7211 buffer.clone(),
7212 cx.clone(),
7213 );
7214 async move {
7215 response
7216 .await
7217 .log_err()
7218 .flatten()
7219 .and_then(remove_empty_hover_blocks)
7220 }
7221 }),
7222 )
7223 .await
7224 .into_iter()
7225 .flatten()
7226 .collect();
7227 Some(hovers)
7228 })
7229 } else {
7230 let all_actions_task = self.request_multiple_lsp_locally(
7231 buffer,
7232 Some(position),
7233 GetHover { position },
7234 cx,
7235 );
7236 cx.background_spawn(async move {
7237 Some(
7238 all_actions_task
7239 .await
7240 .into_iter()
7241 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7242 .collect::<Vec<Hover>>(),
7243 )
7244 })
7245 }
7246 }
7247
7248 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7249 let language_registry = self.languages.clone();
7250
7251 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7252 let request = upstream_client.request(proto::GetProjectSymbols {
7253 project_id: *project_id,
7254 query: query.to_string(),
7255 });
7256 cx.foreground_executor().spawn(async move {
7257 let response = request.await?;
7258 let mut symbols = Vec::new();
7259 let core_symbols = response
7260 .symbols
7261 .into_iter()
7262 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7263 .collect::<Vec<_>>();
7264 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7265 .await;
7266 Ok(symbols)
7267 })
7268 } else if let Some(local) = self.as_local() {
7269 struct WorkspaceSymbolsResult {
7270 server_id: LanguageServerId,
7271 lsp_adapter: Arc<CachedLspAdapter>,
7272 worktree: WeakEntity<Worktree>,
7273 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7274 }
7275
7276 let mut requests = Vec::new();
7277 let mut requested_servers = BTreeSet::new();
7278 for (seed, state) in local.language_server_ids.iter() {
7279 let Some(worktree_handle) = self
7280 .worktree_store
7281 .read(cx)
7282 .worktree_for_id(seed.worktree_id, cx)
7283 else {
7284 continue;
7285 };
7286 let worktree = worktree_handle.read(cx);
7287 if !worktree.is_visible() {
7288 continue;
7289 }
7290
7291 if !requested_servers.insert(state.id) {
7292 continue;
7293 }
7294
7295 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7296 Some(LanguageServerState::Running {
7297 adapter, server, ..
7298 }) => (adapter.clone(), server),
7299
7300 _ => continue,
7301 };
7302 let supports_workspace_symbol_request =
7303 match server.capabilities().workspace_symbol_provider {
7304 Some(OneOf::Left(supported)) => supported,
7305 Some(OneOf::Right(_)) => true,
7306 None => false,
7307 };
7308 if !supports_workspace_symbol_request {
7309 continue;
7310 }
7311 let worktree_handle = worktree_handle.clone();
7312 let server_id = server.server_id();
7313 requests.push(
7314 server
7315 .request::<lsp::request::WorkspaceSymbolRequest>(
7316 lsp::WorkspaceSymbolParams {
7317 query: query.to_string(),
7318 ..Default::default()
7319 },
7320 )
7321 .map(move |response| {
7322 let lsp_symbols = response.into_response()
7323 .context("workspace symbols request")
7324 .log_err()
7325 .flatten()
7326 .map(|symbol_response| match symbol_response {
7327 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7328 flat_responses.into_iter().map(|lsp_symbol| {
7329 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7330 }).collect::<Vec<_>>()
7331 }
7332 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7333 nested_responses.into_iter().filter_map(|lsp_symbol| {
7334 let location = match lsp_symbol.location {
7335 OneOf::Left(location) => location,
7336 OneOf::Right(_) => {
7337 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7338 return None
7339 }
7340 };
7341 Some((lsp_symbol.name, lsp_symbol.kind, location))
7342 }).collect::<Vec<_>>()
7343 }
7344 }).unwrap_or_default();
7345
7346 WorkspaceSymbolsResult {
7347 server_id,
7348 lsp_adapter,
7349 worktree: worktree_handle.downgrade(),
7350 lsp_symbols,
7351 }
7352 }),
7353 );
7354 }
7355
7356 cx.spawn(async move |this, cx| {
7357 let responses = futures::future::join_all(requests).await;
7358 let this = match this.upgrade() {
7359 Some(this) => this,
7360 None => return Ok(Vec::new()),
7361 };
7362
7363 let mut symbols = Vec::new();
7364 for result in responses {
7365 let core_symbols = this.update(cx, |this, cx| {
7366 result
7367 .lsp_symbols
7368 .into_iter()
7369 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7370 let abs_path = symbol_location.uri.to_file_path().ok()?;
7371 let source_worktree = result.worktree.upgrade()?;
7372 let source_worktree_id = source_worktree.read(cx).id();
7373
7374 let path = if let Some((tree, rel_path)) =
7375 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7376 {
7377 let worktree_id = tree.read(cx).id();
7378 SymbolLocation::InProject(ProjectPath {
7379 worktree_id,
7380 path: rel_path,
7381 })
7382 } else {
7383 SymbolLocation::OutsideProject {
7384 signature: this.symbol_signature(&abs_path),
7385 abs_path: abs_path.into(),
7386 }
7387 };
7388
7389 Some(CoreSymbol {
7390 source_language_server_id: result.server_id,
7391 language_server_name: result.lsp_adapter.name.clone(),
7392 source_worktree_id,
7393 path,
7394 kind: symbol_kind,
7395 name: symbol_name,
7396 range: range_from_lsp(symbol_location.range),
7397 })
7398 })
7399 .collect()
7400 })?;
7401
7402 populate_labels_for_symbols(
7403 core_symbols,
7404 &language_registry,
7405 Some(result.lsp_adapter),
7406 &mut symbols,
7407 )
7408 .await;
7409 }
7410
7411 Ok(symbols)
7412 })
7413 } else {
7414 Task::ready(Err(anyhow!("No upstream client or local language server")))
7415 }
7416 }
7417
7418 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7419 let mut summary = DiagnosticSummary::default();
7420 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7421 summary.error_count += path_summary.error_count;
7422 summary.warning_count += path_summary.warning_count;
7423 }
7424 summary
7425 }
7426
7427 /// Returns the diagnostic summary for a specific project path.
7428 pub fn diagnostic_summary_for_path(
7429 &self,
7430 project_path: &ProjectPath,
7431 _: &App,
7432 ) -> DiagnosticSummary {
7433 if let Some(summaries) = self
7434 .diagnostic_summaries
7435 .get(&project_path.worktree_id)
7436 .and_then(|map| map.get(&project_path.path))
7437 {
7438 let (error_count, warning_count) = summaries.iter().fold(
7439 (0, 0),
7440 |(error_count, warning_count), (_language_server_id, summary)| {
7441 (
7442 error_count + summary.error_count,
7443 warning_count + summary.warning_count,
7444 )
7445 },
7446 );
7447
7448 DiagnosticSummary {
7449 error_count,
7450 warning_count,
7451 }
7452 } else {
7453 DiagnosticSummary::default()
7454 }
7455 }
7456
7457 pub fn diagnostic_summaries<'a>(
7458 &'a self,
7459 include_ignored: bool,
7460 cx: &'a App,
7461 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7462 self.worktree_store
7463 .read(cx)
7464 .visible_worktrees(cx)
7465 .filter_map(|worktree| {
7466 let worktree = worktree.read(cx);
7467 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7468 })
7469 .flat_map(move |(worktree, summaries)| {
7470 let worktree_id = worktree.id();
7471 summaries
7472 .iter()
7473 .filter(move |(path, _)| {
7474 include_ignored
7475 || worktree
7476 .entry_for_path(path.as_ref())
7477 .is_some_and(|entry| !entry.is_ignored)
7478 })
7479 .flat_map(move |(path, summaries)| {
7480 summaries.iter().map(move |(server_id, summary)| {
7481 (
7482 ProjectPath {
7483 worktree_id,
7484 path: path.clone(),
7485 },
7486 *server_id,
7487 *summary,
7488 )
7489 })
7490 })
7491 })
7492 }
7493
7494 pub fn on_buffer_edited(
7495 &mut self,
7496 buffer: Entity<Buffer>,
7497 cx: &mut Context<Self>,
7498 ) -> Option<()> {
7499 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7500 Some(
7501 self.as_local()?
7502 .language_servers_for_buffer(buffer, cx)
7503 .map(|i| i.1.clone())
7504 .collect(),
7505 )
7506 })?;
7507
7508 let buffer = buffer.read(cx);
7509 let file = File::from_dyn(buffer.file())?;
7510 let abs_path = file.as_local()?.abs_path(cx);
7511 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7512 let next_snapshot = buffer.text_snapshot();
7513 for language_server in language_servers {
7514 let language_server = language_server.clone();
7515
7516 let buffer_snapshots = self
7517 .as_local_mut()
7518 .unwrap()
7519 .buffer_snapshots
7520 .get_mut(&buffer.remote_id())
7521 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7522 let previous_snapshot = buffer_snapshots.last()?;
7523
7524 let build_incremental_change = || {
7525 let line_ending = next_snapshot.line_ending();
7526 buffer
7527 .edits_since::<Dimensions<PointUtf16, usize>>(
7528 previous_snapshot.snapshot.version(),
7529 )
7530 .map(|edit| {
7531 let edit_start = edit.new.start.0;
7532 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7533 lsp::TextDocumentContentChangeEvent {
7534 range: Some(lsp::Range::new(
7535 point_to_lsp(edit_start),
7536 point_to_lsp(edit_end),
7537 )),
7538 range_length: None,
7539 // Collect changed text and preserve line endings.
7540 // text_for_range returns chunks with normalized \n, so we need to
7541 // convert to the buffer's actual line ending for LSP.
7542 text: line_ending.into_string(
7543 next_snapshot.text_for_range(edit.new.start.1..edit.new.end.1),
7544 ),
7545 }
7546 })
7547 .collect()
7548 };
7549
7550 let document_sync_kind = language_server
7551 .capabilities()
7552 .text_document_sync
7553 .as_ref()
7554 .and_then(|sync| match sync {
7555 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7556 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7557 });
7558
7559 let content_changes: Vec<_> = match document_sync_kind {
7560 Some(lsp::TextDocumentSyncKind::FULL) => {
7561 vec![lsp::TextDocumentContentChangeEvent {
7562 range: None,
7563 range_length: None,
7564 text: next_snapshot.text_with_original_line_endings(),
7565 }]
7566 }
7567 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7568 _ => {
7569 #[cfg(any(test, feature = "test-support"))]
7570 {
7571 build_incremental_change()
7572 }
7573
7574 #[cfg(not(any(test, feature = "test-support")))]
7575 {
7576 continue;
7577 }
7578 }
7579 };
7580
7581 let next_version = previous_snapshot.version + 1;
7582 buffer_snapshots.push(LspBufferSnapshot {
7583 version: next_version,
7584 snapshot: next_snapshot.clone(),
7585 });
7586
7587 language_server
7588 .notify::<lsp::notification::DidChangeTextDocument>(
7589 lsp::DidChangeTextDocumentParams {
7590 text_document: lsp::VersionedTextDocumentIdentifier::new(
7591 uri.clone(),
7592 next_version,
7593 ),
7594 content_changes,
7595 },
7596 )
7597 .ok();
7598 self.pull_workspace_diagnostics(language_server.server_id());
7599 }
7600
7601 None
7602 }
7603
7604 pub fn on_buffer_saved(
7605 &mut self,
7606 buffer: Entity<Buffer>,
7607 cx: &mut Context<Self>,
7608 ) -> Option<()> {
7609 let file = File::from_dyn(buffer.read(cx).file())?;
7610 let worktree_id = file.worktree_id(cx);
7611 let abs_path = file.as_local()?.abs_path(cx);
7612 let text_document = lsp::TextDocumentIdentifier {
7613 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7614 };
7615 let local = self.as_local()?;
7616
7617 for server in local.language_servers_for_worktree(worktree_id) {
7618 if let Some(include_text) = include_text(server.as_ref()) {
7619 let text = if include_text {
7620 Some(buffer.read(cx).text())
7621 } else {
7622 None
7623 };
7624 server
7625 .notify::<lsp::notification::DidSaveTextDocument>(
7626 lsp::DidSaveTextDocumentParams {
7627 text_document: text_document.clone(),
7628 text,
7629 },
7630 )
7631 .ok();
7632 }
7633 }
7634
7635 let language_servers = buffer.update(cx, |buffer, cx| {
7636 local.language_server_ids_for_buffer(buffer, cx)
7637 });
7638 for language_server_id in language_servers {
7639 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7640 }
7641
7642 None
7643 }
7644
7645 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7646 maybe!(async move {
7647 let mut refreshed_servers = HashSet::default();
7648 let servers = lsp_store
7649 .update(cx, |lsp_store, cx| {
7650 let local = lsp_store.as_local()?;
7651
7652 let servers = local
7653 .language_server_ids
7654 .iter()
7655 .filter_map(|(seed, state)| {
7656 let worktree = lsp_store
7657 .worktree_store
7658 .read(cx)
7659 .worktree_for_id(seed.worktree_id, cx);
7660 let delegate: Arc<dyn LspAdapterDelegate> =
7661 worktree.map(|worktree| {
7662 LocalLspAdapterDelegate::new(
7663 local.languages.clone(),
7664 &local.environment,
7665 cx.weak_entity(),
7666 &worktree,
7667 local.http_client.clone(),
7668 local.fs.clone(),
7669 cx,
7670 )
7671 })?;
7672 let server_id = state.id;
7673
7674 let states = local.language_servers.get(&server_id)?;
7675
7676 match states {
7677 LanguageServerState::Starting { .. } => None,
7678 LanguageServerState::Running {
7679 adapter, server, ..
7680 } => {
7681 let adapter = adapter.clone();
7682 let server = server.clone();
7683 refreshed_servers.insert(server.name());
7684 let toolchain = seed.toolchain.clone();
7685 Some(cx.spawn(async move |_, cx| {
7686 let settings =
7687 LocalLspStore::workspace_configuration_for_adapter(
7688 adapter.adapter.clone(),
7689 &delegate,
7690 toolchain,
7691 cx,
7692 )
7693 .await
7694 .ok()?;
7695 server
7696 .notify::<lsp::notification::DidChangeConfiguration>(
7697 lsp::DidChangeConfigurationParams { settings },
7698 )
7699 .ok()?;
7700 Some(())
7701 }))
7702 }
7703 }
7704 })
7705 .collect::<Vec<_>>();
7706
7707 Some(servers)
7708 })
7709 .ok()
7710 .flatten()?;
7711
7712 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7713 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7714 // to stop and unregister its language server wrapper.
7715 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7716 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7717 let _: Vec<Option<()>> = join_all(servers).await;
7718
7719 Some(())
7720 })
7721 .await;
7722 }
7723
7724 fn maintain_workspace_config(
7725 external_refresh_requests: watch::Receiver<()>,
7726 cx: &mut Context<Self>,
7727 ) -> Task<Result<()>> {
7728 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7729 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7730
7731 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7732 *settings_changed_tx.borrow_mut() = ();
7733 });
7734
7735 let mut joint_future =
7736 futures::stream::select(settings_changed_rx, external_refresh_requests);
7737 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7738 // - We might shut down a language server if it's no longer enabled for a given language (and there are no buffers using it otherwise).
7739 // - We might also shut it down when the workspace configuration of all of the users of a given language server converges onto that of the other.
7740 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7741 // - In the easiest case (where we're not wrangling the lifetime of a language server anyhow), if none of the roots of a single language server diverge in their configuration,
7742 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7743 cx.spawn(async move |this, cx| {
7744 while let Some(()) = joint_future.next().await {
7745 this.update(cx, |this, cx| {
7746 this.refresh_server_tree(cx);
7747 })
7748 .ok();
7749
7750 Self::refresh_workspace_configurations(&this, cx).await;
7751 }
7752
7753 drop(settings_observation);
7754 anyhow::Ok(())
7755 })
7756 }
7757
7758 pub fn language_servers_for_local_buffer<'a>(
7759 &'a self,
7760 buffer: &Buffer,
7761 cx: &mut App,
7762 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7763 let local = self.as_local();
7764 let language_server_ids = local
7765 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7766 .unwrap_or_default();
7767
7768 language_server_ids
7769 .into_iter()
7770 .filter_map(
7771 move |server_id| match local?.language_servers.get(&server_id)? {
7772 LanguageServerState::Running {
7773 adapter, server, ..
7774 } => Some((adapter, server)),
7775 _ => None,
7776 },
7777 )
7778 }
7779
7780 pub fn language_server_for_local_buffer<'a>(
7781 &'a self,
7782 buffer: &'a Buffer,
7783 server_id: LanguageServerId,
7784 cx: &'a mut App,
7785 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7786 self.as_local()?
7787 .language_servers_for_buffer(buffer, cx)
7788 .find(|(_, s)| s.server_id() == server_id)
7789 }
7790
7791 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7792 self.diagnostic_summaries.remove(&id_to_remove);
7793 if let Some(local) = self.as_local_mut() {
7794 let to_remove = local.remove_worktree(id_to_remove, cx);
7795 for server in to_remove {
7796 self.language_server_statuses.remove(&server);
7797 }
7798 }
7799 }
7800
7801 pub fn shared(
7802 &mut self,
7803 project_id: u64,
7804 downstream_client: AnyProtoClient,
7805 _: &mut Context<Self>,
7806 ) {
7807 self.downstream_client = Some((downstream_client.clone(), project_id));
7808
7809 for (server_id, status) in &self.language_server_statuses {
7810 if let Some(server) = self.language_server_for_id(*server_id) {
7811 downstream_client
7812 .send(proto::StartLanguageServer {
7813 project_id,
7814 server: Some(proto::LanguageServer {
7815 id: server_id.to_proto(),
7816 name: status.name.to_string(),
7817 worktree_id: status.worktree.map(|id| id.to_proto()),
7818 }),
7819 capabilities: serde_json::to_string(&server.capabilities())
7820 .expect("serializing server LSP capabilities"),
7821 })
7822 .log_err();
7823 }
7824 }
7825 }
7826
7827 pub fn disconnected_from_host(&mut self) {
7828 self.downstream_client.take();
7829 }
7830
7831 pub fn disconnected_from_ssh_remote(&mut self) {
7832 if let LspStoreMode::Remote(RemoteLspStore {
7833 upstream_client, ..
7834 }) = &mut self.mode
7835 {
7836 upstream_client.take();
7837 }
7838 }
7839
7840 pub(crate) fn set_language_server_statuses_from_proto(
7841 &mut self,
7842 project: WeakEntity<Project>,
7843 language_servers: Vec<proto::LanguageServer>,
7844 server_capabilities: Vec<String>,
7845 cx: &mut Context<Self>,
7846 ) {
7847 let lsp_logs = cx
7848 .try_global::<GlobalLogStore>()
7849 .map(|lsp_store| lsp_store.0.clone());
7850
7851 self.language_server_statuses = language_servers
7852 .into_iter()
7853 .zip(server_capabilities)
7854 .map(|(server, server_capabilities)| {
7855 let server_id = LanguageServerId(server.id as usize);
7856 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7857 self.lsp_server_capabilities
7858 .insert(server_id, server_capabilities);
7859 }
7860
7861 let name = LanguageServerName::from_proto(server.name);
7862 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7863
7864 if let Some(lsp_logs) = &lsp_logs {
7865 lsp_logs.update(cx, |lsp_logs, cx| {
7866 lsp_logs.add_language_server(
7867 // Only remote clients get their language servers set from proto
7868 LanguageServerKind::Remote {
7869 project: project.clone(),
7870 },
7871 server_id,
7872 Some(name.clone()),
7873 worktree,
7874 None,
7875 cx,
7876 );
7877 });
7878 }
7879
7880 (
7881 server_id,
7882 LanguageServerStatus {
7883 name,
7884 pending_work: Default::default(),
7885 has_pending_diagnostic_updates: false,
7886 progress_tokens: Default::default(),
7887 worktree,
7888 },
7889 )
7890 })
7891 .collect();
7892 }
7893
7894 #[cfg(test)]
7895 pub fn update_diagnostic_entries(
7896 &mut self,
7897 server_id: LanguageServerId,
7898 abs_path: PathBuf,
7899 result_id: Option<String>,
7900 version: Option<i32>,
7901 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7902 cx: &mut Context<Self>,
7903 ) -> anyhow::Result<()> {
7904 self.merge_diagnostic_entries(
7905 vec![DocumentDiagnosticsUpdate {
7906 diagnostics: DocumentDiagnostics {
7907 diagnostics,
7908 document_abs_path: abs_path,
7909 version,
7910 },
7911 result_id,
7912 server_id,
7913 disk_based_sources: Cow::Borrowed(&[]),
7914 }],
7915 |_, _, _| false,
7916 cx,
7917 )?;
7918 Ok(())
7919 }
7920
7921 pub fn merge_diagnostic_entries<'a>(
7922 &mut self,
7923 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7924 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7925 cx: &mut Context<Self>,
7926 ) -> anyhow::Result<()> {
7927 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7928 let mut updated_diagnostics_paths = HashMap::default();
7929 for mut update in diagnostic_updates {
7930 let abs_path = &update.diagnostics.document_abs_path;
7931 let server_id = update.server_id;
7932 let Some((worktree, relative_path)) =
7933 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7934 else {
7935 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7936 return Ok(());
7937 };
7938
7939 let worktree_id = worktree.read(cx).id();
7940 let project_path = ProjectPath {
7941 worktree_id,
7942 path: relative_path,
7943 };
7944
7945 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7946 let snapshot = buffer_handle.read(cx).snapshot();
7947 let buffer = buffer_handle.read(cx);
7948 let reused_diagnostics = buffer
7949 .buffer_diagnostics(Some(server_id))
7950 .iter()
7951 .filter(|v| merge(buffer, &v.diagnostic, cx))
7952 .map(|v| {
7953 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7954 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7955 DiagnosticEntry {
7956 range: start..end,
7957 diagnostic: v.diagnostic.clone(),
7958 }
7959 })
7960 .collect::<Vec<_>>();
7961
7962 self.as_local_mut()
7963 .context("cannot merge diagnostics on a remote LspStore")?
7964 .update_buffer_diagnostics(
7965 &buffer_handle,
7966 server_id,
7967 update.result_id,
7968 update.diagnostics.version,
7969 update.diagnostics.diagnostics.clone(),
7970 reused_diagnostics.clone(),
7971 cx,
7972 )?;
7973
7974 update.diagnostics.diagnostics.extend(reused_diagnostics);
7975 }
7976
7977 let updated = worktree.update(cx, |worktree, cx| {
7978 self.update_worktree_diagnostics(
7979 worktree.id(),
7980 server_id,
7981 project_path.path.clone(),
7982 update.diagnostics.diagnostics,
7983 cx,
7984 )
7985 })?;
7986 match updated {
7987 ControlFlow::Continue(new_summary) => {
7988 if let Some((project_id, new_summary)) = new_summary {
7989 match &mut diagnostics_summary {
7990 Some(diagnostics_summary) => {
7991 diagnostics_summary
7992 .more_summaries
7993 .push(proto::DiagnosticSummary {
7994 path: project_path.path.as_ref().to_proto(),
7995 language_server_id: server_id.0 as u64,
7996 error_count: new_summary.error_count,
7997 warning_count: new_summary.warning_count,
7998 })
7999 }
8000 None => {
8001 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8002 project_id,
8003 worktree_id: worktree_id.to_proto(),
8004 summary: Some(proto::DiagnosticSummary {
8005 path: project_path.path.as_ref().to_proto(),
8006 language_server_id: server_id.0 as u64,
8007 error_count: new_summary.error_count,
8008 warning_count: new_summary.warning_count,
8009 }),
8010 more_summaries: Vec::new(),
8011 })
8012 }
8013 }
8014 }
8015 updated_diagnostics_paths
8016 .entry(server_id)
8017 .or_insert_with(Vec::new)
8018 .push(project_path);
8019 }
8020 ControlFlow::Break(()) => {}
8021 }
8022 }
8023
8024 if let Some((diagnostics_summary, (downstream_client, _))) =
8025 diagnostics_summary.zip(self.downstream_client.as_ref())
8026 {
8027 downstream_client.send(diagnostics_summary).log_err();
8028 }
8029 for (server_id, paths) in updated_diagnostics_paths {
8030 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8031 }
8032 Ok(())
8033 }
8034
8035 fn update_worktree_diagnostics(
8036 &mut self,
8037 worktree_id: WorktreeId,
8038 server_id: LanguageServerId,
8039 path_in_worktree: Arc<RelPath>,
8040 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8041 _: &mut Context<Worktree>,
8042 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8043 let local = match &mut self.mode {
8044 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8045 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8046 };
8047
8048 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8049 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8050 let summaries_by_server_id = summaries_for_tree
8051 .entry(path_in_worktree.clone())
8052 .or_default();
8053
8054 let old_summary = summaries_by_server_id
8055 .remove(&server_id)
8056 .unwrap_or_default();
8057
8058 let new_summary = DiagnosticSummary::new(&diagnostics);
8059 if new_summary.is_empty() {
8060 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8061 {
8062 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8063 diagnostics_by_server_id.remove(ix);
8064 }
8065 if diagnostics_by_server_id.is_empty() {
8066 diagnostics_for_tree.remove(&path_in_worktree);
8067 }
8068 }
8069 } else {
8070 summaries_by_server_id.insert(server_id, new_summary);
8071 let diagnostics_by_server_id = diagnostics_for_tree
8072 .entry(path_in_worktree.clone())
8073 .or_default();
8074 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8075 Ok(ix) => {
8076 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8077 }
8078 Err(ix) => {
8079 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8080 }
8081 }
8082 }
8083
8084 if !old_summary.is_empty() || !new_summary.is_empty() {
8085 if let Some((_, project_id)) = &self.downstream_client {
8086 Ok(ControlFlow::Continue(Some((
8087 *project_id,
8088 proto::DiagnosticSummary {
8089 path: path_in_worktree.to_proto(),
8090 language_server_id: server_id.0 as u64,
8091 error_count: new_summary.error_count as u32,
8092 warning_count: new_summary.warning_count as u32,
8093 },
8094 ))))
8095 } else {
8096 Ok(ControlFlow::Continue(None))
8097 }
8098 } else {
8099 Ok(ControlFlow::Break(()))
8100 }
8101 }
8102
8103 pub fn open_buffer_for_symbol(
8104 &mut self,
8105 symbol: &Symbol,
8106 cx: &mut Context<Self>,
8107 ) -> Task<Result<Entity<Buffer>>> {
8108 if let Some((client, project_id)) = self.upstream_client() {
8109 let request = client.request(proto::OpenBufferForSymbol {
8110 project_id,
8111 symbol: Some(Self::serialize_symbol(symbol)),
8112 });
8113 cx.spawn(async move |this, cx| {
8114 let response = request.await?;
8115 let buffer_id = BufferId::new(response.buffer_id)?;
8116 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8117 .await
8118 })
8119 } else if let Some(local) = self.as_local() {
8120 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8121 seed.worktree_id == symbol.source_worktree_id
8122 && state.id == symbol.source_language_server_id
8123 && symbol.language_server_name == seed.name
8124 });
8125 if !is_valid {
8126 return Task::ready(Err(anyhow!(
8127 "language server for worktree and language not found"
8128 )));
8129 };
8130
8131 let symbol_abs_path = match &symbol.path {
8132 SymbolLocation::InProject(project_path) => self
8133 .worktree_store
8134 .read(cx)
8135 .absolutize(&project_path, cx)
8136 .context("no such worktree"),
8137 SymbolLocation::OutsideProject {
8138 abs_path,
8139 signature: _,
8140 } => Ok(abs_path.to_path_buf()),
8141 };
8142 let symbol_abs_path = match symbol_abs_path {
8143 Ok(abs_path) => abs_path,
8144 Err(err) => return Task::ready(Err(err)),
8145 };
8146 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8147 uri
8148 } else {
8149 return Task::ready(Err(anyhow!("invalid symbol path")));
8150 };
8151
8152 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8153 } else {
8154 Task::ready(Err(anyhow!("no upstream client or local store")))
8155 }
8156 }
8157
8158 pub(crate) fn open_local_buffer_via_lsp(
8159 &mut self,
8160 abs_path: lsp::Uri,
8161 language_server_id: LanguageServerId,
8162 cx: &mut Context<Self>,
8163 ) -> Task<Result<Entity<Buffer>>> {
8164 cx.spawn(async move |lsp_store, cx| {
8165 // Escape percent-encoded string.
8166 let current_scheme = abs_path.scheme().to_owned();
8167 // Uri is immutable, so we can't modify the scheme
8168
8169 let abs_path = abs_path
8170 .to_file_path()
8171 .map_err(|()| anyhow!("can't convert URI to path"))?;
8172 let p = abs_path.clone();
8173 let yarn_worktree = lsp_store
8174 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8175 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8176 cx.spawn(async move |this, cx| {
8177 let t = this
8178 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8179 .ok()?;
8180 t.await
8181 })
8182 }),
8183 None => Task::ready(None),
8184 })?
8185 .await;
8186 let (worktree_root_target, known_relative_path) =
8187 if let Some((zip_root, relative_path)) = yarn_worktree {
8188 (zip_root, Some(relative_path))
8189 } else {
8190 (Arc::<Path>::from(abs_path.as_path()), None)
8191 };
8192 let (worktree, relative_path) = if let Some(result) =
8193 lsp_store.update(cx, |lsp_store, cx| {
8194 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8195 worktree_store.find_worktree(&worktree_root_target, cx)
8196 })
8197 })? {
8198 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8199 (result.0, relative_path)
8200 } else {
8201 let worktree = lsp_store
8202 .update(cx, |lsp_store, cx| {
8203 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8204 worktree_store.create_worktree(&worktree_root_target, false, cx)
8205 })
8206 })?
8207 .await?;
8208 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8209 lsp_store
8210 .update(cx, |lsp_store, cx| {
8211 if let Some(local) = lsp_store.as_local_mut() {
8212 local.register_language_server_for_invisible_worktree(
8213 &worktree,
8214 language_server_id,
8215 cx,
8216 )
8217 }
8218 })
8219 .ok();
8220 }
8221 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8222 let relative_path = if let Some(known_path) = known_relative_path {
8223 known_path
8224 } else {
8225 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8226 .into_arc()
8227 };
8228 (worktree, relative_path)
8229 };
8230 let project_path = ProjectPath {
8231 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8232 path: relative_path,
8233 };
8234 lsp_store
8235 .update(cx, |lsp_store, cx| {
8236 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8237 buffer_store.open_buffer(project_path, cx)
8238 })
8239 })?
8240 .await
8241 })
8242 }
8243
8244 fn request_multiple_lsp_locally<P, R>(
8245 &mut self,
8246 buffer: &Entity<Buffer>,
8247 position: Option<P>,
8248 request: R,
8249 cx: &mut Context<Self>,
8250 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8251 where
8252 P: ToOffset,
8253 R: LspCommand + Clone,
8254 <R::LspRequest as lsp::request::Request>::Result: Send,
8255 <R::LspRequest as lsp::request::Request>::Params: Send,
8256 {
8257 let Some(local) = self.as_local() else {
8258 return Task::ready(Vec::new());
8259 };
8260
8261 let snapshot = buffer.read(cx).snapshot();
8262 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8263
8264 let server_ids = buffer.update(cx, |buffer, cx| {
8265 local
8266 .language_servers_for_buffer(buffer, cx)
8267 .filter(|(adapter, _)| {
8268 scope
8269 .as_ref()
8270 .map(|scope| scope.language_allowed(&adapter.name))
8271 .unwrap_or(true)
8272 })
8273 .map(|(_, server)| server.server_id())
8274 .filter(|server_id| {
8275 self.as_local().is_none_or(|local| {
8276 local
8277 .buffers_opened_in_servers
8278 .get(&snapshot.remote_id())
8279 .is_some_and(|servers| servers.contains(server_id))
8280 })
8281 })
8282 .collect::<Vec<_>>()
8283 });
8284
8285 let mut response_results = server_ids
8286 .into_iter()
8287 .map(|server_id| {
8288 let task = self.request_lsp(
8289 buffer.clone(),
8290 LanguageServerToQuery::Other(server_id),
8291 request.clone(),
8292 cx,
8293 );
8294 async move { (server_id, task.await) }
8295 })
8296 .collect::<FuturesUnordered<_>>();
8297
8298 cx.background_spawn(async move {
8299 let mut responses = Vec::with_capacity(response_results.len());
8300 while let Some((server_id, response_result)) = response_results.next().await {
8301 match response_result {
8302 Ok(response) => responses.push((server_id, response)),
8303 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8304 }
8305 }
8306 responses
8307 })
8308 }
8309
8310 async fn handle_lsp_command<T: LspCommand>(
8311 this: Entity<Self>,
8312 envelope: TypedEnvelope<T::ProtoRequest>,
8313 mut cx: AsyncApp,
8314 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8315 where
8316 <T::LspRequest as lsp::request::Request>::Params: Send,
8317 <T::LspRequest as lsp::request::Request>::Result: Send,
8318 {
8319 let sender_id = envelope.original_sender_id().unwrap_or_default();
8320 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8321 let buffer_handle = this.update(&mut cx, |this, cx| {
8322 this.buffer_store.read(cx).get_existing(buffer_id)
8323 })??;
8324 let request = T::from_proto(
8325 envelope.payload,
8326 this.clone(),
8327 buffer_handle.clone(),
8328 cx.clone(),
8329 )
8330 .await?;
8331 let response = this
8332 .update(&mut cx, |this, cx| {
8333 this.request_lsp(
8334 buffer_handle.clone(),
8335 LanguageServerToQuery::FirstCapable,
8336 request,
8337 cx,
8338 )
8339 })?
8340 .await?;
8341 this.update(&mut cx, |this, cx| {
8342 Ok(T::response_to_proto(
8343 response,
8344 this,
8345 sender_id,
8346 &buffer_handle.read(cx).version(),
8347 cx,
8348 ))
8349 })?
8350 }
8351
8352 async fn handle_lsp_query(
8353 lsp_store: Entity<Self>,
8354 envelope: TypedEnvelope<proto::LspQuery>,
8355 mut cx: AsyncApp,
8356 ) -> Result<proto::Ack> {
8357 use proto::lsp_query::Request;
8358 let sender_id = envelope.original_sender_id().unwrap_or_default();
8359 let lsp_query = envelope.payload;
8360 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8361 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8362 match lsp_query.request.context("invalid LSP query request")? {
8363 Request::GetReferences(get_references) => {
8364 let position = get_references.position.clone().and_then(deserialize_anchor);
8365 Self::query_lsp_locally::<GetReferences>(
8366 lsp_store,
8367 server_id,
8368 sender_id,
8369 lsp_request_id,
8370 get_references,
8371 position,
8372 &mut cx,
8373 )
8374 .await?;
8375 }
8376 Request::GetDocumentColor(get_document_color) => {
8377 Self::query_lsp_locally::<GetDocumentColor>(
8378 lsp_store,
8379 server_id,
8380 sender_id,
8381 lsp_request_id,
8382 get_document_color,
8383 None,
8384 &mut cx,
8385 )
8386 .await?;
8387 }
8388 Request::GetHover(get_hover) => {
8389 let position = get_hover.position.clone().and_then(deserialize_anchor);
8390 Self::query_lsp_locally::<GetHover>(
8391 lsp_store,
8392 server_id,
8393 sender_id,
8394 lsp_request_id,
8395 get_hover,
8396 position,
8397 &mut cx,
8398 )
8399 .await?;
8400 }
8401 Request::GetCodeActions(get_code_actions) => {
8402 Self::query_lsp_locally::<GetCodeActions>(
8403 lsp_store,
8404 server_id,
8405 sender_id,
8406 lsp_request_id,
8407 get_code_actions,
8408 None,
8409 &mut cx,
8410 )
8411 .await?;
8412 }
8413 Request::GetSignatureHelp(get_signature_help) => {
8414 let position = get_signature_help
8415 .position
8416 .clone()
8417 .and_then(deserialize_anchor);
8418 Self::query_lsp_locally::<GetSignatureHelp>(
8419 lsp_store,
8420 server_id,
8421 sender_id,
8422 lsp_request_id,
8423 get_signature_help,
8424 position,
8425 &mut cx,
8426 )
8427 .await?;
8428 }
8429 Request::GetCodeLens(get_code_lens) => {
8430 Self::query_lsp_locally::<GetCodeLens>(
8431 lsp_store,
8432 server_id,
8433 sender_id,
8434 lsp_request_id,
8435 get_code_lens,
8436 None,
8437 &mut cx,
8438 )
8439 .await?;
8440 }
8441 Request::GetDefinition(get_definition) => {
8442 let position = get_definition.position.clone().and_then(deserialize_anchor);
8443 Self::query_lsp_locally::<GetDefinitions>(
8444 lsp_store,
8445 server_id,
8446 sender_id,
8447 lsp_request_id,
8448 get_definition,
8449 position,
8450 &mut cx,
8451 )
8452 .await?;
8453 }
8454 Request::GetDeclaration(get_declaration) => {
8455 let position = get_declaration
8456 .position
8457 .clone()
8458 .and_then(deserialize_anchor);
8459 Self::query_lsp_locally::<GetDeclarations>(
8460 lsp_store,
8461 server_id,
8462 sender_id,
8463 lsp_request_id,
8464 get_declaration,
8465 position,
8466 &mut cx,
8467 )
8468 .await?;
8469 }
8470 Request::GetTypeDefinition(get_type_definition) => {
8471 let position = get_type_definition
8472 .position
8473 .clone()
8474 .and_then(deserialize_anchor);
8475 Self::query_lsp_locally::<GetTypeDefinitions>(
8476 lsp_store,
8477 server_id,
8478 sender_id,
8479 lsp_request_id,
8480 get_type_definition,
8481 position,
8482 &mut cx,
8483 )
8484 .await?;
8485 }
8486 Request::GetImplementation(get_implementation) => {
8487 let position = get_implementation
8488 .position
8489 .clone()
8490 .and_then(deserialize_anchor);
8491 Self::query_lsp_locally::<GetImplementations>(
8492 lsp_store,
8493 server_id,
8494 sender_id,
8495 lsp_request_id,
8496 get_implementation,
8497 position,
8498 &mut cx,
8499 )
8500 .await?;
8501 }
8502 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8503 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8504 let version = deserialize_version(get_document_diagnostics.buffer_version());
8505 let buffer = lsp_store.update(&mut cx, |this, cx| {
8506 this.buffer_store.read(cx).get_existing(buffer_id)
8507 })??;
8508 buffer
8509 .update(&mut cx, |buffer, _| {
8510 buffer.wait_for_version(version.clone())
8511 })?
8512 .await?;
8513 lsp_store.update(&mut cx, |lsp_store, cx| {
8514 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8515 let key = LspKey {
8516 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8517 server_queried: server_id,
8518 };
8519 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8520 ) {
8521 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8522 lsp_requests.clear();
8523 };
8524 }
8525
8526 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8527 existing_queries.insert(
8528 lsp_request_id,
8529 cx.spawn(async move |lsp_store, cx| {
8530 let diagnostics_pull = lsp_store
8531 .update(cx, |lsp_store, cx| {
8532 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8533 })
8534 .ok();
8535 if let Some(diagnostics_pull) = diagnostics_pull {
8536 match diagnostics_pull.await {
8537 Ok(()) => {}
8538 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8539 };
8540 }
8541 }),
8542 );
8543 })?;
8544 }
8545 Request::InlayHints(inlay_hints) => {
8546 let query_start = inlay_hints
8547 .start
8548 .clone()
8549 .and_then(deserialize_anchor)
8550 .context("invalid inlay hints range start")?;
8551 let query_end = inlay_hints
8552 .end
8553 .clone()
8554 .and_then(deserialize_anchor)
8555 .context("invalid inlay hints range end")?;
8556 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8557 &lsp_store,
8558 server_id,
8559 lsp_request_id,
8560 &inlay_hints,
8561 query_start..query_end,
8562 &mut cx,
8563 )
8564 .await
8565 .context("preparing inlay hints request")?;
8566 Self::query_lsp_locally::<InlayHints>(
8567 lsp_store,
8568 server_id,
8569 sender_id,
8570 lsp_request_id,
8571 inlay_hints,
8572 None,
8573 &mut cx,
8574 )
8575 .await
8576 .context("querying for inlay hints")?
8577 }
8578 }
8579 Ok(proto::Ack {})
8580 }
8581
8582 async fn handle_lsp_query_response(
8583 lsp_store: Entity<Self>,
8584 envelope: TypedEnvelope<proto::LspQueryResponse>,
8585 cx: AsyncApp,
8586 ) -> Result<()> {
8587 lsp_store.read_with(&cx, |lsp_store, _| {
8588 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8589 upstream_client.handle_lsp_response(envelope.clone());
8590 }
8591 })?;
8592 Ok(())
8593 }
8594
8595 async fn handle_apply_code_action(
8596 this: Entity<Self>,
8597 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8598 mut cx: AsyncApp,
8599 ) -> Result<proto::ApplyCodeActionResponse> {
8600 let sender_id = envelope.original_sender_id().unwrap_or_default();
8601 let action =
8602 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8603 let apply_code_action = this.update(&mut cx, |this, cx| {
8604 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8605 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8606 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8607 })??;
8608
8609 let project_transaction = apply_code_action.await?;
8610 let project_transaction = this.update(&mut cx, |this, cx| {
8611 this.buffer_store.update(cx, |buffer_store, cx| {
8612 buffer_store.serialize_project_transaction_for_peer(
8613 project_transaction,
8614 sender_id,
8615 cx,
8616 )
8617 })
8618 })?;
8619 Ok(proto::ApplyCodeActionResponse {
8620 transaction: Some(project_transaction),
8621 })
8622 }
8623
8624 async fn handle_register_buffer_with_language_servers(
8625 this: Entity<Self>,
8626 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8627 mut cx: AsyncApp,
8628 ) -> Result<proto::Ack> {
8629 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8630 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8631 this.update(&mut cx, |this, cx| {
8632 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8633 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8634 project_id: upstream_project_id,
8635 buffer_id: buffer_id.to_proto(),
8636 only_servers: envelope.payload.only_servers,
8637 });
8638 }
8639
8640 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8641 anyhow::bail!("buffer is not open");
8642 };
8643
8644 let handle = this.register_buffer_with_language_servers(
8645 &buffer,
8646 envelope
8647 .payload
8648 .only_servers
8649 .into_iter()
8650 .filter_map(|selector| {
8651 Some(match selector.selector? {
8652 proto::language_server_selector::Selector::ServerId(server_id) => {
8653 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8654 }
8655 proto::language_server_selector::Selector::Name(name) => {
8656 LanguageServerSelector::Name(LanguageServerName(
8657 SharedString::from(name),
8658 ))
8659 }
8660 })
8661 })
8662 .collect(),
8663 false,
8664 cx,
8665 );
8666 this.buffer_store().update(cx, |buffer_store, _| {
8667 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8668 });
8669
8670 Ok(())
8671 })??;
8672 Ok(proto::Ack {})
8673 }
8674
8675 async fn handle_rename_project_entry(
8676 this: Entity<Self>,
8677 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8678 mut cx: AsyncApp,
8679 ) -> Result<proto::ProjectEntryResponse> {
8680 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8681 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8682 let new_path =
8683 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8684
8685 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8686 .update(&mut cx, |this, cx| {
8687 let (worktree, entry) = this
8688 .worktree_store
8689 .read(cx)
8690 .worktree_and_entry_for_id(entry_id, cx)?;
8691 let new_worktree = this
8692 .worktree_store
8693 .read(cx)
8694 .worktree_for_id(new_worktree_id, cx)?;
8695 Some((
8696 this.worktree_store.clone(),
8697 worktree,
8698 new_worktree,
8699 entry.clone(),
8700 ))
8701 })?
8702 .context("worktree not found")?;
8703 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8704 (worktree.absolutize(&old_entry.path), worktree.id())
8705 })?;
8706 let new_abs_path =
8707 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8708
8709 let _transaction = Self::will_rename_entry(
8710 this.downgrade(),
8711 old_worktree_id,
8712 &old_abs_path,
8713 &new_abs_path,
8714 old_entry.is_dir(),
8715 cx.clone(),
8716 )
8717 .await;
8718 let response = WorktreeStore::handle_rename_project_entry(
8719 worktree_store,
8720 envelope.payload,
8721 cx.clone(),
8722 )
8723 .await;
8724 this.read_with(&cx, |this, _| {
8725 this.did_rename_entry(
8726 old_worktree_id,
8727 &old_abs_path,
8728 &new_abs_path,
8729 old_entry.is_dir(),
8730 );
8731 })
8732 .ok();
8733 response
8734 }
8735
8736 async fn handle_update_diagnostic_summary(
8737 this: Entity<Self>,
8738 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8739 mut cx: AsyncApp,
8740 ) -> Result<()> {
8741 this.update(&mut cx, |lsp_store, cx| {
8742 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8743 let mut updated_diagnostics_paths = HashMap::default();
8744 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8745 for message_summary in envelope
8746 .payload
8747 .summary
8748 .into_iter()
8749 .chain(envelope.payload.more_summaries)
8750 {
8751 let project_path = ProjectPath {
8752 worktree_id,
8753 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8754 };
8755 let path = project_path.path.clone();
8756 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8757 let summary = DiagnosticSummary {
8758 error_count: message_summary.error_count as usize,
8759 warning_count: message_summary.warning_count as usize,
8760 };
8761
8762 if summary.is_empty() {
8763 if let Some(worktree_summaries) =
8764 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8765 && let Some(summaries) = worktree_summaries.get_mut(&path)
8766 {
8767 summaries.remove(&server_id);
8768 if summaries.is_empty() {
8769 worktree_summaries.remove(&path);
8770 }
8771 }
8772 } else {
8773 lsp_store
8774 .diagnostic_summaries
8775 .entry(worktree_id)
8776 .or_default()
8777 .entry(path)
8778 .or_default()
8779 .insert(server_id, summary);
8780 }
8781
8782 if let Some((_, project_id)) = &lsp_store.downstream_client {
8783 match &mut diagnostics_summary {
8784 Some(diagnostics_summary) => {
8785 diagnostics_summary
8786 .more_summaries
8787 .push(proto::DiagnosticSummary {
8788 path: project_path.path.as_ref().to_proto(),
8789 language_server_id: server_id.0 as u64,
8790 error_count: summary.error_count as u32,
8791 warning_count: summary.warning_count as u32,
8792 })
8793 }
8794 None => {
8795 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8796 project_id: *project_id,
8797 worktree_id: worktree_id.to_proto(),
8798 summary: Some(proto::DiagnosticSummary {
8799 path: project_path.path.as_ref().to_proto(),
8800 language_server_id: server_id.0 as u64,
8801 error_count: summary.error_count as u32,
8802 warning_count: summary.warning_count as u32,
8803 }),
8804 more_summaries: Vec::new(),
8805 })
8806 }
8807 }
8808 }
8809 updated_diagnostics_paths
8810 .entry(server_id)
8811 .or_insert_with(Vec::new)
8812 .push(project_path);
8813 }
8814
8815 if let Some((diagnostics_summary, (downstream_client, _))) =
8816 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8817 {
8818 downstream_client.send(diagnostics_summary).log_err();
8819 }
8820 for (server_id, paths) in updated_diagnostics_paths {
8821 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8822 }
8823 Ok(())
8824 })?
8825 }
8826
8827 async fn handle_start_language_server(
8828 lsp_store: Entity<Self>,
8829 envelope: TypedEnvelope<proto::StartLanguageServer>,
8830 mut cx: AsyncApp,
8831 ) -> Result<()> {
8832 let server = envelope.payload.server.context("invalid server")?;
8833 let server_capabilities =
8834 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8835 .with_context(|| {
8836 format!(
8837 "incorrect server capabilities {}",
8838 envelope.payload.capabilities
8839 )
8840 })?;
8841 lsp_store.update(&mut cx, |lsp_store, cx| {
8842 let server_id = LanguageServerId(server.id as usize);
8843 let server_name = LanguageServerName::from_proto(server.name.clone());
8844 lsp_store
8845 .lsp_server_capabilities
8846 .insert(server_id, server_capabilities);
8847 lsp_store.language_server_statuses.insert(
8848 server_id,
8849 LanguageServerStatus {
8850 name: server_name.clone(),
8851 pending_work: Default::default(),
8852 has_pending_diagnostic_updates: false,
8853 progress_tokens: Default::default(),
8854 worktree: server.worktree_id.map(WorktreeId::from_proto),
8855 },
8856 );
8857 cx.emit(LspStoreEvent::LanguageServerAdded(
8858 server_id,
8859 server_name,
8860 server.worktree_id.map(WorktreeId::from_proto),
8861 ));
8862 cx.notify();
8863 })?;
8864 Ok(())
8865 }
8866
8867 async fn handle_update_language_server(
8868 lsp_store: Entity<Self>,
8869 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8870 mut cx: AsyncApp,
8871 ) -> Result<()> {
8872 lsp_store.update(&mut cx, |lsp_store, cx| {
8873 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8874
8875 match envelope.payload.variant.context("invalid variant")? {
8876 proto::update_language_server::Variant::WorkStart(payload) => {
8877 lsp_store.on_lsp_work_start(
8878 language_server_id,
8879 payload.token,
8880 LanguageServerProgress {
8881 title: payload.title,
8882 is_disk_based_diagnostics_progress: false,
8883 is_cancellable: payload.is_cancellable.unwrap_or(false),
8884 message: payload.message,
8885 percentage: payload.percentage.map(|p| p as usize),
8886 last_update_at: cx.background_executor().now(),
8887 },
8888 cx,
8889 );
8890 }
8891 proto::update_language_server::Variant::WorkProgress(payload) => {
8892 lsp_store.on_lsp_work_progress(
8893 language_server_id,
8894 payload.token,
8895 LanguageServerProgress {
8896 title: None,
8897 is_disk_based_diagnostics_progress: false,
8898 is_cancellable: payload.is_cancellable.unwrap_or(false),
8899 message: payload.message,
8900 percentage: payload.percentage.map(|p| p as usize),
8901 last_update_at: cx.background_executor().now(),
8902 },
8903 cx,
8904 );
8905 }
8906
8907 proto::update_language_server::Variant::WorkEnd(payload) => {
8908 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8909 }
8910
8911 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8912 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8913 }
8914
8915 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8916 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8917 }
8918
8919 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8920 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8921 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8922 cx.emit(LspStoreEvent::LanguageServerUpdate {
8923 language_server_id,
8924 name: envelope
8925 .payload
8926 .server_name
8927 .map(SharedString::new)
8928 .map(LanguageServerName),
8929 message: non_lsp,
8930 });
8931 }
8932 }
8933
8934 Ok(())
8935 })?
8936 }
8937
8938 async fn handle_language_server_log(
8939 this: Entity<Self>,
8940 envelope: TypedEnvelope<proto::LanguageServerLog>,
8941 mut cx: AsyncApp,
8942 ) -> Result<()> {
8943 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8944 let log_type = envelope
8945 .payload
8946 .log_type
8947 .map(LanguageServerLogType::from_proto)
8948 .context("invalid language server log type")?;
8949
8950 let message = envelope.payload.message;
8951
8952 this.update(&mut cx, |_, cx| {
8953 cx.emit(LspStoreEvent::LanguageServerLog(
8954 language_server_id,
8955 log_type,
8956 message,
8957 ));
8958 })
8959 }
8960
8961 async fn handle_lsp_ext_cancel_flycheck(
8962 lsp_store: Entity<Self>,
8963 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
8964 cx: AsyncApp,
8965 ) -> Result<proto::Ack> {
8966 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8967 let task = lsp_store.read_with(&cx, |lsp_store, _| {
8968 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8969 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
8970 } else {
8971 None
8972 }
8973 })?;
8974 if let Some(task) = task {
8975 task.context("handling lsp ext cancel flycheck")?;
8976 }
8977
8978 Ok(proto::Ack {})
8979 }
8980
8981 async fn handle_lsp_ext_run_flycheck(
8982 lsp_store: Entity<Self>,
8983 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
8984 mut cx: AsyncApp,
8985 ) -> Result<proto::Ack> {
8986 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8987 lsp_store.update(&mut cx, |lsp_store, cx| {
8988 if let Some(server) = lsp_store.language_server_for_id(server_id) {
8989 let text_document = if envelope.payload.current_file_only {
8990 let buffer_id = envelope
8991 .payload
8992 .buffer_id
8993 .map(|id| BufferId::new(id))
8994 .transpose()?;
8995 buffer_id
8996 .and_then(|buffer_id| {
8997 lsp_store
8998 .buffer_store()
8999 .read(cx)
9000 .get(buffer_id)
9001 .and_then(|buffer| {
9002 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9003 })
9004 .map(|path| make_text_document_identifier(&path))
9005 })
9006 .transpose()?
9007 } else {
9008 None
9009 };
9010 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9011 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9012 )?;
9013 }
9014 anyhow::Ok(())
9015 })??;
9016
9017 Ok(proto::Ack {})
9018 }
9019
9020 async fn handle_lsp_ext_clear_flycheck(
9021 lsp_store: Entity<Self>,
9022 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9023 cx: AsyncApp,
9024 ) -> Result<proto::Ack> {
9025 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9026 lsp_store
9027 .read_with(&cx, |lsp_store, _| {
9028 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9029 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9030 } else {
9031 None
9032 }
9033 })
9034 .context("handling lsp ext clear flycheck")?;
9035
9036 Ok(proto::Ack {})
9037 }
9038
9039 pub fn disk_based_diagnostics_started(
9040 &mut self,
9041 language_server_id: LanguageServerId,
9042 cx: &mut Context<Self>,
9043 ) {
9044 if let Some(language_server_status) =
9045 self.language_server_statuses.get_mut(&language_server_id)
9046 {
9047 language_server_status.has_pending_diagnostic_updates = true;
9048 }
9049
9050 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9051 cx.emit(LspStoreEvent::LanguageServerUpdate {
9052 language_server_id,
9053 name: self
9054 .language_server_adapter_for_id(language_server_id)
9055 .map(|adapter| adapter.name()),
9056 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9057 Default::default(),
9058 ),
9059 })
9060 }
9061
9062 pub fn disk_based_diagnostics_finished(
9063 &mut self,
9064 language_server_id: LanguageServerId,
9065 cx: &mut Context<Self>,
9066 ) {
9067 if let Some(language_server_status) =
9068 self.language_server_statuses.get_mut(&language_server_id)
9069 {
9070 language_server_status.has_pending_diagnostic_updates = false;
9071 }
9072
9073 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9074 cx.emit(LspStoreEvent::LanguageServerUpdate {
9075 language_server_id,
9076 name: self
9077 .language_server_adapter_for_id(language_server_id)
9078 .map(|adapter| adapter.name()),
9079 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9080 Default::default(),
9081 ),
9082 })
9083 }
9084
9085 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9086 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9087 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9088 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9089 // the language server might take some time to publish diagnostics.
9090 fn simulate_disk_based_diagnostics_events_if_needed(
9091 &mut self,
9092 language_server_id: LanguageServerId,
9093 cx: &mut Context<Self>,
9094 ) {
9095 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9096
9097 let Some(LanguageServerState::Running {
9098 simulate_disk_based_diagnostics_completion,
9099 adapter,
9100 ..
9101 }) = self
9102 .as_local_mut()
9103 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9104 else {
9105 return;
9106 };
9107
9108 if adapter.disk_based_diagnostics_progress_token.is_some() {
9109 return;
9110 }
9111
9112 let prev_task =
9113 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9114 cx.background_executor()
9115 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9116 .await;
9117
9118 this.update(cx, |this, cx| {
9119 this.disk_based_diagnostics_finished(language_server_id, cx);
9120
9121 if let Some(LanguageServerState::Running {
9122 simulate_disk_based_diagnostics_completion,
9123 ..
9124 }) = this.as_local_mut().and_then(|local_store| {
9125 local_store.language_servers.get_mut(&language_server_id)
9126 }) {
9127 *simulate_disk_based_diagnostics_completion = None;
9128 }
9129 })
9130 .ok();
9131 }));
9132
9133 if prev_task.is_none() {
9134 self.disk_based_diagnostics_started(language_server_id, cx);
9135 }
9136 }
9137
9138 pub fn language_server_statuses(
9139 &self,
9140 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9141 self.language_server_statuses
9142 .iter()
9143 .map(|(key, value)| (*key, value))
9144 }
9145
9146 pub(super) fn did_rename_entry(
9147 &self,
9148 worktree_id: WorktreeId,
9149 old_path: &Path,
9150 new_path: &Path,
9151 is_dir: bool,
9152 ) {
9153 maybe!({
9154 let local_store = self.as_local()?;
9155
9156 let old_uri = lsp::Uri::from_file_path(old_path)
9157 .ok()
9158 .map(|uri| uri.to_string())?;
9159 let new_uri = lsp::Uri::from_file_path(new_path)
9160 .ok()
9161 .map(|uri| uri.to_string())?;
9162
9163 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9164 let Some(filter) = local_store
9165 .language_server_paths_watched_for_rename
9166 .get(&language_server.server_id())
9167 else {
9168 continue;
9169 };
9170
9171 if filter.should_send_did_rename(&old_uri, is_dir) {
9172 language_server
9173 .notify::<DidRenameFiles>(RenameFilesParams {
9174 files: vec![FileRename {
9175 old_uri: old_uri.clone(),
9176 new_uri: new_uri.clone(),
9177 }],
9178 })
9179 .ok();
9180 }
9181 }
9182 Some(())
9183 });
9184 }
9185
9186 pub(super) fn will_rename_entry(
9187 this: WeakEntity<Self>,
9188 worktree_id: WorktreeId,
9189 old_path: &Path,
9190 new_path: &Path,
9191 is_dir: bool,
9192 cx: AsyncApp,
9193 ) -> Task<ProjectTransaction> {
9194 let old_uri = lsp::Uri::from_file_path(old_path)
9195 .ok()
9196 .map(|uri| uri.to_string());
9197 let new_uri = lsp::Uri::from_file_path(new_path)
9198 .ok()
9199 .map(|uri| uri.to_string());
9200 cx.spawn(async move |cx| {
9201 let mut tasks = vec![];
9202 this.update(cx, |this, cx| {
9203 let local_store = this.as_local()?;
9204 let old_uri = old_uri?;
9205 let new_uri = new_uri?;
9206 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9207 let Some(filter) = local_store
9208 .language_server_paths_watched_for_rename
9209 .get(&language_server.server_id())
9210 else {
9211 continue;
9212 };
9213
9214 if filter.should_send_will_rename(&old_uri, is_dir) {
9215 let apply_edit = cx.spawn({
9216 let old_uri = old_uri.clone();
9217 let new_uri = new_uri.clone();
9218 let language_server = language_server.clone();
9219 async move |this, cx| {
9220 let edit = language_server
9221 .request::<WillRenameFiles>(RenameFilesParams {
9222 files: vec![FileRename { old_uri, new_uri }],
9223 })
9224 .await
9225 .into_response()
9226 .context("will rename files")
9227 .log_err()
9228 .flatten()?;
9229
9230 let transaction = LocalLspStore::deserialize_workspace_edit(
9231 this.upgrade()?,
9232 edit,
9233 false,
9234 language_server.clone(),
9235 cx,
9236 )
9237 .await
9238 .ok()?;
9239 Some(transaction)
9240 }
9241 });
9242 tasks.push(apply_edit);
9243 }
9244 }
9245 Some(())
9246 })
9247 .ok()
9248 .flatten();
9249 let mut merged_transaction = ProjectTransaction::default();
9250 for task in tasks {
9251 // Await on tasks sequentially so that the order of application of edits is deterministic
9252 // (at least with regards to the order of registration of language servers)
9253 if let Some(transaction) = task.await {
9254 for (buffer, buffer_transaction) in transaction.0 {
9255 merged_transaction.0.insert(buffer, buffer_transaction);
9256 }
9257 }
9258 }
9259 merged_transaction
9260 })
9261 }
9262
9263 fn lsp_notify_abs_paths_changed(
9264 &mut self,
9265 server_id: LanguageServerId,
9266 changes: Vec<PathEvent>,
9267 ) {
9268 maybe!({
9269 let server = self.language_server_for_id(server_id)?;
9270 let changes = changes
9271 .into_iter()
9272 .filter_map(|event| {
9273 let typ = match event.kind? {
9274 PathEventKind::Created => lsp::FileChangeType::CREATED,
9275 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9276 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9277 };
9278 Some(lsp::FileEvent {
9279 uri: file_path_to_lsp_url(&event.path).log_err()?,
9280 typ,
9281 })
9282 })
9283 .collect::<Vec<_>>();
9284 if !changes.is_empty() {
9285 server
9286 .notify::<lsp::notification::DidChangeWatchedFiles>(
9287 lsp::DidChangeWatchedFilesParams { changes },
9288 )
9289 .ok();
9290 }
9291 Some(())
9292 });
9293 }
9294
9295 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9296 self.as_local()?.language_server_for_id(id)
9297 }
9298
9299 fn on_lsp_progress(
9300 &mut self,
9301 progress: lsp::ProgressParams,
9302 language_server_id: LanguageServerId,
9303 disk_based_diagnostics_progress_token: Option<String>,
9304 cx: &mut Context<Self>,
9305 ) {
9306 let token = match progress.token {
9307 lsp::NumberOrString::String(token) => token,
9308 lsp::NumberOrString::Number(token) => {
9309 log::info!("skipping numeric progress token {}", token);
9310 return;
9311 }
9312 };
9313
9314 match progress.value {
9315 lsp::ProgressParamsValue::WorkDone(progress) => {
9316 self.handle_work_done_progress(
9317 progress,
9318 language_server_id,
9319 disk_based_diagnostics_progress_token,
9320 token,
9321 cx,
9322 );
9323 }
9324 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9325 if let Some(LanguageServerState::Running {
9326 workspace_refresh_task: Some(workspace_refresh_task),
9327 ..
9328 }) = self
9329 .as_local_mut()
9330 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9331 {
9332 workspace_refresh_task.progress_tx.try_send(()).ok();
9333 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9334 }
9335 }
9336 }
9337 }
9338
9339 fn handle_work_done_progress(
9340 &mut self,
9341 progress: lsp::WorkDoneProgress,
9342 language_server_id: LanguageServerId,
9343 disk_based_diagnostics_progress_token: Option<String>,
9344 token: String,
9345 cx: &mut Context<Self>,
9346 ) {
9347 let language_server_status =
9348 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9349 status
9350 } else {
9351 return;
9352 };
9353
9354 if !language_server_status.progress_tokens.contains(&token) {
9355 return;
9356 }
9357
9358 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9359 .as_ref()
9360 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9361
9362 match progress {
9363 lsp::WorkDoneProgress::Begin(report) => {
9364 if is_disk_based_diagnostics_progress {
9365 self.disk_based_diagnostics_started(language_server_id, cx);
9366 }
9367 self.on_lsp_work_start(
9368 language_server_id,
9369 token.clone(),
9370 LanguageServerProgress {
9371 title: Some(report.title),
9372 is_disk_based_diagnostics_progress,
9373 is_cancellable: report.cancellable.unwrap_or(false),
9374 message: report.message.clone(),
9375 percentage: report.percentage.map(|p| p as usize),
9376 last_update_at: cx.background_executor().now(),
9377 },
9378 cx,
9379 );
9380 }
9381 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9382 language_server_id,
9383 token,
9384 LanguageServerProgress {
9385 title: None,
9386 is_disk_based_diagnostics_progress,
9387 is_cancellable: report.cancellable.unwrap_or(false),
9388 message: report.message,
9389 percentage: report.percentage.map(|p| p as usize),
9390 last_update_at: cx.background_executor().now(),
9391 },
9392 cx,
9393 ),
9394 lsp::WorkDoneProgress::End(_) => {
9395 language_server_status.progress_tokens.remove(&token);
9396 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9397 if is_disk_based_diagnostics_progress {
9398 self.disk_based_diagnostics_finished(language_server_id, cx);
9399 }
9400 }
9401 }
9402 }
9403
9404 fn on_lsp_work_start(
9405 &mut self,
9406 language_server_id: LanguageServerId,
9407 token: String,
9408 progress: LanguageServerProgress,
9409 cx: &mut Context<Self>,
9410 ) {
9411 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9412 status.pending_work.insert(token.clone(), progress.clone());
9413 cx.notify();
9414 }
9415 cx.emit(LspStoreEvent::LanguageServerUpdate {
9416 language_server_id,
9417 name: self
9418 .language_server_adapter_for_id(language_server_id)
9419 .map(|adapter| adapter.name()),
9420 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9421 token,
9422 title: progress.title,
9423 message: progress.message,
9424 percentage: progress.percentage.map(|p| p as u32),
9425 is_cancellable: Some(progress.is_cancellable),
9426 }),
9427 })
9428 }
9429
9430 fn on_lsp_work_progress(
9431 &mut self,
9432 language_server_id: LanguageServerId,
9433 token: String,
9434 progress: LanguageServerProgress,
9435 cx: &mut Context<Self>,
9436 ) {
9437 let mut did_update = false;
9438 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9439 match status.pending_work.entry(token.clone()) {
9440 btree_map::Entry::Vacant(entry) => {
9441 entry.insert(progress.clone());
9442 did_update = true;
9443 }
9444 btree_map::Entry::Occupied(mut entry) => {
9445 let entry = entry.get_mut();
9446 if (progress.last_update_at - entry.last_update_at)
9447 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9448 {
9449 entry.last_update_at = progress.last_update_at;
9450 if progress.message.is_some() {
9451 entry.message = progress.message.clone();
9452 }
9453 if progress.percentage.is_some() {
9454 entry.percentage = progress.percentage;
9455 }
9456 if progress.is_cancellable != entry.is_cancellable {
9457 entry.is_cancellable = progress.is_cancellable;
9458 }
9459 did_update = true;
9460 }
9461 }
9462 }
9463 }
9464
9465 if did_update {
9466 cx.emit(LspStoreEvent::LanguageServerUpdate {
9467 language_server_id,
9468 name: self
9469 .language_server_adapter_for_id(language_server_id)
9470 .map(|adapter| adapter.name()),
9471 message: proto::update_language_server::Variant::WorkProgress(
9472 proto::LspWorkProgress {
9473 token,
9474 message: progress.message,
9475 percentage: progress.percentage.map(|p| p as u32),
9476 is_cancellable: Some(progress.is_cancellable),
9477 },
9478 ),
9479 })
9480 }
9481 }
9482
9483 fn on_lsp_work_end(
9484 &mut self,
9485 language_server_id: LanguageServerId,
9486 token: String,
9487 cx: &mut Context<Self>,
9488 ) {
9489 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9490 if let Some(work) = status.pending_work.remove(&token)
9491 && !work.is_disk_based_diagnostics_progress
9492 {
9493 cx.emit(LspStoreEvent::RefreshInlayHints(language_server_id));
9494 }
9495 cx.notify();
9496 }
9497
9498 cx.emit(LspStoreEvent::LanguageServerUpdate {
9499 language_server_id,
9500 name: self
9501 .language_server_adapter_for_id(language_server_id)
9502 .map(|adapter| adapter.name()),
9503 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9504 })
9505 }
9506
9507 pub async fn handle_resolve_completion_documentation(
9508 this: Entity<Self>,
9509 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9510 mut cx: AsyncApp,
9511 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9512 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9513
9514 let completion = this
9515 .read_with(&cx, |this, cx| {
9516 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9517 let server = this
9518 .language_server_for_id(id)
9519 .with_context(|| format!("No language server {id}"))?;
9520
9521 anyhow::Ok(cx.background_spawn(async move {
9522 let can_resolve = server
9523 .capabilities()
9524 .completion_provider
9525 .as_ref()
9526 .and_then(|options| options.resolve_provider)
9527 .unwrap_or(false);
9528 if can_resolve {
9529 server
9530 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9531 .await
9532 .into_response()
9533 .context("resolve completion item")
9534 } else {
9535 anyhow::Ok(lsp_completion)
9536 }
9537 }))
9538 })??
9539 .await?;
9540
9541 let mut documentation_is_markdown = false;
9542 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9543 let documentation = match completion.documentation {
9544 Some(lsp::Documentation::String(text)) => text,
9545
9546 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9547 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9548 value
9549 }
9550
9551 _ => String::new(),
9552 };
9553
9554 // If we have a new buffer_id, that means we're talking to a new client
9555 // and want to check for new text_edits in the completion too.
9556 let mut old_replace_start = None;
9557 let mut old_replace_end = None;
9558 let mut old_insert_start = None;
9559 let mut old_insert_end = None;
9560 let mut new_text = String::default();
9561 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9562 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9563 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9564 anyhow::Ok(buffer.read(cx).snapshot())
9565 })??;
9566
9567 if let Some(text_edit) = completion.text_edit.as_ref() {
9568 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9569
9570 if let Some(mut edit) = edit {
9571 LineEnding::normalize(&mut edit.new_text);
9572
9573 new_text = edit.new_text;
9574 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9575 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9576 if let Some(insert_range) = edit.insert_range {
9577 old_insert_start = Some(serialize_anchor(&insert_range.start));
9578 old_insert_end = Some(serialize_anchor(&insert_range.end));
9579 }
9580 }
9581 }
9582 }
9583
9584 Ok(proto::ResolveCompletionDocumentationResponse {
9585 documentation,
9586 documentation_is_markdown,
9587 old_replace_start,
9588 old_replace_end,
9589 new_text,
9590 lsp_completion,
9591 old_insert_start,
9592 old_insert_end,
9593 })
9594 }
9595
9596 async fn handle_on_type_formatting(
9597 this: Entity<Self>,
9598 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9599 mut cx: AsyncApp,
9600 ) -> Result<proto::OnTypeFormattingResponse> {
9601 let on_type_formatting = this.update(&mut cx, |this, cx| {
9602 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9603 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9604 let position = envelope
9605 .payload
9606 .position
9607 .and_then(deserialize_anchor)
9608 .context("invalid position")?;
9609 anyhow::Ok(this.apply_on_type_formatting(
9610 buffer,
9611 position,
9612 envelope.payload.trigger.clone(),
9613 cx,
9614 ))
9615 })??;
9616
9617 let transaction = on_type_formatting
9618 .await?
9619 .as_ref()
9620 .map(language::proto::serialize_transaction);
9621 Ok(proto::OnTypeFormattingResponse { transaction })
9622 }
9623
9624 async fn handle_refresh_inlay_hints(
9625 lsp_store: Entity<Self>,
9626 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9627 mut cx: AsyncApp,
9628 ) -> Result<proto::Ack> {
9629 lsp_store.update(&mut cx, |_, cx| {
9630 cx.emit(LspStoreEvent::RefreshInlayHints(
9631 LanguageServerId::from_proto(envelope.payload.server_id),
9632 ));
9633 })?;
9634 Ok(proto::Ack {})
9635 }
9636
9637 async fn handle_pull_workspace_diagnostics(
9638 lsp_store: Entity<Self>,
9639 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9640 mut cx: AsyncApp,
9641 ) -> Result<proto::Ack> {
9642 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9643 lsp_store.update(&mut cx, |lsp_store, _| {
9644 lsp_store.pull_workspace_diagnostics(server_id);
9645 })?;
9646 Ok(proto::Ack {})
9647 }
9648
9649 async fn handle_get_color_presentation(
9650 lsp_store: Entity<Self>,
9651 envelope: TypedEnvelope<proto::GetColorPresentation>,
9652 mut cx: AsyncApp,
9653 ) -> Result<proto::GetColorPresentationResponse> {
9654 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9655 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9656 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9657 })??;
9658
9659 let color = envelope
9660 .payload
9661 .color
9662 .context("invalid color resolve request")?;
9663 let start = color
9664 .lsp_range_start
9665 .context("invalid color resolve request")?;
9666 let end = color
9667 .lsp_range_end
9668 .context("invalid color resolve request")?;
9669
9670 let color = DocumentColor {
9671 lsp_range: lsp::Range {
9672 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9673 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9674 },
9675 color: lsp::Color {
9676 red: color.red,
9677 green: color.green,
9678 blue: color.blue,
9679 alpha: color.alpha,
9680 },
9681 resolved: false,
9682 color_presentations: Vec::new(),
9683 };
9684 let resolved_color = lsp_store
9685 .update(&mut cx, |lsp_store, cx| {
9686 lsp_store.resolve_color_presentation(
9687 color,
9688 buffer.clone(),
9689 LanguageServerId(envelope.payload.server_id as usize),
9690 cx,
9691 )
9692 })?
9693 .await
9694 .context("resolving color presentation")?;
9695
9696 Ok(proto::GetColorPresentationResponse {
9697 presentations: resolved_color
9698 .color_presentations
9699 .into_iter()
9700 .map(|presentation| proto::ColorPresentation {
9701 label: presentation.label.to_string(),
9702 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9703 additional_text_edits: presentation
9704 .additional_text_edits
9705 .into_iter()
9706 .map(serialize_lsp_edit)
9707 .collect(),
9708 })
9709 .collect(),
9710 })
9711 }
9712
9713 async fn handle_resolve_inlay_hint(
9714 lsp_store: Entity<Self>,
9715 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9716 mut cx: AsyncApp,
9717 ) -> Result<proto::ResolveInlayHintResponse> {
9718 let proto_hint = envelope
9719 .payload
9720 .hint
9721 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9722 let hint = InlayHints::proto_to_project_hint(proto_hint)
9723 .context("resolved proto inlay hint conversion")?;
9724 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9725 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9726 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9727 })??;
9728 let response_hint = lsp_store
9729 .update(&mut cx, |lsp_store, cx| {
9730 lsp_store.resolve_inlay_hint(
9731 hint,
9732 buffer,
9733 LanguageServerId(envelope.payload.language_server_id as usize),
9734 cx,
9735 )
9736 })?
9737 .await
9738 .context("inlay hints fetch")?;
9739 Ok(proto::ResolveInlayHintResponse {
9740 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9741 })
9742 }
9743
9744 async fn handle_refresh_code_lens(
9745 this: Entity<Self>,
9746 _: TypedEnvelope<proto::RefreshCodeLens>,
9747 mut cx: AsyncApp,
9748 ) -> Result<proto::Ack> {
9749 this.update(&mut cx, |_, cx| {
9750 cx.emit(LspStoreEvent::RefreshCodeLens);
9751 })?;
9752 Ok(proto::Ack {})
9753 }
9754
9755 async fn handle_open_buffer_for_symbol(
9756 this: Entity<Self>,
9757 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9758 mut cx: AsyncApp,
9759 ) -> Result<proto::OpenBufferForSymbolResponse> {
9760 let peer_id = envelope.original_sender_id().unwrap_or_default();
9761 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9762 let symbol = Self::deserialize_symbol(symbol)?;
9763 this.read_with(&cx, |this, _| {
9764 if let SymbolLocation::OutsideProject {
9765 abs_path,
9766 signature,
9767 } = &symbol.path
9768 {
9769 let new_signature = this.symbol_signature(&abs_path);
9770 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9771 }
9772 Ok(())
9773 })??;
9774 let buffer = this
9775 .update(&mut cx, |this, cx| {
9776 this.open_buffer_for_symbol(
9777 &Symbol {
9778 language_server_name: symbol.language_server_name,
9779 source_worktree_id: symbol.source_worktree_id,
9780 source_language_server_id: symbol.source_language_server_id,
9781 path: symbol.path,
9782 name: symbol.name,
9783 kind: symbol.kind,
9784 range: symbol.range,
9785 label: CodeLabel::default(),
9786 },
9787 cx,
9788 )
9789 })?
9790 .await?;
9791
9792 this.update(&mut cx, |this, cx| {
9793 let is_private = buffer
9794 .read(cx)
9795 .file()
9796 .map(|f| f.is_private())
9797 .unwrap_or_default();
9798 if is_private {
9799 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9800 } else {
9801 this.buffer_store
9802 .update(cx, |buffer_store, cx| {
9803 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9804 })
9805 .detach_and_log_err(cx);
9806 let buffer_id = buffer.read(cx).remote_id().to_proto();
9807 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9808 }
9809 })?
9810 }
9811
9812 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9813 let mut hasher = Sha256::new();
9814 hasher.update(abs_path.to_string_lossy().as_bytes());
9815 hasher.update(self.nonce.to_be_bytes());
9816 hasher.finalize().as_slice().try_into().unwrap()
9817 }
9818
9819 pub async fn handle_get_project_symbols(
9820 this: Entity<Self>,
9821 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9822 mut cx: AsyncApp,
9823 ) -> Result<proto::GetProjectSymbolsResponse> {
9824 let symbols = this
9825 .update(&mut cx, |this, cx| {
9826 this.symbols(&envelope.payload.query, cx)
9827 })?
9828 .await?;
9829
9830 Ok(proto::GetProjectSymbolsResponse {
9831 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9832 })
9833 }
9834
9835 pub async fn handle_restart_language_servers(
9836 this: Entity<Self>,
9837 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9838 mut cx: AsyncApp,
9839 ) -> Result<proto::Ack> {
9840 this.update(&mut cx, |lsp_store, cx| {
9841 let buffers =
9842 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9843 lsp_store.restart_language_servers_for_buffers(
9844 buffers,
9845 envelope
9846 .payload
9847 .only_servers
9848 .into_iter()
9849 .filter_map(|selector| {
9850 Some(match selector.selector? {
9851 proto::language_server_selector::Selector::ServerId(server_id) => {
9852 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9853 }
9854 proto::language_server_selector::Selector::Name(name) => {
9855 LanguageServerSelector::Name(LanguageServerName(
9856 SharedString::from(name),
9857 ))
9858 }
9859 })
9860 })
9861 .collect(),
9862 cx,
9863 );
9864 })?;
9865
9866 Ok(proto::Ack {})
9867 }
9868
9869 pub async fn handle_stop_language_servers(
9870 lsp_store: Entity<Self>,
9871 envelope: TypedEnvelope<proto::StopLanguageServers>,
9872 mut cx: AsyncApp,
9873 ) -> Result<proto::Ack> {
9874 lsp_store.update(&mut cx, |lsp_store, cx| {
9875 if envelope.payload.all
9876 && envelope.payload.also_servers.is_empty()
9877 && envelope.payload.buffer_ids.is_empty()
9878 {
9879 lsp_store.stop_all_language_servers(cx);
9880 } else {
9881 let buffers =
9882 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9883 lsp_store
9884 .stop_language_servers_for_buffers(
9885 buffers,
9886 envelope
9887 .payload
9888 .also_servers
9889 .into_iter()
9890 .filter_map(|selector| {
9891 Some(match selector.selector? {
9892 proto::language_server_selector::Selector::ServerId(
9893 server_id,
9894 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9895 server_id,
9896 )),
9897 proto::language_server_selector::Selector::Name(name) => {
9898 LanguageServerSelector::Name(LanguageServerName(
9899 SharedString::from(name),
9900 ))
9901 }
9902 })
9903 })
9904 .collect(),
9905 cx,
9906 )
9907 .detach_and_log_err(cx);
9908 }
9909 })?;
9910
9911 Ok(proto::Ack {})
9912 }
9913
9914 pub async fn handle_cancel_language_server_work(
9915 this: Entity<Self>,
9916 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9917 mut cx: AsyncApp,
9918 ) -> Result<proto::Ack> {
9919 this.update(&mut cx, |this, cx| {
9920 if let Some(work) = envelope.payload.work {
9921 match work {
9922 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9923 let buffers =
9924 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9925 this.cancel_language_server_work_for_buffers(buffers, cx);
9926 }
9927 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9928 let server_id = LanguageServerId::from_proto(work.language_server_id);
9929 this.cancel_language_server_work(server_id, work.token, cx);
9930 }
9931 }
9932 }
9933 })?;
9934
9935 Ok(proto::Ack {})
9936 }
9937
9938 fn buffer_ids_to_buffers(
9939 &mut self,
9940 buffer_ids: impl Iterator<Item = u64>,
9941 cx: &mut Context<Self>,
9942 ) -> Vec<Entity<Buffer>> {
9943 buffer_ids
9944 .into_iter()
9945 .flat_map(|buffer_id| {
9946 self.buffer_store
9947 .read(cx)
9948 .get(BufferId::new(buffer_id).log_err()?)
9949 })
9950 .collect::<Vec<_>>()
9951 }
9952
9953 async fn handle_apply_additional_edits_for_completion(
9954 this: Entity<Self>,
9955 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
9956 mut cx: AsyncApp,
9957 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
9958 let (buffer, completion) = this.update(&mut cx, |this, cx| {
9959 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9960 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9961 let completion = Self::deserialize_completion(
9962 envelope.payload.completion.context("invalid completion")?,
9963 )?;
9964 anyhow::Ok((buffer, completion))
9965 })??;
9966
9967 let apply_additional_edits = this.update(&mut cx, |this, cx| {
9968 this.apply_additional_edits_for_completion(
9969 buffer,
9970 Rc::new(RefCell::new(Box::new([Completion {
9971 replace_range: completion.replace_range,
9972 new_text: completion.new_text,
9973 source: completion.source,
9974 documentation: None,
9975 label: CodeLabel::default(),
9976 match_start: None,
9977 insert_text_mode: None,
9978 icon_path: None,
9979 confirm: None,
9980 }]))),
9981 0,
9982 false,
9983 cx,
9984 )
9985 })?;
9986
9987 Ok(proto::ApplyCompletionAdditionalEditsResponse {
9988 transaction: apply_additional_edits
9989 .await?
9990 .as_ref()
9991 .map(language::proto::serialize_transaction),
9992 })
9993 }
9994
9995 pub fn last_formatting_failure(&self) -> Option<&str> {
9996 self.last_formatting_failure.as_deref()
9997 }
9998
9999 pub fn reset_last_formatting_failure(&mut self) {
10000 self.last_formatting_failure = None;
10001 }
10002
10003 pub fn environment_for_buffer(
10004 &self,
10005 buffer: &Entity<Buffer>,
10006 cx: &mut Context<Self>,
10007 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10008 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10009 environment.update(cx, |env, cx| {
10010 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10011 })
10012 } else {
10013 Task::ready(None).shared()
10014 }
10015 }
10016
10017 pub fn format(
10018 &mut self,
10019 buffers: HashSet<Entity<Buffer>>,
10020 target: LspFormatTarget,
10021 push_to_history: bool,
10022 trigger: FormatTrigger,
10023 cx: &mut Context<Self>,
10024 ) -> Task<anyhow::Result<ProjectTransaction>> {
10025 let logger = zlog::scoped!("format");
10026 if self.as_local().is_some() {
10027 zlog::trace!(logger => "Formatting locally");
10028 let logger = zlog::scoped!(logger => "local");
10029 let buffers = buffers
10030 .into_iter()
10031 .map(|buffer_handle| {
10032 let buffer = buffer_handle.read(cx);
10033 let buffer_abs_path = File::from_dyn(buffer.file())
10034 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10035
10036 (buffer_handle, buffer_abs_path, buffer.remote_id())
10037 })
10038 .collect::<Vec<_>>();
10039
10040 cx.spawn(async move |lsp_store, cx| {
10041 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10042
10043 for (handle, abs_path, id) in buffers {
10044 let env = lsp_store
10045 .update(cx, |lsp_store, cx| {
10046 lsp_store.environment_for_buffer(&handle, cx)
10047 })?
10048 .await;
10049
10050 let ranges = match &target {
10051 LspFormatTarget::Buffers => None,
10052 LspFormatTarget::Ranges(ranges) => {
10053 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10054 }
10055 };
10056
10057 formattable_buffers.push(FormattableBuffer {
10058 handle,
10059 abs_path,
10060 env,
10061 ranges,
10062 });
10063 }
10064 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10065
10066 let format_timer = zlog::time!(logger => "Formatting buffers");
10067 let result = LocalLspStore::format_locally(
10068 lsp_store.clone(),
10069 formattable_buffers,
10070 push_to_history,
10071 trigger,
10072 logger,
10073 cx,
10074 )
10075 .await;
10076 format_timer.end();
10077
10078 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10079
10080 lsp_store.update(cx, |lsp_store, _| {
10081 lsp_store.update_last_formatting_failure(&result);
10082 })?;
10083
10084 result
10085 })
10086 } else if let Some((client, project_id)) = self.upstream_client() {
10087 zlog::trace!(logger => "Formatting remotely");
10088 let logger = zlog::scoped!(logger => "remote");
10089 // Don't support formatting ranges via remote
10090 match target {
10091 LspFormatTarget::Buffers => {}
10092 LspFormatTarget::Ranges(_) => {
10093 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10094 return Task::ready(Ok(ProjectTransaction::default()));
10095 }
10096 }
10097
10098 let buffer_store = self.buffer_store();
10099 cx.spawn(async move |lsp_store, cx| {
10100 zlog::trace!(logger => "Sending remote format request");
10101 let request_timer = zlog::time!(logger => "remote format request");
10102 let result = client
10103 .request(proto::FormatBuffers {
10104 project_id,
10105 trigger: trigger as i32,
10106 buffer_ids: buffers
10107 .iter()
10108 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10109 .collect::<Result<_>>()?,
10110 })
10111 .await
10112 .and_then(|result| result.transaction.context("missing transaction"));
10113 request_timer.end();
10114
10115 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10116
10117 lsp_store.update(cx, |lsp_store, _| {
10118 lsp_store.update_last_formatting_failure(&result);
10119 })?;
10120
10121 let transaction_response = result?;
10122 let _timer = zlog::time!(logger => "deserializing project transaction");
10123 buffer_store
10124 .update(cx, |buffer_store, cx| {
10125 buffer_store.deserialize_project_transaction(
10126 transaction_response,
10127 push_to_history,
10128 cx,
10129 )
10130 })?
10131 .await
10132 })
10133 } else {
10134 zlog::trace!(logger => "Not formatting");
10135 Task::ready(Ok(ProjectTransaction::default()))
10136 }
10137 }
10138
10139 async fn handle_format_buffers(
10140 this: Entity<Self>,
10141 envelope: TypedEnvelope<proto::FormatBuffers>,
10142 mut cx: AsyncApp,
10143 ) -> Result<proto::FormatBuffersResponse> {
10144 let sender_id = envelope.original_sender_id().unwrap_or_default();
10145 let format = this.update(&mut cx, |this, cx| {
10146 let mut buffers = HashSet::default();
10147 for buffer_id in &envelope.payload.buffer_ids {
10148 let buffer_id = BufferId::new(*buffer_id)?;
10149 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10150 }
10151 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10152 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10153 })??;
10154
10155 let project_transaction = format.await?;
10156 let project_transaction = this.update(&mut cx, |this, cx| {
10157 this.buffer_store.update(cx, |buffer_store, cx| {
10158 buffer_store.serialize_project_transaction_for_peer(
10159 project_transaction,
10160 sender_id,
10161 cx,
10162 )
10163 })
10164 })?;
10165 Ok(proto::FormatBuffersResponse {
10166 transaction: Some(project_transaction),
10167 })
10168 }
10169
10170 async fn handle_apply_code_action_kind(
10171 this: Entity<Self>,
10172 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10173 mut cx: AsyncApp,
10174 ) -> Result<proto::ApplyCodeActionKindResponse> {
10175 let sender_id = envelope.original_sender_id().unwrap_or_default();
10176 let format = this.update(&mut cx, |this, cx| {
10177 let mut buffers = HashSet::default();
10178 for buffer_id in &envelope.payload.buffer_ids {
10179 let buffer_id = BufferId::new(*buffer_id)?;
10180 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10181 }
10182 let kind = match envelope.payload.kind.as_str() {
10183 "" => CodeActionKind::EMPTY,
10184 "quickfix" => CodeActionKind::QUICKFIX,
10185 "refactor" => CodeActionKind::REFACTOR,
10186 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10187 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10188 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10189 "source" => CodeActionKind::SOURCE,
10190 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10191 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10192 _ => anyhow::bail!(
10193 "Invalid code action kind {}",
10194 envelope.payload.kind.as_str()
10195 ),
10196 };
10197 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10198 })??;
10199
10200 let project_transaction = format.await?;
10201 let project_transaction = this.update(&mut cx, |this, cx| {
10202 this.buffer_store.update(cx, |buffer_store, cx| {
10203 buffer_store.serialize_project_transaction_for_peer(
10204 project_transaction,
10205 sender_id,
10206 cx,
10207 )
10208 })
10209 })?;
10210 Ok(proto::ApplyCodeActionKindResponse {
10211 transaction: Some(project_transaction),
10212 })
10213 }
10214
10215 async fn shutdown_language_server(
10216 server_state: Option<LanguageServerState>,
10217 name: LanguageServerName,
10218 cx: &mut AsyncApp,
10219 ) {
10220 let server = match server_state {
10221 Some(LanguageServerState::Starting { startup, .. }) => {
10222 let mut timer = cx
10223 .background_executor()
10224 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10225 .fuse();
10226
10227 select! {
10228 server = startup.fuse() => server,
10229 () = timer => {
10230 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10231 None
10232 },
10233 }
10234 }
10235
10236 Some(LanguageServerState::Running { server, .. }) => Some(server),
10237
10238 None => None,
10239 };
10240
10241 if let Some(server) = server
10242 && let Some(shutdown) = server.shutdown()
10243 {
10244 shutdown.await;
10245 }
10246 }
10247
10248 // Returns a list of all of the worktrees which no longer have a language server and the root path
10249 // for the stopped server
10250 fn stop_local_language_server(
10251 &mut self,
10252 server_id: LanguageServerId,
10253 cx: &mut Context<Self>,
10254 ) -> Task<()> {
10255 let local = match &mut self.mode {
10256 LspStoreMode::Local(local) => local,
10257 _ => {
10258 return Task::ready(());
10259 }
10260 };
10261
10262 // Remove this server ID from all entries in the given worktree.
10263 local
10264 .language_server_ids
10265 .retain(|_, state| state.id != server_id);
10266 self.buffer_store.update(cx, |buffer_store, cx| {
10267 for buffer in buffer_store.buffers() {
10268 buffer.update(cx, |buffer, cx| {
10269 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10270 buffer.set_completion_triggers(server_id, Default::default(), cx);
10271 });
10272 }
10273 });
10274
10275 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10276 summaries.retain(|path, summaries_by_server_id| {
10277 if summaries_by_server_id.remove(&server_id).is_some() {
10278 if let Some((client, project_id)) = self.downstream_client.clone() {
10279 client
10280 .send(proto::UpdateDiagnosticSummary {
10281 project_id,
10282 worktree_id: worktree_id.to_proto(),
10283 summary: Some(proto::DiagnosticSummary {
10284 path: path.as_ref().to_proto(),
10285 language_server_id: server_id.0 as u64,
10286 error_count: 0,
10287 warning_count: 0,
10288 }),
10289 more_summaries: Vec::new(),
10290 })
10291 .log_err();
10292 }
10293 !summaries_by_server_id.is_empty()
10294 } else {
10295 true
10296 }
10297 });
10298 }
10299
10300 let local = self.as_local_mut().unwrap();
10301 for diagnostics in local.diagnostics.values_mut() {
10302 diagnostics.retain(|_, diagnostics_by_server_id| {
10303 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10304 diagnostics_by_server_id.remove(ix);
10305 !diagnostics_by_server_id.is_empty()
10306 } else {
10307 true
10308 }
10309 });
10310 }
10311 local.language_server_watched_paths.remove(&server_id);
10312
10313 let server_state = local.language_servers.remove(&server_id);
10314 self.cleanup_lsp_data(server_id);
10315 let name = self
10316 .language_server_statuses
10317 .remove(&server_id)
10318 .map(|status| status.name)
10319 .or_else(|| {
10320 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10321 Some(adapter.name())
10322 } else {
10323 None
10324 }
10325 });
10326
10327 if let Some(name) = name {
10328 log::info!("stopping language server {name}");
10329 self.languages
10330 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10331 cx.notify();
10332
10333 return cx.spawn(async move |lsp_store, cx| {
10334 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10335 lsp_store
10336 .update(cx, |lsp_store, cx| {
10337 lsp_store
10338 .languages
10339 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10340 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10341 cx.notify();
10342 })
10343 .ok();
10344 });
10345 }
10346
10347 if server_state.is_some() {
10348 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10349 }
10350 Task::ready(())
10351 }
10352
10353 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10354 if let Some((client, project_id)) = self.upstream_client() {
10355 let request = client.request(proto::StopLanguageServers {
10356 project_id,
10357 buffer_ids: Vec::new(),
10358 also_servers: Vec::new(),
10359 all: true,
10360 });
10361 cx.background_spawn(request).detach_and_log_err(cx);
10362 } else {
10363 let Some(local) = self.as_local_mut() else {
10364 return;
10365 };
10366 let language_servers_to_stop = local
10367 .language_server_ids
10368 .values()
10369 .map(|state| state.id)
10370 .collect();
10371 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10372 let tasks = language_servers_to_stop
10373 .into_iter()
10374 .map(|server| self.stop_local_language_server(server, cx))
10375 .collect::<Vec<_>>();
10376 cx.background_spawn(async move {
10377 futures::future::join_all(tasks).await;
10378 })
10379 .detach();
10380 }
10381 }
10382
10383 pub fn restart_language_servers_for_buffers(
10384 &mut self,
10385 buffers: Vec<Entity<Buffer>>,
10386 only_restart_servers: HashSet<LanguageServerSelector>,
10387 cx: &mut Context<Self>,
10388 ) {
10389 if let Some((client, project_id)) = self.upstream_client() {
10390 let request = client.request(proto::RestartLanguageServers {
10391 project_id,
10392 buffer_ids: buffers
10393 .into_iter()
10394 .map(|b| b.read(cx).remote_id().to_proto())
10395 .collect(),
10396 only_servers: only_restart_servers
10397 .into_iter()
10398 .map(|selector| {
10399 let selector = match selector {
10400 LanguageServerSelector::Id(language_server_id) => {
10401 proto::language_server_selector::Selector::ServerId(
10402 language_server_id.to_proto(),
10403 )
10404 }
10405 LanguageServerSelector::Name(language_server_name) => {
10406 proto::language_server_selector::Selector::Name(
10407 language_server_name.to_string(),
10408 )
10409 }
10410 };
10411 proto::LanguageServerSelector {
10412 selector: Some(selector),
10413 }
10414 })
10415 .collect(),
10416 all: false,
10417 });
10418 cx.background_spawn(request).detach_and_log_err(cx);
10419 } else {
10420 let stop_task = if only_restart_servers.is_empty() {
10421 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10422 } else {
10423 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10424 };
10425 cx.spawn(async move |lsp_store, cx| {
10426 stop_task.await;
10427 lsp_store
10428 .update(cx, |lsp_store, cx| {
10429 for buffer in buffers {
10430 lsp_store.register_buffer_with_language_servers(
10431 &buffer,
10432 only_restart_servers.clone(),
10433 true,
10434 cx,
10435 );
10436 }
10437 })
10438 .ok()
10439 })
10440 .detach();
10441 }
10442 }
10443
10444 pub fn stop_language_servers_for_buffers(
10445 &mut self,
10446 buffers: Vec<Entity<Buffer>>,
10447 also_stop_servers: HashSet<LanguageServerSelector>,
10448 cx: &mut Context<Self>,
10449 ) -> Task<Result<()>> {
10450 if let Some((client, project_id)) = self.upstream_client() {
10451 let request = client.request(proto::StopLanguageServers {
10452 project_id,
10453 buffer_ids: buffers
10454 .into_iter()
10455 .map(|b| b.read(cx).remote_id().to_proto())
10456 .collect(),
10457 also_servers: also_stop_servers
10458 .into_iter()
10459 .map(|selector| {
10460 let selector = match selector {
10461 LanguageServerSelector::Id(language_server_id) => {
10462 proto::language_server_selector::Selector::ServerId(
10463 language_server_id.to_proto(),
10464 )
10465 }
10466 LanguageServerSelector::Name(language_server_name) => {
10467 proto::language_server_selector::Selector::Name(
10468 language_server_name.to_string(),
10469 )
10470 }
10471 };
10472 proto::LanguageServerSelector {
10473 selector: Some(selector),
10474 }
10475 })
10476 .collect(),
10477 all: false,
10478 });
10479 cx.background_spawn(async move {
10480 let _ = request.await?;
10481 Ok(())
10482 })
10483 } else {
10484 let task =
10485 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10486 cx.background_spawn(async move {
10487 task.await;
10488 Ok(())
10489 })
10490 }
10491 }
10492
10493 fn stop_local_language_servers_for_buffers(
10494 &mut self,
10495 buffers: &[Entity<Buffer>],
10496 also_stop_servers: HashSet<LanguageServerSelector>,
10497 cx: &mut Context<Self>,
10498 ) -> Task<()> {
10499 let Some(local) = self.as_local_mut() else {
10500 return Task::ready(());
10501 };
10502 let mut language_server_names_to_stop = BTreeSet::default();
10503 let mut language_servers_to_stop = also_stop_servers
10504 .into_iter()
10505 .flat_map(|selector| match selector {
10506 LanguageServerSelector::Id(id) => Some(id),
10507 LanguageServerSelector::Name(name) => {
10508 language_server_names_to_stop.insert(name);
10509 None
10510 }
10511 })
10512 .collect::<BTreeSet<_>>();
10513
10514 let mut covered_worktrees = HashSet::default();
10515 for buffer in buffers {
10516 buffer.update(cx, |buffer, cx| {
10517 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10518 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10519 && covered_worktrees.insert(worktree_id)
10520 {
10521 language_server_names_to_stop.retain(|name| {
10522 let old_ids_count = language_servers_to_stop.len();
10523 let all_language_servers_with_this_name = local
10524 .language_server_ids
10525 .iter()
10526 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10527 language_servers_to_stop.extend(all_language_servers_with_this_name);
10528 old_ids_count == language_servers_to_stop.len()
10529 });
10530 }
10531 });
10532 }
10533 for name in language_server_names_to_stop {
10534 language_servers_to_stop.extend(
10535 local
10536 .language_server_ids
10537 .iter()
10538 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10539 );
10540 }
10541
10542 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10543 let tasks = language_servers_to_stop
10544 .into_iter()
10545 .map(|server| self.stop_local_language_server(server, cx))
10546 .collect::<Vec<_>>();
10547
10548 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10549 }
10550
10551 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10552 let (worktree, relative_path) =
10553 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10554
10555 let project_path = ProjectPath {
10556 worktree_id: worktree.read(cx).id(),
10557 path: relative_path,
10558 };
10559
10560 Some(
10561 self.buffer_store()
10562 .read(cx)
10563 .get_by_path(&project_path)?
10564 .read(cx),
10565 )
10566 }
10567
10568 #[cfg(any(test, feature = "test-support"))]
10569 pub fn update_diagnostics(
10570 &mut self,
10571 server_id: LanguageServerId,
10572 diagnostics: lsp::PublishDiagnosticsParams,
10573 result_id: Option<String>,
10574 source_kind: DiagnosticSourceKind,
10575 disk_based_sources: &[String],
10576 cx: &mut Context<Self>,
10577 ) -> Result<()> {
10578 self.merge_lsp_diagnostics(
10579 source_kind,
10580 vec![DocumentDiagnosticsUpdate {
10581 diagnostics,
10582 result_id,
10583 server_id,
10584 disk_based_sources: Cow::Borrowed(disk_based_sources),
10585 }],
10586 |_, _, _| false,
10587 cx,
10588 )
10589 }
10590
10591 pub fn merge_lsp_diagnostics(
10592 &mut self,
10593 source_kind: DiagnosticSourceKind,
10594 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10595 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10596 cx: &mut Context<Self>,
10597 ) -> Result<()> {
10598 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10599 let updates = lsp_diagnostics
10600 .into_iter()
10601 .filter_map(|update| {
10602 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10603 Some(DocumentDiagnosticsUpdate {
10604 diagnostics: self.lsp_to_document_diagnostics(
10605 abs_path,
10606 source_kind,
10607 update.server_id,
10608 update.diagnostics,
10609 &update.disk_based_sources,
10610 ),
10611 result_id: update.result_id,
10612 server_id: update.server_id,
10613 disk_based_sources: update.disk_based_sources,
10614 })
10615 })
10616 .collect();
10617 self.merge_diagnostic_entries(updates, merge, cx)?;
10618 Ok(())
10619 }
10620
10621 fn lsp_to_document_diagnostics(
10622 &mut self,
10623 document_abs_path: PathBuf,
10624 source_kind: DiagnosticSourceKind,
10625 server_id: LanguageServerId,
10626 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10627 disk_based_sources: &[String],
10628 ) -> DocumentDiagnostics {
10629 let mut diagnostics = Vec::default();
10630 let mut primary_diagnostic_group_ids = HashMap::default();
10631 let mut sources_by_group_id = HashMap::default();
10632 let mut supporting_diagnostics = HashMap::default();
10633
10634 let adapter = self.language_server_adapter_for_id(server_id);
10635
10636 // Ensure that primary diagnostics are always the most severe
10637 lsp_diagnostics
10638 .diagnostics
10639 .sort_by_key(|item| item.severity);
10640
10641 for diagnostic in &lsp_diagnostics.diagnostics {
10642 let source = diagnostic.source.as_ref();
10643 let range = range_from_lsp(diagnostic.range);
10644 let is_supporting = diagnostic
10645 .related_information
10646 .as_ref()
10647 .is_some_and(|infos| {
10648 infos.iter().any(|info| {
10649 primary_diagnostic_group_ids.contains_key(&(
10650 source,
10651 diagnostic.code.clone(),
10652 range_from_lsp(info.location.range),
10653 ))
10654 })
10655 });
10656
10657 let is_unnecessary = diagnostic
10658 .tags
10659 .as_ref()
10660 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10661
10662 let underline = self
10663 .language_server_adapter_for_id(server_id)
10664 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10665
10666 if is_supporting {
10667 supporting_diagnostics.insert(
10668 (source, diagnostic.code.clone(), range),
10669 (diagnostic.severity, is_unnecessary),
10670 );
10671 } else {
10672 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10673 let is_disk_based =
10674 source.is_some_and(|source| disk_based_sources.contains(source));
10675
10676 sources_by_group_id.insert(group_id, source);
10677 primary_diagnostic_group_ids
10678 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10679
10680 diagnostics.push(DiagnosticEntry {
10681 range,
10682 diagnostic: Diagnostic {
10683 source: diagnostic.source.clone(),
10684 source_kind,
10685 code: diagnostic.code.clone(),
10686 code_description: diagnostic
10687 .code_description
10688 .as_ref()
10689 .and_then(|d| d.href.clone()),
10690 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10691 markdown: adapter.as_ref().and_then(|adapter| {
10692 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10693 }),
10694 message: diagnostic.message.trim().to_string(),
10695 group_id,
10696 is_primary: true,
10697 is_disk_based,
10698 is_unnecessary,
10699 underline,
10700 data: diagnostic.data.clone(),
10701 },
10702 });
10703 if let Some(infos) = &diagnostic.related_information {
10704 for info in infos {
10705 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10706 let range = range_from_lsp(info.location.range);
10707 diagnostics.push(DiagnosticEntry {
10708 range,
10709 diagnostic: Diagnostic {
10710 source: diagnostic.source.clone(),
10711 source_kind,
10712 code: diagnostic.code.clone(),
10713 code_description: diagnostic
10714 .code_description
10715 .as_ref()
10716 .and_then(|d| d.href.clone()),
10717 severity: DiagnosticSeverity::INFORMATION,
10718 markdown: adapter.as_ref().and_then(|adapter| {
10719 adapter.diagnostic_message_to_markdown(&info.message)
10720 }),
10721 message: info.message.trim().to_string(),
10722 group_id,
10723 is_primary: false,
10724 is_disk_based,
10725 is_unnecessary: false,
10726 underline,
10727 data: diagnostic.data.clone(),
10728 },
10729 });
10730 }
10731 }
10732 }
10733 }
10734 }
10735
10736 for entry in &mut diagnostics {
10737 let diagnostic = &mut entry.diagnostic;
10738 if !diagnostic.is_primary {
10739 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10740 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10741 source,
10742 diagnostic.code.clone(),
10743 entry.range.clone(),
10744 )) {
10745 if let Some(severity) = severity {
10746 diagnostic.severity = severity;
10747 }
10748 diagnostic.is_unnecessary = is_unnecessary;
10749 }
10750 }
10751 }
10752
10753 DocumentDiagnostics {
10754 diagnostics,
10755 document_abs_path,
10756 version: lsp_diagnostics.version,
10757 }
10758 }
10759
10760 fn insert_newly_running_language_server(
10761 &mut self,
10762 adapter: Arc<CachedLspAdapter>,
10763 language_server: Arc<LanguageServer>,
10764 server_id: LanguageServerId,
10765 key: LanguageServerSeed,
10766 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10767 cx: &mut Context<Self>,
10768 ) {
10769 let Some(local) = self.as_local_mut() else {
10770 return;
10771 };
10772 // If the language server for this key doesn't match the server id, don't store the
10773 // server. Which will cause it to be dropped, killing the process
10774 if local
10775 .language_server_ids
10776 .get(&key)
10777 .map(|state| state.id != server_id)
10778 .unwrap_or(false)
10779 {
10780 return;
10781 }
10782
10783 // Update language_servers collection with Running variant of LanguageServerState
10784 // indicating that the server is up and running and ready
10785 let workspace_folders = workspace_folders.lock().clone();
10786 language_server.set_workspace_folders(workspace_folders);
10787
10788 local.language_servers.insert(
10789 server_id,
10790 LanguageServerState::Running {
10791 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10792 language_server.clone(),
10793 cx,
10794 ),
10795 adapter: adapter.clone(),
10796 server: language_server.clone(),
10797 simulate_disk_based_diagnostics_completion: None,
10798 },
10799 );
10800 local
10801 .languages
10802 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10803 if let Some(file_ops_caps) = language_server
10804 .capabilities()
10805 .workspace
10806 .as_ref()
10807 .and_then(|ws| ws.file_operations.as_ref())
10808 {
10809 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10810 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10811 if did_rename_caps.or(will_rename_caps).is_some() {
10812 let watcher = RenamePathsWatchedForServer::default()
10813 .with_did_rename_patterns(did_rename_caps)
10814 .with_will_rename_patterns(will_rename_caps);
10815 local
10816 .language_server_paths_watched_for_rename
10817 .insert(server_id, watcher);
10818 }
10819 }
10820
10821 self.language_server_statuses.insert(
10822 server_id,
10823 LanguageServerStatus {
10824 name: language_server.name(),
10825 pending_work: Default::default(),
10826 has_pending_diagnostic_updates: false,
10827 progress_tokens: Default::default(),
10828 worktree: Some(key.worktree_id),
10829 },
10830 );
10831
10832 cx.emit(LspStoreEvent::LanguageServerAdded(
10833 server_id,
10834 language_server.name(),
10835 Some(key.worktree_id),
10836 ));
10837 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
10838
10839 let server_capabilities = language_server.capabilities();
10840 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10841 downstream_client
10842 .send(proto::StartLanguageServer {
10843 project_id: *project_id,
10844 server: Some(proto::LanguageServer {
10845 id: server_id.to_proto(),
10846 name: language_server.name().to_string(),
10847 worktree_id: Some(key.worktree_id.to_proto()),
10848 }),
10849 capabilities: serde_json::to_string(&server_capabilities)
10850 .expect("serializing server LSP capabilities"),
10851 })
10852 .log_err();
10853 }
10854 self.lsp_server_capabilities
10855 .insert(server_id, server_capabilities);
10856
10857 // Tell the language server about every open buffer in the worktree that matches the language.
10858 // Also check for buffers in worktrees that reused this server
10859 let mut worktrees_using_server = vec![key.worktree_id];
10860 if let Some(local) = self.as_local() {
10861 // Find all worktrees that have this server in their language server tree
10862 for (worktree_id, servers) in &local.lsp_tree.instances {
10863 if *worktree_id != key.worktree_id {
10864 for server_map in servers.roots.values() {
10865 if server_map
10866 .values()
10867 .any(|(node, _)| node.id() == Some(server_id))
10868 {
10869 worktrees_using_server.push(*worktree_id);
10870 }
10871 }
10872 }
10873 }
10874 }
10875
10876 let mut buffer_paths_registered = Vec::new();
10877 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10878 let mut lsp_adapters = HashMap::default();
10879 for buffer_handle in buffer_store.buffers() {
10880 let buffer = buffer_handle.read(cx);
10881 let file = match File::from_dyn(buffer.file()) {
10882 Some(file) => file,
10883 None => continue,
10884 };
10885 let language = match buffer.language() {
10886 Some(language) => language,
10887 None => continue,
10888 };
10889
10890 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10891 || !lsp_adapters
10892 .entry(language.name())
10893 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
10894 .iter()
10895 .any(|a| a.name == key.name)
10896 {
10897 continue;
10898 }
10899 // didOpen
10900 let file = match file.as_local() {
10901 Some(file) => file,
10902 None => continue,
10903 };
10904
10905 let local = self.as_local_mut().unwrap();
10906
10907 let buffer_id = buffer.remote_id();
10908 if local.registered_buffers.contains_key(&buffer_id) {
10909 let versions = local
10910 .buffer_snapshots
10911 .entry(buffer_id)
10912 .or_default()
10913 .entry(server_id)
10914 .and_modify(|_| {
10915 assert!(
10916 false,
10917 "There should not be an existing snapshot for a newly inserted buffer"
10918 )
10919 })
10920 .or_insert_with(|| {
10921 vec![LspBufferSnapshot {
10922 version: 0,
10923 snapshot: buffer.text_snapshot(),
10924 }]
10925 });
10926
10927 let snapshot = versions.last().unwrap();
10928 let version = snapshot.version;
10929 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
10930 language_server.register_buffer(
10931 uri,
10932 adapter.language_id(&language.name()),
10933 version,
10934 buffer_handle.read(cx).text_with_original_line_endings(),
10935 );
10936 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
10937 local
10938 .buffers_opened_in_servers
10939 .entry(buffer_id)
10940 .or_default()
10941 .insert(server_id);
10942 }
10943 buffer_handle.update(cx, |buffer, cx| {
10944 buffer.set_completion_triggers(
10945 server_id,
10946 language_server
10947 .capabilities()
10948 .completion_provider
10949 .as_ref()
10950 .and_then(|provider| {
10951 provider
10952 .trigger_characters
10953 .as_ref()
10954 .map(|characters| characters.iter().cloned().collect())
10955 })
10956 .unwrap_or_default(),
10957 cx,
10958 )
10959 });
10960 }
10961 });
10962
10963 for (buffer_id, abs_path) in buffer_paths_registered {
10964 cx.emit(LspStoreEvent::LanguageServerUpdate {
10965 language_server_id: server_id,
10966 name: Some(adapter.name()),
10967 message: proto::update_language_server::Variant::RegisteredForBuffer(
10968 proto::RegisteredForBuffer {
10969 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
10970 buffer_id: buffer_id.to_proto(),
10971 },
10972 ),
10973 });
10974 }
10975
10976 cx.notify();
10977 }
10978
10979 pub fn language_servers_running_disk_based_diagnostics(
10980 &self,
10981 ) -> impl Iterator<Item = LanguageServerId> + '_ {
10982 self.language_server_statuses
10983 .iter()
10984 .filter_map(|(id, status)| {
10985 if status.has_pending_diagnostic_updates {
10986 Some(*id)
10987 } else {
10988 None
10989 }
10990 })
10991 }
10992
10993 pub(crate) fn cancel_language_server_work_for_buffers(
10994 &mut self,
10995 buffers: impl IntoIterator<Item = Entity<Buffer>>,
10996 cx: &mut Context<Self>,
10997 ) {
10998 if let Some((client, project_id)) = self.upstream_client() {
10999 let request = client.request(proto::CancelLanguageServerWork {
11000 project_id,
11001 work: Some(proto::cancel_language_server_work::Work::Buffers(
11002 proto::cancel_language_server_work::Buffers {
11003 buffer_ids: buffers
11004 .into_iter()
11005 .map(|b| b.read(cx).remote_id().to_proto())
11006 .collect(),
11007 },
11008 )),
11009 });
11010 cx.background_spawn(request).detach_and_log_err(cx);
11011 } else if let Some(local) = self.as_local() {
11012 let servers = buffers
11013 .into_iter()
11014 .flat_map(|buffer| {
11015 buffer.update(cx, |buffer, cx| {
11016 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11017 })
11018 })
11019 .collect::<HashSet<_>>();
11020 for server_id in servers {
11021 self.cancel_language_server_work(server_id, None, cx);
11022 }
11023 }
11024 }
11025
11026 pub(crate) fn cancel_language_server_work(
11027 &mut self,
11028 server_id: LanguageServerId,
11029 token_to_cancel: Option<String>,
11030 cx: &mut Context<Self>,
11031 ) {
11032 if let Some(local) = self.as_local() {
11033 let status = self.language_server_statuses.get(&server_id);
11034 let server = local.language_servers.get(&server_id);
11035 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11036 {
11037 for (token, progress) in &status.pending_work {
11038 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11039 && token != token_to_cancel
11040 {
11041 continue;
11042 }
11043 if progress.is_cancellable {
11044 server
11045 .notify::<lsp::notification::WorkDoneProgressCancel>(
11046 WorkDoneProgressCancelParams {
11047 token: lsp::NumberOrString::String(token.clone()),
11048 },
11049 )
11050 .ok();
11051 }
11052 }
11053 }
11054 } else if let Some((client, project_id)) = self.upstream_client() {
11055 let request = client.request(proto::CancelLanguageServerWork {
11056 project_id,
11057 work: Some(
11058 proto::cancel_language_server_work::Work::LanguageServerWork(
11059 proto::cancel_language_server_work::LanguageServerWork {
11060 language_server_id: server_id.to_proto(),
11061 token: token_to_cancel,
11062 },
11063 ),
11064 ),
11065 });
11066 cx.background_spawn(request).detach_and_log_err(cx);
11067 }
11068 }
11069
11070 fn register_supplementary_language_server(
11071 &mut self,
11072 id: LanguageServerId,
11073 name: LanguageServerName,
11074 server: Arc<LanguageServer>,
11075 cx: &mut Context<Self>,
11076 ) {
11077 if let Some(local) = self.as_local_mut() {
11078 local
11079 .supplementary_language_servers
11080 .insert(id, (name.clone(), server));
11081 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11082 }
11083 }
11084
11085 fn unregister_supplementary_language_server(
11086 &mut self,
11087 id: LanguageServerId,
11088 cx: &mut Context<Self>,
11089 ) {
11090 if let Some(local) = self.as_local_mut() {
11091 local.supplementary_language_servers.remove(&id);
11092 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11093 }
11094 }
11095
11096 pub(crate) fn supplementary_language_servers(
11097 &self,
11098 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11099 self.as_local().into_iter().flat_map(|local| {
11100 local
11101 .supplementary_language_servers
11102 .iter()
11103 .map(|(id, (name, _))| (*id, name.clone()))
11104 })
11105 }
11106
11107 pub fn language_server_adapter_for_id(
11108 &self,
11109 id: LanguageServerId,
11110 ) -> Option<Arc<CachedLspAdapter>> {
11111 self.as_local()
11112 .and_then(|local| local.language_servers.get(&id))
11113 .and_then(|language_server_state| match language_server_state {
11114 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11115 _ => None,
11116 })
11117 }
11118
11119 pub(super) fn update_local_worktree_language_servers(
11120 &mut self,
11121 worktree_handle: &Entity<Worktree>,
11122 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11123 cx: &mut Context<Self>,
11124 ) {
11125 if changes.is_empty() {
11126 return;
11127 }
11128
11129 let Some(local) = self.as_local() else { return };
11130
11131 local.prettier_store.update(cx, |prettier_store, cx| {
11132 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11133 });
11134
11135 let worktree_id = worktree_handle.read(cx).id();
11136 let mut language_server_ids = local
11137 .language_server_ids
11138 .iter()
11139 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11140 .collect::<Vec<_>>();
11141 language_server_ids.sort();
11142 language_server_ids.dedup();
11143
11144 // let abs_path = worktree_handle.read(cx).abs_path();
11145 for server_id in &language_server_ids {
11146 if let Some(LanguageServerState::Running { server, .. }) =
11147 local.language_servers.get(server_id)
11148 && let Some(watched_paths) = local
11149 .language_server_watched_paths
11150 .get(server_id)
11151 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11152 {
11153 let params = lsp::DidChangeWatchedFilesParams {
11154 changes: changes
11155 .iter()
11156 .filter_map(|(path, _, change)| {
11157 if !watched_paths.is_match(path.as_std_path()) {
11158 return None;
11159 }
11160 let typ = match change {
11161 PathChange::Loaded => return None,
11162 PathChange::Added => lsp::FileChangeType::CREATED,
11163 PathChange::Removed => lsp::FileChangeType::DELETED,
11164 PathChange::Updated => lsp::FileChangeType::CHANGED,
11165 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11166 };
11167 let uri = lsp::Uri::from_file_path(
11168 worktree_handle.read(cx).absolutize(&path),
11169 )
11170 .ok()?;
11171 Some(lsp::FileEvent { uri, typ })
11172 })
11173 .collect(),
11174 };
11175 if !params.changes.is_empty() {
11176 server
11177 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11178 .ok();
11179 }
11180 }
11181 }
11182 for (path, _, _) in changes {
11183 if let Some(file_name) = path.file_name()
11184 && local.watched_manifest_filenames.contains(file_name)
11185 {
11186 self.request_workspace_config_refresh();
11187 break;
11188 }
11189 }
11190 }
11191
11192 pub fn wait_for_remote_buffer(
11193 &mut self,
11194 id: BufferId,
11195 cx: &mut Context<Self>,
11196 ) -> Task<Result<Entity<Buffer>>> {
11197 self.buffer_store.update(cx, |buffer_store, cx| {
11198 buffer_store.wait_for_remote_buffer(id, cx)
11199 })
11200 }
11201
11202 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11203 let mut result = proto::Symbol {
11204 language_server_name: symbol.language_server_name.0.to_string(),
11205 source_worktree_id: symbol.source_worktree_id.to_proto(),
11206 language_server_id: symbol.source_language_server_id.to_proto(),
11207 name: symbol.name.clone(),
11208 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11209 start: Some(proto::PointUtf16 {
11210 row: symbol.range.start.0.row,
11211 column: symbol.range.start.0.column,
11212 }),
11213 end: Some(proto::PointUtf16 {
11214 row: symbol.range.end.0.row,
11215 column: symbol.range.end.0.column,
11216 }),
11217 worktree_id: Default::default(),
11218 path: Default::default(),
11219 signature: Default::default(),
11220 };
11221 match &symbol.path {
11222 SymbolLocation::InProject(path) => {
11223 result.worktree_id = path.worktree_id.to_proto();
11224 result.path = path.path.to_proto();
11225 }
11226 SymbolLocation::OutsideProject {
11227 abs_path,
11228 signature,
11229 } => {
11230 result.path = abs_path.to_string_lossy().into_owned();
11231 result.signature = signature.to_vec();
11232 }
11233 }
11234 result
11235 }
11236
11237 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11238 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11239 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11240 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11241
11242 let path = if serialized_symbol.signature.is_empty() {
11243 SymbolLocation::InProject(ProjectPath {
11244 worktree_id,
11245 path: RelPath::from_proto(&serialized_symbol.path)
11246 .context("invalid symbol path")?,
11247 })
11248 } else {
11249 SymbolLocation::OutsideProject {
11250 abs_path: Path::new(&serialized_symbol.path).into(),
11251 signature: serialized_symbol
11252 .signature
11253 .try_into()
11254 .map_err(|_| anyhow!("invalid signature"))?,
11255 }
11256 };
11257
11258 let start = serialized_symbol.start.context("invalid start")?;
11259 let end = serialized_symbol.end.context("invalid end")?;
11260 Ok(CoreSymbol {
11261 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11262 source_worktree_id,
11263 source_language_server_id: LanguageServerId::from_proto(
11264 serialized_symbol.language_server_id,
11265 ),
11266 path,
11267 name: serialized_symbol.name,
11268 range: Unclipped(PointUtf16::new(start.row, start.column))
11269 ..Unclipped(PointUtf16::new(end.row, end.column)),
11270 kind,
11271 })
11272 }
11273
11274 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11275 let mut serialized_completion = proto::Completion {
11276 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11277 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11278 new_text: completion.new_text.clone(),
11279 ..proto::Completion::default()
11280 };
11281 match &completion.source {
11282 CompletionSource::Lsp {
11283 insert_range,
11284 server_id,
11285 lsp_completion,
11286 lsp_defaults,
11287 resolved,
11288 } => {
11289 let (old_insert_start, old_insert_end) = insert_range
11290 .as_ref()
11291 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11292 .unzip();
11293
11294 serialized_completion.old_insert_start = old_insert_start;
11295 serialized_completion.old_insert_end = old_insert_end;
11296 serialized_completion.source = proto::completion::Source::Lsp as i32;
11297 serialized_completion.server_id = server_id.0 as u64;
11298 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11299 serialized_completion.lsp_defaults = lsp_defaults
11300 .as_deref()
11301 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11302 serialized_completion.resolved = *resolved;
11303 }
11304 CompletionSource::BufferWord {
11305 word_range,
11306 resolved,
11307 } => {
11308 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11309 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11310 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11311 serialized_completion.resolved = *resolved;
11312 }
11313 CompletionSource::Custom => {
11314 serialized_completion.source = proto::completion::Source::Custom as i32;
11315 serialized_completion.resolved = true;
11316 }
11317 CompletionSource::Dap { sort_text } => {
11318 serialized_completion.source = proto::completion::Source::Dap as i32;
11319 serialized_completion.sort_text = Some(sort_text.clone());
11320 }
11321 }
11322
11323 serialized_completion
11324 }
11325
11326 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11327 let old_replace_start = completion
11328 .old_replace_start
11329 .and_then(deserialize_anchor)
11330 .context("invalid old start")?;
11331 let old_replace_end = completion
11332 .old_replace_end
11333 .and_then(deserialize_anchor)
11334 .context("invalid old end")?;
11335 let insert_range = {
11336 match completion.old_insert_start.zip(completion.old_insert_end) {
11337 Some((start, end)) => {
11338 let start = deserialize_anchor(start).context("invalid insert old start")?;
11339 let end = deserialize_anchor(end).context("invalid insert old end")?;
11340 Some(start..end)
11341 }
11342 None => None,
11343 }
11344 };
11345 Ok(CoreCompletion {
11346 replace_range: old_replace_start..old_replace_end,
11347 new_text: completion.new_text,
11348 source: match proto::completion::Source::from_i32(completion.source) {
11349 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11350 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11351 insert_range,
11352 server_id: LanguageServerId::from_proto(completion.server_id),
11353 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11354 lsp_defaults: completion
11355 .lsp_defaults
11356 .as_deref()
11357 .map(serde_json::from_slice)
11358 .transpose()?,
11359 resolved: completion.resolved,
11360 },
11361 Some(proto::completion::Source::BufferWord) => {
11362 let word_range = completion
11363 .buffer_word_start
11364 .and_then(deserialize_anchor)
11365 .context("invalid buffer word start")?
11366 ..completion
11367 .buffer_word_end
11368 .and_then(deserialize_anchor)
11369 .context("invalid buffer word end")?;
11370 CompletionSource::BufferWord {
11371 word_range,
11372 resolved: completion.resolved,
11373 }
11374 }
11375 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11376 sort_text: completion
11377 .sort_text
11378 .context("expected sort text to exist")?,
11379 },
11380 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11381 },
11382 })
11383 }
11384
11385 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11386 let (kind, lsp_action) = match &action.lsp_action {
11387 LspAction::Action(code_action) => (
11388 proto::code_action::Kind::Action as i32,
11389 serde_json::to_vec(code_action).unwrap(),
11390 ),
11391 LspAction::Command(command) => (
11392 proto::code_action::Kind::Command as i32,
11393 serde_json::to_vec(command).unwrap(),
11394 ),
11395 LspAction::CodeLens(code_lens) => (
11396 proto::code_action::Kind::CodeLens as i32,
11397 serde_json::to_vec(code_lens).unwrap(),
11398 ),
11399 };
11400
11401 proto::CodeAction {
11402 server_id: action.server_id.0 as u64,
11403 start: Some(serialize_anchor(&action.range.start)),
11404 end: Some(serialize_anchor(&action.range.end)),
11405 lsp_action,
11406 kind,
11407 resolved: action.resolved,
11408 }
11409 }
11410
11411 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11412 let start = action
11413 .start
11414 .and_then(deserialize_anchor)
11415 .context("invalid start")?;
11416 let end = action
11417 .end
11418 .and_then(deserialize_anchor)
11419 .context("invalid end")?;
11420 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11421 Some(proto::code_action::Kind::Action) => {
11422 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11423 }
11424 Some(proto::code_action::Kind::Command) => {
11425 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11426 }
11427 Some(proto::code_action::Kind::CodeLens) => {
11428 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11429 }
11430 None => anyhow::bail!("Unknown action kind {}", action.kind),
11431 };
11432 Ok(CodeAction {
11433 server_id: LanguageServerId(action.server_id as usize),
11434 range: start..end,
11435 resolved: action.resolved,
11436 lsp_action,
11437 })
11438 }
11439
11440 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11441 match &formatting_result {
11442 Ok(_) => self.last_formatting_failure = None,
11443 Err(error) => {
11444 let error_string = format!("{error:#}");
11445 log::error!("Formatting failed: {error_string}");
11446 self.last_formatting_failure
11447 .replace(error_string.lines().join(" "));
11448 }
11449 }
11450 }
11451
11452 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11453 self.lsp_server_capabilities.remove(&for_server);
11454 for lsp_data in self.lsp_data.values_mut() {
11455 lsp_data.remove_server_data(for_server);
11456 }
11457 if let Some(local) = self.as_local_mut() {
11458 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11459 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11460 buffer_servers.remove(&for_server);
11461 }
11462 }
11463 }
11464
11465 pub fn result_id(
11466 &self,
11467 server_id: LanguageServerId,
11468 buffer_id: BufferId,
11469 cx: &App,
11470 ) -> Option<String> {
11471 let abs_path = self
11472 .buffer_store
11473 .read(cx)
11474 .get(buffer_id)
11475 .and_then(|b| File::from_dyn(b.read(cx).file()))
11476 .map(|f| f.abs_path(cx))?;
11477 self.as_local()?
11478 .buffer_pull_diagnostics_result_ids
11479 .get(&server_id)?
11480 .get(&abs_path)?
11481 .clone()
11482 }
11483
11484 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11485 let Some(local) = self.as_local() else {
11486 return HashMap::default();
11487 };
11488 local
11489 .buffer_pull_diagnostics_result_ids
11490 .get(&server_id)
11491 .into_iter()
11492 .flatten()
11493 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11494 .collect()
11495 }
11496
11497 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11498 if let Some(LanguageServerState::Running {
11499 workspace_refresh_task: Some(workspace_refresh_task),
11500 ..
11501 }) = self
11502 .as_local_mut()
11503 .and_then(|local| local.language_servers.get_mut(&server_id))
11504 {
11505 workspace_refresh_task.refresh_tx.try_send(()).ok();
11506 }
11507 }
11508
11509 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11510 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11511 return;
11512 };
11513 let Some(local) = self.as_local_mut() else {
11514 return;
11515 };
11516
11517 for server_id in buffer.update(cx, |buffer, cx| {
11518 local.language_server_ids_for_buffer(buffer, cx)
11519 }) {
11520 if let Some(LanguageServerState::Running {
11521 workspace_refresh_task: Some(workspace_refresh_task),
11522 ..
11523 }) = local.language_servers.get_mut(&server_id)
11524 {
11525 workspace_refresh_task.refresh_tx.try_send(()).ok();
11526 }
11527 }
11528 }
11529
11530 fn apply_workspace_diagnostic_report(
11531 &mut self,
11532 server_id: LanguageServerId,
11533 report: lsp::WorkspaceDiagnosticReportResult,
11534 cx: &mut Context<Self>,
11535 ) {
11536 let workspace_diagnostics =
11537 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11538 let mut unchanged_buffers = HashSet::default();
11539 let mut changed_buffers = HashSet::default();
11540 let workspace_diagnostics_updates = workspace_diagnostics
11541 .into_iter()
11542 .filter_map(
11543 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11544 LspPullDiagnostics::Response {
11545 server_id,
11546 uri,
11547 diagnostics,
11548 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11549 LspPullDiagnostics::Default => None,
11550 },
11551 )
11552 .fold(
11553 HashMap::default(),
11554 |mut acc, (server_id, uri, diagnostics, version)| {
11555 let (result_id, diagnostics) = match diagnostics {
11556 PulledDiagnostics::Unchanged { result_id } => {
11557 unchanged_buffers.insert(uri.clone());
11558 (Some(result_id), Vec::new())
11559 }
11560 PulledDiagnostics::Changed {
11561 result_id,
11562 diagnostics,
11563 } => {
11564 changed_buffers.insert(uri.clone());
11565 (result_id, diagnostics)
11566 }
11567 };
11568 let disk_based_sources = Cow::Owned(
11569 self.language_server_adapter_for_id(server_id)
11570 .as_ref()
11571 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11572 .unwrap_or(&[])
11573 .to_vec(),
11574 );
11575 acc.entry(server_id)
11576 .or_insert_with(Vec::new)
11577 .push(DocumentDiagnosticsUpdate {
11578 server_id,
11579 diagnostics: lsp::PublishDiagnosticsParams {
11580 uri,
11581 diagnostics,
11582 version,
11583 },
11584 result_id,
11585 disk_based_sources,
11586 });
11587 acc
11588 },
11589 );
11590
11591 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11592 self.merge_lsp_diagnostics(
11593 DiagnosticSourceKind::Pulled,
11594 diagnostic_updates,
11595 |buffer, old_diagnostic, cx| {
11596 File::from_dyn(buffer.file())
11597 .and_then(|file| {
11598 let abs_path = file.as_local()?.abs_path(cx);
11599 lsp::Uri::from_file_path(abs_path).ok()
11600 })
11601 .is_none_or(|buffer_uri| {
11602 unchanged_buffers.contains(&buffer_uri)
11603 || match old_diagnostic.source_kind {
11604 DiagnosticSourceKind::Pulled => {
11605 !changed_buffers.contains(&buffer_uri)
11606 }
11607 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11608 true
11609 }
11610 }
11611 })
11612 },
11613 cx,
11614 )
11615 .log_err();
11616 }
11617 }
11618
11619 fn register_server_capabilities(
11620 &mut self,
11621 server_id: LanguageServerId,
11622 params: lsp::RegistrationParams,
11623 cx: &mut Context<Self>,
11624 ) -> anyhow::Result<()> {
11625 let server = self
11626 .language_server_for_id(server_id)
11627 .with_context(|| format!("no server {server_id} found"))?;
11628 for reg in params.registrations {
11629 match reg.method.as_str() {
11630 "workspace/didChangeWatchedFiles" => {
11631 if let Some(options) = reg.register_options {
11632 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11633 let caps = serde_json::from_value(options)?;
11634 local_lsp_store
11635 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11636 true
11637 } else {
11638 false
11639 };
11640 if notify {
11641 notify_server_capabilities_updated(&server, cx);
11642 }
11643 }
11644 }
11645 "workspace/didChangeConfiguration" => {
11646 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11647 }
11648 "workspace/didChangeWorkspaceFolders" => {
11649 // In this case register options is an empty object, we can ignore it
11650 let caps = lsp::WorkspaceFoldersServerCapabilities {
11651 supported: Some(true),
11652 change_notifications: Some(OneOf::Right(reg.id)),
11653 };
11654 server.update_capabilities(|capabilities| {
11655 capabilities
11656 .workspace
11657 .get_or_insert_default()
11658 .workspace_folders = Some(caps);
11659 });
11660 notify_server_capabilities_updated(&server, cx);
11661 }
11662 "workspace/symbol" => {
11663 let options = parse_register_capabilities(reg)?;
11664 server.update_capabilities(|capabilities| {
11665 capabilities.workspace_symbol_provider = Some(options);
11666 });
11667 notify_server_capabilities_updated(&server, cx);
11668 }
11669 "workspace/fileOperations" => {
11670 if let Some(options) = reg.register_options {
11671 let caps = serde_json::from_value(options)?;
11672 server.update_capabilities(|capabilities| {
11673 capabilities
11674 .workspace
11675 .get_or_insert_default()
11676 .file_operations = Some(caps);
11677 });
11678 notify_server_capabilities_updated(&server, cx);
11679 }
11680 }
11681 "workspace/executeCommand" => {
11682 if let Some(options) = reg.register_options {
11683 let options = serde_json::from_value(options)?;
11684 server.update_capabilities(|capabilities| {
11685 capabilities.execute_command_provider = Some(options);
11686 });
11687 notify_server_capabilities_updated(&server, cx);
11688 }
11689 }
11690 "textDocument/rangeFormatting" => {
11691 let options = parse_register_capabilities(reg)?;
11692 server.update_capabilities(|capabilities| {
11693 capabilities.document_range_formatting_provider = Some(options);
11694 });
11695 notify_server_capabilities_updated(&server, cx);
11696 }
11697 "textDocument/onTypeFormatting" => {
11698 if let Some(options) = reg
11699 .register_options
11700 .map(serde_json::from_value)
11701 .transpose()?
11702 {
11703 server.update_capabilities(|capabilities| {
11704 capabilities.document_on_type_formatting_provider = Some(options);
11705 });
11706 notify_server_capabilities_updated(&server, cx);
11707 }
11708 }
11709 "textDocument/formatting" => {
11710 let options = parse_register_capabilities(reg)?;
11711 server.update_capabilities(|capabilities| {
11712 capabilities.document_formatting_provider = Some(options);
11713 });
11714 notify_server_capabilities_updated(&server, cx);
11715 }
11716 "textDocument/rename" => {
11717 let options = parse_register_capabilities(reg)?;
11718 server.update_capabilities(|capabilities| {
11719 capabilities.rename_provider = Some(options);
11720 });
11721 notify_server_capabilities_updated(&server, cx);
11722 }
11723 "textDocument/inlayHint" => {
11724 let options = parse_register_capabilities(reg)?;
11725 server.update_capabilities(|capabilities| {
11726 capabilities.inlay_hint_provider = Some(options);
11727 });
11728 notify_server_capabilities_updated(&server, cx);
11729 }
11730 "textDocument/documentSymbol" => {
11731 let options = parse_register_capabilities(reg)?;
11732 server.update_capabilities(|capabilities| {
11733 capabilities.document_symbol_provider = Some(options);
11734 });
11735 notify_server_capabilities_updated(&server, cx);
11736 }
11737 "textDocument/codeAction" => {
11738 let options = parse_register_capabilities(reg)?;
11739 let provider = match options {
11740 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11741 OneOf::Right(caps) => caps,
11742 };
11743 server.update_capabilities(|capabilities| {
11744 capabilities.code_action_provider = Some(provider);
11745 });
11746 notify_server_capabilities_updated(&server, cx);
11747 }
11748 "textDocument/definition" => {
11749 let options = parse_register_capabilities(reg)?;
11750 server.update_capabilities(|capabilities| {
11751 capabilities.definition_provider = Some(options);
11752 });
11753 notify_server_capabilities_updated(&server, cx);
11754 }
11755 "textDocument/completion" => {
11756 if let Some(caps) = reg
11757 .register_options
11758 .map(serde_json::from_value)
11759 .transpose()?
11760 {
11761 server.update_capabilities(|capabilities| {
11762 capabilities.completion_provider = Some(caps);
11763 });
11764 notify_server_capabilities_updated(&server, cx);
11765 }
11766 }
11767 "textDocument/hover" => {
11768 let options = parse_register_capabilities(reg)?;
11769 let provider = match options {
11770 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11771 OneOf::Right(caps) => caps,
11772 };
11773 server.update_capabilities(|capabilities| {
11774 capabilities.hover_provider = Some(provider);
11775 });
11776 notify_server_capabilities_updated(&server, cx);
11777 }
11778 "textDocument/signatureHelp" => {
11779 if let Some(caps) = reg
11780 .register_options
11781 .map(serde_json::from_value)
11782 .transpose()?
11783 {
11784 server.update_capabilities(|capabilities| {
11785 capabilities.signature_help_provider = Some(caps);
11786 });
11787 notify_server_capabilities_updated(&server, cx);
11788 }
11789 }
11790 "textDocument/didChange" => {
11791 if let Some(sync_kind) = reg
11792 .register_options
11793 .and_then(|opts| opts.get("syncKind").cloned())
11794 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11795 .transpose()?
11796 {
11797 server.update_capabilities(|capabilities| {
11798 let mut sync_options =
11799 Self::take_text_document_sync_options(capabilities);
11800 sync_options.change = Some(sync_kind);
11801 capabilities.text_document_sync =
11802 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11803 });
11804 notify_server_capabilities_updated(&server, cx);
11805 }
11806 }
11807 "textDocument/didSave" => {
11808 if let Some(include_text) = reg
11809 .register_options
11810 .map(|opts| {
11811 let transpose = opts
11812 .get("includeText")
11813 .cloned()
11814 .map(serde_json::from_value::<Option<bool>>)
11815 .transpose();
11816 match transpose {
11817 Ok(value) => Ok(value.flatten()),
11818 Err(e) => Err(e),
11819 }
11820 })
11821 .transpose()?
11822 {
11823 server.update_capabilities(|capabilities| {
11824 let mut sync_options =
11825 Self::take_text_document_sync_options(capabilities);
11826 sync_options.save =
11827 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11828 include_text,
11829 }));
11830 capabilities.text_document_sync =
11831 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11832 });
11833 notify_server_capabilities_updated(&server, cx);
11834 }
11835 }
11836 "textDocument/codeLens" => {
11837 if let Some(caps) = reg
11838 .register_options
11839 .map(serde_json::from_value)
11840 .transpose()?
11841 {
11842 server.update_capabilities(|capabilities| {
11843 capabilities.code_lens_provider = Some(caps);
11844 });
11845 notify_server_capabilities_updated(&server, cx);
11846 }
11847 }
11848 "textDocument/diagnostic" => {
11849 if let Some(caps) = reg
11850 .register_options
11851 .map(serde_json::from_value)
11852 .transpose()?
11853 {
11854 let state = self
11855 .as_local_mut()
11856 .context("Expected LSP Store to be local")?
11857 .language_servers
11858 .get_mut(&server_id)
11859 .context("Could not obtain Language Servers state")?;
11860 server.update_capabilities(|capabilities| {
11861 capabilities.diagnostic_provider = Some(caps);
11862 });
11863 if let LanguageServerState::Running {
11864 workspace_refresh_task,
11865 ..
11866 } = state
11867 && workspace_refresh_task.is_none()
11868 {
11869 *workspace_refresh_task =
11870 lsp_workspace_diagnostics_refresh(server.clone(), cx)
11871 }
11872
11873 notify_server_capabilities_updated(&server, cx);
11874 }
11875 }
11876 "textDocument/documentColor" => {
11877 let options = parse_register_capabilities(reg)?;
11878 let provider = match options {
11879 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
11880 OneOf::Right(caps) => caps,
11881 };
11882 server.update_capabilities(|capabilities| {
11883 capabilities.color_provider = Some(provider);
11884 });
11885 notify_server_capabilities_updated(&server, cx);
11886 }
11887 _ => log::warn!("unhandled capability registration: {reg:?}"),
11888 }
11889 }
11890
11891 Ok(())
11892 }
11893
11894 fn unregister_server_capabilities(
11895 &mut self,
11896 server_id: LanguageServerId,
11897 params: lsp::UnregistrationParams,
11898 cx: &mut Context<Self>,
11899 ) -> anyhow::Result<()> {
11900 let server = self
11901 .language_server_for_id(server_id)
11902 .with_context(|| format!("no server {server_id} found"))?;
11903 for unreg in params.unregisterations.iter() {
11904 match unreg.method.as_str() {
11905 "workspace/didChangeWatchedFiles" => {
11906 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11907 local_lsp_store
11908 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11909 true
11910 } else {
11911 false
11912 };
11913 if notify {
11914 notify_server_capabilities_updated(&server, cx);
11915 }
11916 }
11917 "workspace/didChangeConfiguration" => {
11918 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11919 }
11920 "workspace/didChangeWorkspaceFolders" => {
11921 server.update_capabilities(|capabilities| {
11922 capabilities
11923 .workspace
11924 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11925 workspace_folders: None,
11926 file_operations: None,
11927 })
11928 .workspace_folders = None;
11929 });
11930 notify_server_capabilities_updated(&server, cx);
11931 }
11932 "workspace/symbol" => {
11933 server.update_capabilities(|capabilities| {
11934 capabilities.workspace_symbol_provider = None
11935 });
11936 notify_server_capabilities_updated(&server, cx);
11937 }
11938 "workspace/fileOperations" => {
11939 server.update_capabilities(|capabilities| {
11940 capabilities
11941 .workspace
11942 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11943 workspace_folders: None,
11944 file_operations: None,
11945 })
11946 .file_operations = None;
11947 });
11948 notify_server_capabilities_updated(&server, cx);
11949 }
11950 "workspace/executeCommand" => {
11951 server.update_capabilities(|capabilities| {
11952 capabilities.execute_command_provider = None;
11953 });
11954 notify_server_capabilities_updated(&server, cx);
11955 }
11956 "textDocument/rangeFormatting" => {
11957 server.update_capabilities(|capabilities| {
11958 capabilities.document_range_formatting_provider = None
11959 });
11960 notify_server_capabilities_updated(&server, cx);
11961 }
11962 "textDocument/onTypeFormatting" => {
11963 server.update_capabilities(|capabilities| {
11964 capabilities.document_on_type_formatting_provider = None;
11965 });
11966 notify_server_capabilities_updated(&server, cx);
11967 }
11968 "textDocument/formatting" => {
11969 server.update_capabilities(|capabilities| {
11970 capabilities.document_formatting_provider = None;
11971 });
11972 notify_server_capabilities_updated(&server, cx);
11973 }
11974 "textDocument/rename" => {
11975 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11976 notify_server_capabilities_updated(&server, cx);
11977 }
11978 "textDocument/codeAction" => {
11979 server.update_capabilities(|capabilities| {
11980 capabilities.code_action_provider = None;
11981 });
11982 notify_server_capabilities_updated(&server, cx);
11983 }
11984 "textDocument/definition" => {
11985 server.update_capabilities(|capabilities| {
11986 capabilities.definition_provider = None;
11987 });
11988 notify_server_capabilities_updated(&server, cx);
11989 }
11990 "textDocument/completion" => {
11991 server.update_capabilities(|capabilities| {
11992 capabilities.completion_provider = None;
11993 });
11994 notify_server_capabilities_updated(&server, cx);
11995 }
11996 "textDocument/hover" => {
11997 server.update_capabilities(|capabilities| {
11998 capabilities.hover_provider = None;
11999 });
12000 notify_server_capabilities_updated(&server, cx);
12001 }
12002 "textDocument/signatureHelp" => {
12003 server.update_capabilities(|capabilities| {
12004 capabilities.signature_help_provider = None;
12005 });
12006 notify_server_capabilities_updated(&server, cx);
12007 }
12008 "textDocument/didChange" => {
12009 server.update_capabilities(|capabilities| {
12010 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12011 sync_options.change = None;
12012 capabilities.text_document_sync =
12013 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12014 });
12015 notify_server_capabilities_updated(&server, cx);
12016 }
12017 "textDocument/didSave" => {
12018 server.update_capabilities(|capabilities| {
12019 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12020 sync_options.save = None;
12021 capabilities.text_document_sync =
12022 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12023 });
12024 notify_server_capabilities_updated(&server, cx);
12025 }
12026 "textDocument/codeLens" => {
12027 server.update_capabilities(|capabilities| {
12028 capabilities.code_lens_provider = None;
12029 });
12030 notify_server_capabilities_updated(&server, cx);
12031 }
12032 "textDocument/diagnostic" => {
12033 server.update_capabilities(|capabilities| {
12034 capabilities.diagnostic_provider = None;
12035 });
12036 let state = self
12037 .as_local_mut()
12038 .context("Expected LSP Store to be local")?
12039 .language_servers
12040 .get_mut(&server_id)
12041 .context("Could not obtain Language Servers state")?;
12042 if let LanguageServerState::Running {
12043 workspace_refresh_task,
12044 ..
12045 } = state
12046 {
12047 _ = workspace_refresh_task.take();
12048 }
12049 notify_server_capabilities_updated(&server, cx);
12050 }
12051 "textDocument/documentColor" => {
12052 server.update_capabilities(|capabilities| {
12053 capabilities.color_provider = None;
12054 });
12055 notify_server_capabilities_updated(&server, cx);
12056 }
12057 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12058 }
12059 }
12060
12061 Ok(())
12062 }
12063
12064 async fn deduplicate_range_based_lsp_requests<T>(
12065 lsp_store: &Entity<Self>,
12066 server_id: Option<LanguageServerId>,
12067 lsp_request_id: LspRequestId,
12068 proto_request: &T::ProtoRequest,
12069 range: Range<Anchor>,
12070 cx: &mut AsyncApp,
12071 ) -> Result<()>
12072 where
12073 T: LspCommand,
12074 T::ProtoRequest: proto::LspRequestMessage,
12075 {
12076 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12077 let version = deserialize_version(proto_request.buffer_version());
12078 let buffer = lsp_store.update(cx, |this, cx| {
12079 this.buffer_store.read(cx).get_existing(buffer_id)
12080 })??;
12081 buffer
12082 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12083 .await?;
12084 lsp_store.update(cx, |lsp_store, cx| {
12085 let lsp_data = lsp_store
12086 .lsp_data
12087 .entry(buffer_id)
12088 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12089 let chunks_queried_for = lsp_data
12090 .inlay_hints
12091 .applicable_chunks(&[range])
12092 .collect::<Vec<_>>();
12093 match chunks_queried_for.as_slice() {
12094 &[chunk] => {
12095 let key = LspKey {
12096 request_type: TypeId::of::<T>(),
12097 server_queried: server_id,
12098 };
12099 let previous_request = lsp_data
12100 .chunk_lsp_requests
12101 .entry(key)
12102 .or_default()
12103 .insert(chunk, lsp_request_id);
12104 if let Some((previous_request, running_requests)) =
12105 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12106 {
12107 running_requests.remove(&previous_request);
12108 }
12109 }
12110 _ambiguous_chunks => {
12111 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12112 // there, a buffer version-based check will be performed and outdated requests discarded.
12113 }
12114 }
12115 anyhow::Ok(())
12116 })??;
12117
12118 Ok(())
12119 }
12120
12121 async fn query_lsp_locally<T>(
12122 lsp_store: Entity<Self>,
12123 for_server_id: Option<LanguageServerId>,
12124 sender_id: proto::PeerId,
12125 lsp_request_id: LspRequestId,
12126 proto_request: T::ProtoRequest,
12127 position: Option<Anchor>,
12128 cx: &mut AsyncApp,
12129 ) -> Result<()>
12130 where
12131 T: LspCommand + Clone,
12132 T::ProtoRequest: proto::LspRequestMessage,
12133 <T::ProtoRequest as proto::RequestMessage>::Response:
12134 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12135 {
12136 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12137 let version = deserialize_version(proto_request.buffer_version());
12138 let buffer = lsp_store.update(cx, |this, cx| {
12139 this.buffer_store.read(cx).get_existing(buffer_id)
12140 })??;
12141 buffer
12142 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12143 .await?;
12144 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12145 let request =
12146 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12147 let key = LspKey {
12148 request_type: TypeId::of::<T>(),
12149 server_queried: for_server_id,
12150 };
12151 lsp_store.update(cx, |lsp_store, cx| {
12152 let request_task = match for_server_id {
12153 Some(server_id) => {
12154 let server_task = lsp_store.request_lsp(
12155 buffer.clone(),
12156 LanguageServerToQuery::Other(server_id),
12157 request.clone(),
12158 cx,
12159 );
12160 cx.background_spawn(async move {
12161 let mut responses = Vec::new();
12162 match server_task.await {
12163 Ok(response) => responses.push((server_id, response)),
12164 Err(e) => log::error!(
12165 "Error handling response for request {request:?}: {e:#}"
12166 ),
12167 }
12168 responses
12169 })
12170 }
12171 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12172 };
12173 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12174 if T::ProtoRequest::stop_previous_requests() {
12175 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12176 lsp_requests.clear();
12177 }
12178 }
12179 lsp_data.lsp_requests.entry(key).or_default().insert(
12180 lsp_request_id,
12181 cx.spawn(async move |lsp_store, cx| {
12182 let response = request_task.await;
12183 lsp_store
12184 .update(cx, |lsp_store, cx| {
12185 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12186 {
12187 let response = response
12188 .into_iter()
12189 .map(|(server_id, response)| {
12190 (
12191 server_id.to_proto(),
12192 T::response_to_proto(
12193 response,
12194 lsp_store,
12195 sender_id,
12196 &buffer_version,
12197 cx,
12198 )
12199 .into(),
12200 )
12201 })
12202 .collect::<HashMap<_, _>>();
12203 match client.send_lsp_response::<T::ProtoRequest>(
12204 project_id,
12205 lsp_request_id,
12206 response,
12207 ) {
12208 Ok(()) => {}
12209 Err(e) => {
12210 log::error!("Failed to send LSP response: {e:#}",)
12211 }
12212 }
12213 }
12214 })
12215 .ok();
12216 }),
12217 );
12218 })?;
12219 Ok(())
12220 }
12221
12222 fn take_text_document_sync_options(
12223 capabilities: &mut lsp::ServerCapabilities,
12224 ) -> lsp::TextDocumentSyncOptions {
12225 match capabilities.text_document_sync.take() {
12226 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12227 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12228 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12229 sync_options.change = Some(sync_kind);
12230 sync_options
12231 }
12232 None => lsp::TextDocumentSyncOptions::default(),
12233 }
12234 }
12235
12236 #[cfg(any(test, feature = "test-support"))]
12237 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12238 Some(
12239 self.lsp_data
12240 .get_mut(&buffer_id)?
12241 .code_lens
12242 .take()?
12243 .update
12244 .take()?
12245 .1,
12246 )
12247 }
12248
12249 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12250 self.downstream_client.clone()
12251 }
12252
12253 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12254 self.worktree_store.clone()
12255 }
12256
12257 /// Gets what's stored in the LSP data for the given buffer.
12258 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12259 self.lsp_data.get_mut(&buffer_id)
12260 }
12261
12262 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12263 /// new [`BufferLspData`] will be created to replace the previous state.
12264 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12265 let (buffer_id, buffer_version) =
12266 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12267 let lsp_data = self
12268 .lsp_data
12269 .entry(buffer_id)
12270 .or_insert_with(|| BufferLspData::new(buffer, cx));
12271 if buffer_version.changed_since(&lsp_data.buffer_version) {
12272 *lsp_data = BufferLspData::new(buffer, cx);
12273 }
12274 lsp_data
12275 }
12276}
12277
12278// Registration with registerOptions as null, should fallback to true.
12279// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12280fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12281 reg: lsp::Registration,
12282) -> Result<OneOf<bool, T>> {
12283 Ok(match reg.register_options {
12284 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12285 None => OneOf::Left(true),
12286 })
12287}
12288
12289fn subscribe_to_binary_statuses(
12290 languages: &Arc<LanguageRegistry>,
12291 cx: &mut Context<'_, LspStore>,
12292) -> Task<()> {
12293 let mut server_statuses = languages.language_server_binary_statuses();
12294 cx.spawn(async move |lsp_store, cx| {
12295 while let Some((server_name, binary_status)) = server_statuses.next().await {
12296 if lsp_store
12297 .update(cx, |_, cx| {
12298 let mut message = None;
12299 let binary_status = match binary_status {
12300 BinaryStatus::None => proto::ServerBinaryStatus::None,
12301 BinaryStatus::CheckingForUpdate => {
12302 proto::ServerBinaryStatus::CheckingForUpdate
12303 }
12304 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12305 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12306 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12307 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12308 BinaryStatus::Failed { error } => {
12309 message = Some(error);
12310 proto::ServerBinaryStatus::Failed
12311 }
12312 };
12313 cx.emit(LspStoreEvent::LanguageServerUpdate {
12314 // Binary updates are about the binary that might not have any language server id at that point.
12315 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12316 language_server_id: LanguageServerId(0),
12317 name: Some(server_name),
12318 message: proto::update_language_server::Variant::StatusUpdate(
12319 proto::StatusUpdate {
12320 message,
12321 status: Some(proto::status_update::Status::Binary(
12322 binary_status as i32,
12323 )),
12324 },
12325 ),
12326 });
12327 })
12328 .is_err()
12329 {
12330 break;
12331 }
12332 }
12333 })
12334}
12335
12336fn lsp_workspace_diagnostics_refresh(
12337 server: Arc<LanguageServer>,
12338 cx: &mut Context<'_, LspStore>,
12339) -> Option<WorkspaceRefreshTask> {
12340 let identifier = match server.capabilities().diagnostic_provider? {
12341 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12342 if !diagnostic_options.workspace_diagnostics {
12343 return None;
12344 }
12345 diagnostic_options.identifier
12346 }
12347 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12348 let diagnostic_options = registration_options.diagnostic_options;
12349 if !diagnostic_options.workspace_diagnostics {
12350 return None;
12351 }
12352 diagnostic_options.identifier
12353 }
12354 };
12355
12356 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12357 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12358 refresh_tx.try_send(()).ok();
12359
12360 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12361 let mut attempts = 0;
12362 let max_attempts = 50;
12363 let mut requests = 0;
12364
12365 loop {
12366 let Some(()) = refresh_rx.recv().await else {
12367 return;
12368 };
12369
12370 'request: loop {
12371 requests += 1;
12372 if attempts > max_attempts {
12373 log::error!(
12374 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12375 );
12376 return;
12377 }
12378 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12379 cx.background_executor()
12380 .timer(Duration::from_millis(backoff_millis))
12381 .await;
12382 attempts += 1;
12383
12384 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12385 lsp_store
12386 .all_result_ids(server.server_id())
12387 .into_iter()
12388 .filter_map(|(abs_path, result_id)| {
12389 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12390 Some(lsp::PreviousResultId {
12391 uri,
12392 value: result_id,
12393 })
12394 })
12395 .collect()
12396 }) else {
12397 return;
12398 };
12399
12400 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12401
12402 progress_rx.try_recv().ok();
12403 let timer =
12404 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12405 let progress = pin!(progress_rx.recv().fuse());
12406 let response_result = server
12407 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12408 lsp::WorkspaceDiagnosticParams {
12409 previous_result_ids,
12410 identifier: identifier.clone(),
12411 work_done_progress_params: Default::default(),
12412 partial_result_params: lsp::PartialResultParams {
12413 partial_result_token: Some(lsp::ProgressToken::String(token)),
12414 },
12415 },
12416 select(timer, progress).then(|either| match either {
12417 Either::Left((message, ..)) => ready(message).left_future(),
12418 Either::Right(..) => pending::<String>().right_future(),
12419 }),
12420 )
12421 .await;
12422
12423 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12424 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12425 match response_result {
12426 ConnectionResult::Timeout => {
12427 log::error!("Timeout during workspace diagnostics pull");
12428 continue 'request;
12429 }
12430 ConnectionResult::ConnectionReset => {
12431 log::error!("Server closed a workspace diagnostics pull request");
12432 continue 'request;
12433 }
12434 ConnectionResult::Result(Err(e)) => {
12435 log::error!("Error during workspace diagnostics pull: {e:#}");
12436 break 'request;
12437 }
12438 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12439 attempts = 0;
12440 if lsp_store
12441 .update(cx, |lsp_store, cx| {
12442 lsp_store.apply_workspace_diagnostic_report(
12443 server.server_id(),
12444 pulled_diagnostics,
12445 cx,
12446 )
12447 })
12448 .is_err()
12449 {
12450 return;
12451 }
12452 break 'request;
12453 }
12454 }
12455 }
12456 }
12457 });
12458
12459 Some(WorkspaceRefreshTask {
12460 refresh_tx,
12461 progress_tx,
12462 task: workspace_query_language_server,
12463 })
12464}
12465
12466fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12467 let CompletionSource::BufferWord {
12468 word_range,
12469 resolved,
12470 } = &mut completion.source
12471 else {
12472 return;
12473 };
12474 if *resolved {
12475 return;
12476 }
12477
12478 if completion.new_text
12479 != snapshot
12480 .text_for_range(word_range.clone())
12481 .collect::<String>()
12482 {
12483 return;
12484 }
12485
12486 let mut offset = 0;
12487 for chunk in snapshot.chunks(word_range.clone(), true) {
12488 let end_offset = offset + chunk.text.len();
12489 if let Some(highlight_id) = chunk.syntax_highlight_id {
12490 completion
12491 .label
12492 .runs
12493 .push((offset..end_offset, highlight_id));
12494 }
12495 offset = end_offset;
12496 }
12497 *resolved = true;
12498}
12499
12500impl EventEmitter<LspStoreEvent> for LspStore {}
12501
12502fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12503 hover
12504 .contents
12505 .retain(|hover_block| !hover_block.text.trim().is_empty());
12506 if hover.contents.is_empty() {
12507 None
12508 } else {
12509 Some(hover)
12510 }
12511}
12512
12513async fn populate_labels_for_completions(
12514 new_completions: Vec<CoreCompletion>,
12515 language: Option<Arc<Language>>,
12516 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12517) -> Vec<Completion> {
12518 let lsp_completions = new_completions
12519 .iter()
12520 .filter_map(|new_completion| {
12521 new_completion
12522 .source
12523 .lsp_completion(true)
12524 .map(|lsp_completion| lsp_completion.into_owned())
12525 })
12526 .collect::<Vec<_>>();
12527
12528 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12529 lsp_adapter
12530 .labels_for_completions(&lsp_completions, language)
12531 .await
12532 .log_err()
12533 .unwrap_or_default()
12534 } else {
12535 Vec::new()
12536 }
12537 .into_iter()
12538 .fuse();
12539
12540 let mut completions = Vec::new();
12541 for completion in new_completions {
12542 match completion.source.lsp_completion(true) {
12543 Some(lsp_completion) => {
12544 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12545
12546 let mut label = labels.next().flatten().unwrap_or_else(|| {
12547 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12548 });
12549 ensure_uniform_list_compatible_label(&mut label);
12550 completions.push(Completion {
12551 label,
12552 documentation,
12553 replace_range: completion.replace_range,
12554 new_text: completion.new_text,
12555 insert_text_mode: lsp_completion.insert_text_mode,
12556 source: completion.source,
12557 icon_path: None,
12558 confirm: None,
12559 match_start: None,
12560 });
12561 }
12562 None => {
12563 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12564 ensure_uniform_list_compatible_label(&mut label);
12565 completions.push(Completion {
12566 label,
12567 documentation: None,
12568 replace_range: completion.replace_range,
12569 new_text: completion.new_text,
12570 source: completion.source,
12571 insert_text_mode: None,
12572 icon_path: None,
12573 confirm: None,
12574 match_start: None,
12575 });
12576 }
12577 }
12578 }
12579 completions
12580}
12581
12582#[derive(Debug)]
12583pub enum LanguageServerToQuery {
12584 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12585 FirstCapable,
12586 /// Query a specific language server.
12587 Other(LanguageServerId),
12588}
12589
12590#[derive(Default)]
12591struct RenamePathsWatchedForServer {
12592 did_rename: Vec<RenameActionPredicate>,
12593 will_rename: Vec<RenameActionPredicate>,
12594}
12595
12596impl RenamePathsWatchedForServer {
12597 fn with_did_rename_patterns(
12598 mut self,
12599 did_rename: Option<&FileOperationRegistrationOptions>,
12600 ) -> Self {
12601 if let Some(did_rename) = did_rename {
12602 self.did_rename = did_rename
12603 .filters
12604 .iter()
12605 .filter_map(|filter| filter.try_into().log_err())
12606 .collect();
12607 }
12608 self
12609 }
12610 fn with_will_rename_patterns(
12611 mut self,
12612 will_rename: Option<&FileOperationRegistrationOptions>,
12613 ) -> Self {
12614 if let Some(will_rename) = will_rename {
12615 self.will_rename = will_rename
12616 .filters
12617 .iter()
12618 .filter_map(|filter| filter.try_into().log_err())
12619 .collect();
12620 }
12621 self
12622 }
12623
12624 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12625 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12626 }
12627 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12628 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12629 }
12630}
12631
12632impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12633 type Error = globset::Error;
12634 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12635 Ok(Self {
12636 kind: ops.pattern.matches.clone(),
12637 glob: GlobBuilder::new(&ops.pattern.glob)
12638 .case_insensitive(
12639 ops.pattern
12640 .options
12641 .as_ref()
12642 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12643 )
12644 .build()?
12645 .compile_matcher(),
12646 })
12647 }
12648}
12649struct RenameActionPredicate {
12650 glob: GlobMatcher,
12651 kind: Option<FileOperationPatternKind>,
12652}
12653
12654impl RenameActionPredicate {
12655 // Returns true if language server should be notified
12656 fn eval(&self, path: &str, is_dir: bool) -> bool {
12657 self.kind.as_ref().is_none_or(|kind| {
12658 let expected_kind = if is_dir {
12659 FileOperationPatternKind::Folder
12660 } else {
12661 FileOperationPatternKind::File
12662 };
12663 kind == &expected_kind
12664 }) && self.glob.is_match(path)
12665 }
12666}
12667
12668#[derive(Default)]
12669struct LanguageServerWatchedPaths {
12670 worktree_paths: HashMap<WorktreeId, GlobSet>,
12671 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12672}
12673
12674#[derive(Default)]
12675struct LanguageServerWatchedPathsBuilder {
12676 worktree_paths: HashMap<WorktreeId, GlobSet>,
12677 abs_paths: HashMap<Arc<Path>, GlobSet>,
12678}
12679
12680impl LanguageServerWatchedPathsBuilder {
12681 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12682 self.worktree_paths.insert(worktree_id, glob_set);
12683 }
12684 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12685 self.abs_paths.insert(path, glob_set);
12686 }
12687 fn build(
12688 self,
12689 fs: Arc<dyn Fs>,
12690 language_server_id: LanguageServerId,
12691 cx: &mut Context<LspStore>,
12692 ) -> LanguageServerWatchedPaths {
12693 let project = cx.weak_entity();
12694
12695 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12696 let abs_paths = self
12697 .abs_paths
12698 .into_iter()
12699 .map(|(abs_path, globset)| {
12700 let task = cx.spawn({
12701 let abs_path = abs_path.clone();
12702 let fs = fs.clone();
12703
12704 let lsp_store = project.clone();
12705 async move |_, cx| {
12706 maybe!(async move {
12707 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12708 while let Some(update) = push_updates.0.next().await {
12709 let action = lsp_store
12710 .update(cx, |this, _| {
12711 let Some(local) = this.as_local() else {
12712 return ControlFlow::Break(());
12713 };
12714 let Some(watcher) = local
12715 .language_server_watched_paths
12716 .get(&language_server_id)
12717 else {
12718 return ControlFlow::Break(());
12719 };
12720 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12721 "Watched abs path is not registered with a watcher",
12722 );
12723 let matching_entries = update
12724 .into_iter()
12725 .filter(|event| globs.is_match(&event.path))
12726 .collect::<Vec<_>>();
12727 this.lsp_notify_abs_paths_changed(
12728 language_server_id,
12729 matching_entries,
12730 );
12731 ControlFlow::Continue(())
12732 })
12733 .ok()?;
12734
12735 if action.is_break() {
12736 break;
12737 }
12738 }
12739 Some(())
12740 })
12741 .await;
12742 }
12743 });
12744 (abs_path, (globset, task))
12745 })
12746 .collect();
12747 LanguageServerWatchedPaths {
12748 worktree_paths: self.worktree_paths,
12749 abs_paths,
12750 }
12751 }
12752}
12753
12754struct LspBufferSnapshot {
12755 version: i32,
12756 snapshot: TextBufferSnapshot,
12757}
12758
12759/// A prompt requested by LSP server.
12760#[derive(Clone, Debug)]
12761pub struct LanguageServerPromptRequest {
12762 pub level: PromptLevel,
12763 pub message: String,
12764 pub actions: Vec<MessageActionItem>,
12765 pub lsp_name: String,
12766 pub(crate) response_channel: Sender<MessageActionItem>,
12767}
12768
12769impl LanguageServerPromptRequest {
12770 pub async fn respond(self, index: usize) -> Option<()> {
12771 if let Some(response) = self.actions.into_iter().nth(index) {
12772 self.response_channel.send(response).await.ok()
12773 } else {
12774 None
12775 }
12776 }
12777}
12778impl PartialEq for LanguageServerPromptRequest {
12779 fn eq(&self, other: &Self) -> bool {
12780 self.message == other.message && self.actions == other.actions
12781 }
12782}
12783
12784#[derive(Clone, Debug, PartialEq)]
12785pub enum LanguageServerLogType {
12786 Log(MessageType),
12787 Trace { verbose_info: Option<String> },
12788 Rpc { received: bool },
12789}
12790
12791impl LanguageServerLogType {
12792 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12793 match self {
12794 Self::Log(log_type) => {
12795 use proto::log_message::LogLevel;
12796 let level = match *log_type {
12797 MessageType::ERROR => LogLevel::Error,
12798 MessageType::WARNING => LogLevel::Warning,
12799 MessageType::INFO => LogLevel::Info,
12800 MessageType::LOG => LogLevel::Log,
12801 other => {
12802 log::warn!("Unknown lsp log message type: {other:?}");
12803 LogLevel::Log
12804 }
12805 };
12806 proto::language_server_log::LogType::Log(proto::LogMessage {
12807 level: level as i32,
12808 })
12809 }
12810 Self::Trace { verbose_info } => {
12811 proto::language_server_log::LogType::Trace(proto::TraceMessage {
12812 verbose_info: verbose_info.to_owned(),
12813 })
12814 }
12815 Self::Rpc { received } => {
12816 let kind = if *received {
12817 proto::rpc_message::Kind::Received
12818 } else {
12819 proto::rpc_message::Kind::Sent
12820 };
12821 let kind = kind as i32;
12822 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
12823 }
12824 }
12825 }
12826
12827 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12828 use proto::log_message::LogLevel;
12829 use proto::rpc_message;
12830 match log_type {
12831 proto::language_server_log::LogType::Log(message_type) => Self::Log(
12832 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
12833 LogLevel::Error => MessageType::ERROR,
12834 LogLevel::Warning => MessageType::WARNING,
12835 LogLevel::Info => MessageType::INFO,
12836 LogLevel::Log => MessageType::LOG,
12837 },
12838 ),
12839 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
12840 verbose_info: trace_message.verbose_info,
12841 },
12842 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
12843 received: match rpc_message::Kind::from_i32(message.kind)
12844 .unwrap_or(rpc_message::Kind::Received)
12845 {
12846 rpc_message::Kind::Received => true,
12847 rpc_message::Kind::Sent => false,
12848 },
12849 },
12850 }
12851 }
12852}
12853
12854pub struct WorkspaceRefreshTask {
12855 refresh_tx: mpsc::Sender<()>,
12856 progress_tx: mpsc::Sender<()>,
12857 #[allow(dead_code)]
12858 task: Task<()>,
12859}
12860
12861pub enum LanguageServerState {
12862 Starting {
12863 startup: Task<Option<Arc<LanguageServer>>>,
12864 /// List of language servers that will be added to the workspace once it's initialization completes.
12865 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
12866 },
12867
12868 Running {
12869 adapter: Arc<CachedLspAdapter>,
12870 server: Arc<LanguageServer>,
12871 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12872 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12873 },
12874}
12875
12876impl LanguageServerState {
12877 fn add_workspace_folder(&self, uri: Uri) {
12878 match self {
12879 LanguageServerState::Starting {
12880 pending_workspace_folders,
12881 ..
12882 } => {
12883 pending_workspace_folders.lock().insert(uri);
12884 }
12885 LanguageServerState::Running { server, .. } => {
12886 server.add_workspace_folder(uri);
12887 }
12888 }
12889 }
12890 fn _remove_workspace_folder(&self, uri: Uri) {
12891 match self {
12892 LanguageServerState::Starting {
12893 pending_workspace_folders,
12894 ..
12895 } => {
12896 pending_workspace_folders.lock().remove(&uri);
12897 }
12898 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12899 }
12900 }
12901}
12902
12903impl std::fmt::Debug for LanguageServerState {
12904 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12905 match self {
12906 LanguageServerState::Starting { .. } => {
12907 f.debug_struct("LanguageServerState::Starting").finish()
12908 }
12909 LanguageServerState::Running { .. } => {
12910 f.debug_struct("LanguageServerState::Running").finish()
12911 }
12912 }
12913 }
12914}
12915
12916#[derive(Clone, Debug, Serialize)]
12917pub struct LanguageServerProgress {
12918 pub is_disk_based_diagnostics_progress: bool,
12919 pub is_cancellable: bool,
12920 pub title: Option<String>,
12921 pub message: Option<String>,
12922 pub percentage: Option<usize>,
12923 #[serde(skip_serializing)]
12924 pub last_update_at: Instant,
12925}
12926
12927#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12928pub struct DiagnosticSummary {
12929 pub error_count: usize,
12930 pub warning_count: usize,
12931}
12932
12933impl DiagnosticSummary {
12934 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12935 let mut this = Self {
12936 error_count: 0,
12937 warning_count: 0,
12938 };
12939
12940 for entry in diagnostics {
12941 if entry.diagnostic.is_primary {
12942 match entry.diagnostic.severity {
12943 DiagnosticSeverity::ERROR => this.error_count += 1,
12944 DiagnosticSeverity::WARNING => this.warning_count += 1,
12945 _ => {}
12946 }
12947 }
12948 }
12949
12950 this
12951 }
12952
12953 pub fn is_empty(&self) -> bool {
12954 self.error_count == 0 && self.warning_count == 0
12955 }
12956
12957 pub fn to_proto(
12958 self,
12959 language_server_id: LanguageServerId,
12960 path: &RelPath,
12961 ) -> proto::DiagnosticSummary {
12962 proto::DiagnosticSummary {
12963 path: path.to_proto(),
12964 language_server_id: language_server_id.0 as u64,
12965 error_count: self.error_count as u32,
12966 warning_count: self.warning_count as u32,
12967 }
12968 }
12969}
12970
12971#[derive(Clone, Debug)]
12972pub enum CompletionDocumentation {
12973 /// There is no documentation for this completion.
12974 Undocumented,
12975 /// A single line of documentation.
12976 SingleLine(SharedString),
12977 /// Multiple lines of plain text documentation.
12978 MultiLinePlainText(SharedString),
12979 /// Markdown documentation.
12980 MultiLineMarkdown(SharedString),
12981 /// Both single line and multiple lines of plain text documentation.
12982 SingleLineAndMultiLinePlainText {
12983 single_line: SharedString,
12984 plain_text: Option<SharedString>,
12985 },
12986}
12987
12988impl CompletionDocumentation {
12989 #[cfg(any(test, feature = "test-support"))]
12990 pub fn text(&self) -> SharedString {
12991 match self {
12992 CompletionDocumentation::Undocumented => "".into(),
12993 CompletionDocumentation::SingleLine(s) => s.clone(),
12994 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
12995 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
12996 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
12997 single_line.clone()
12998 }
12999 }
13000 }
13001}
13002
13003impl From<lsp::Documentation> for CompletionDocumentation {
13004 fn from(docs: lsp::Documentation) -> Self {
13005 match docs {
13006 lsp::Documentation::String(text) => {
13007 if text.lines().count() <= 1 {
13008 CompletionDocumentation::SingleLine(text.into())
13009 } else {
13010 CompletionDocumentation::MultiLinePlainText(text.into())
13011 }
13012 }
13013
13014 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13015 lsp::MarkupKind::PlainText => {
13016 if value.lines().count() <= 1 {
13017 CompletionDocumentation::SingleLine(value.into())
13018 } else {
13019 CompletionDocumentation::MultiLinePlainText(value.into())
13020 }
13021 }
13022
13023 lsp::MarkupKind::Markdown => {
13024 CompletionDocumentation::MultiLineMarkdown(value.into())
13025 }
13026 },
13027 }
13028 }
13029}
13030
13031pub enum ResolvedHint {
13032 Resolved(InlayHint),
13033 Resolving(Shared<Task<()>>),
13034}
13035
13036fn glob_literal_prefix(glob: &Path) -> PathBuf {
13037 glob.components()
13038 .take_while(|component| match component {
13039 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13040 _ => true,
13041 })
13042 .collect()
13043}
13044
13045pub struct SshLspAdapter {
13046 name: LanguageServerName,
13047 binary: LanguageServerBinary,
13048 initialization_options: Option<String>,
13049 code_action_kinds: Option<Vec<CodeActionKind>>,
13050}
13051
13052impl SshLspAdapter {
13053 pub fn new(
13054 name: LanguageServerName,
13055 binary: LanguageServerBinary,
13056 initialization_options: Option<String>,
13057 code_action_kinds: Option<String>,
13058 ) -> Self {
13059 Self {
13060 name,
13061 binary,
13062 initialization_options,
13063 code_action_kinds: code_action_kinds
13064 .as_ref()
13065 .and_then(|c| serde_json::from_str(c).ok()),
13066 }
13067 }
13068}
13069
13070impl LspInstaller for SshLspAdapter {
13071 type BinaryVersion = ();
13072 async fn check_if_user_installed(
13073 &self,
13074 _: &dyn LspAdapterDelegate,
13075 _: Option<Toolchain>,
13076 _: &AsyncApp,
13077 ) -> Option<LanguageServerBinary> {
13078 Some(self.binary.clone())
13079 }
13080
13081 async fn cached_server_binary(
13082 &self,
13083 _: PathBuf,
13084 _: &dyn LspAdapterDelegate,
13085 ) -> Option<LanguageServerBinary> {
13086 None
13087 }
13088
13089 async fn fetch_latest_server_version(
13090 &self,
13091 _: &dyn LspAdapterDelegate,
13092 _: bool,
13093 _: &mut AsyncApp,
13094 ) -> Result<()> {
13095 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13096 }
13097
13098 async fn fetch_server_binary(
13099 &self,
13100 _: (),
13101 _: PathBuf,
13102 _: &dyn LspAdapterDelegate,
13103 ) -> Result<LanguageServerBinary> {
13104 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13105 }
13106}
13107
13108#[async_trait(?Send)]
13109impl LspAdapter for SshLspAdapter {
13110 fn name(&self) -> LanguageServerName {
13111 self.name.clone()
13112 }
13113
13114 async fn initialization_options(
13115 self: Arc<Self>,
13116 _: &Arc<dyn LspAdapterDelegate>,
13117 ) -> Result<Option<serde_json::Value>> {
13118 let Some(options) = &self.initialization_options else {
13119 return Ok(None);
13120 };
13121 let result = serde_json::from_str(options)?;
13122 Ok(result)
13123 }
13124
13125 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13126 self.code_action_kinds.clone()
13127 }
13128}
13129
13130pub fn language_server_settings<'a>(
13131 delegate: &'a dyn LspAdapterDelegate,
13132 language: &LanguageServerName,
13133 cx: &'a App,
13134) -> Option<&'a LspSettings> {
13135 language_server_settings_for(
13136 SettingsLocation {
13137 worktree_id: delegate.worktree_id(),
13138 path: RelPath::empty(),
13139 },
13140 language,
13141 cx,
13142 )
13143}
13144
13145pub(crate) fn language_server_settings_for<'a>(
13146 location: SettingsLocation<'a>,
13147 language: &LanguageServerName,
13148 cx: &'a App,
13149) -> Option<&'a LspSettings> {
13150 ProjectSettings::get(Some(location), cx).lsp.get(language)
13151}
13152
13153pub struct LocalLspAdapterDelegate {
13154 lsp_store: WeakEntity<LspStore>,
13155 worktree: worktree::Snapshot,
13156 fs: Arc<dyn Fs>,
13157 http_client: Arc<dyn HttpClient>,
13158 language_registry: Arc<LanguageRegistry>,
13159 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13160}
13161
13162impl LocalLspAdapterDelegate {
13163 pub fn new(
13164 language_registry: Arc<LanguageRegistry>,
13165 environment: &Entity<ProjectEnvironment>,
13166 lsp_store: WeakEntity<LspStore>,
13167 worktree: &Entity<Worktree>,
13168 http_client: Arc<dyn HttpClient>,
13169 fs: Arc<dyn Fs>,
13170 cx: &mut App,
13171 ) -> Arc<Self> {
13172 let load_shell_env_task = environment.update(cx, |env, cx| {
13173 env.get_worktree_environment(worktree.clone(), cx)
13174 });
13175
13176 Arc::new(Self {
13177 lsp_store,
13178 worktree: worktree.read(cx).snapshot(),
13179 fs,
13180 http_client,
13181 language_registry,
13182 load_shell_env_task,
13183 })
13184 }
13185
13186 fn from_local_lsp(
13187 local: &LocalLspStore,
13188 worktree: &Entity<Worktree>,
13189 cx: &mut App,
13190 ) -> Arc<Self> {
13191 Self::new(
13192 local.languages.clone(),
13193 &local.environment,
13194 local.weak.clone(),
13195 worktree,
13196 local.http_client.clone(),
13197 local.fs.clone(),
13198 cx,
13199 )
13200 }
13201}
13202
13203#[async_trait]
13204impl LspAdapterDelegate for LocalLspAdapterDelegate {
13205 fn show_notification(&self, message: &str, cx: &mut App) {
13206 self.lsp_store
13207 .update(cx, |_, cx| {
13208 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13209 })
13210 .ok();
13211 }
13212
13213 fn http_client(&self) -> Arc<dyn HttpClient> {
13214 self.http_client.clone()
13215 }
13216
13217 fn worktree_id(&self) -> WorktreeId {
13218 self.worktree.id()
13219 }
13220
13221 fn worktree_root_path(&self) -> &Path {
13222 self.worktree.abs_path().as_ref()
13223 }
13224
13225 async fn shell_env(&self) -> HashMap<String, String> {
13226 let task = self.load_shell_env_task.clone();
13227 task.await.unwrap_or_default()
13228 }
13229
13230 async fn npm_package_installed_version(
13231 &self,
13232 package_name: &str,
13233 ) -> Result<Option<(PathBuf, String)>> {
13234 let local_package_directory = self.worktree_root_path();
13235 let node_modules_directory = local_package_directory.join("node_modules");
13236
13237 if let Some(version) =
13238 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13239 {
13240 return Ok(Some((node_modules_directory, version)));
13241 }
13242 let Some(npm) = self.which("npm".as_ref()).await else {
13243 log::warn!(
13244 "Failed to find npm executable for {:?}",
13245 local_package_directory
13246 );
13247 return Ok(None);
13248 };
13249
13250 let env = self.shell_env().await;
13251 let output = util::command::new_smol_command(&npm)
13252 .args(["root", "-g"])
13253 .envs(env)
13254 .current_dir(local_package_directory)
13255 .output()
13256 .await?;
13257 let global_node_modules =
13258 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13259
13260 if let Some(version) =
13261 read_package_installed_version(global_node_modules.clone(), package_name).await?
13262 {
13263 return Ok(Some((global_node_modules, version)));
13264 }
13265 return Ok(None);
13266 }
13267
13268 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13269 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13270 if self.fs.is_file(&worktree_abs_path).await {
13271 worktree_abs_path.pop();
13272 }
13273
13274 let env = self.shell_env().await;
13275
13276 let shell_path = env.get("PATH").cloned();
13277
13278 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13279 }
13280
13281 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13282 let mut working_dir = self.worktree_root_path().to_path_buf();
13283 if self.fs.is_file(&working_dir).await {
13284 working_dir.pop();
13285 }
13286 let output = util::command::new_smol_command(&command.path)
13287 .args(command.arguments)
13288 .envs(command.env.clone().unwrap_or_default())
13289 .current_dir(working_dir)
13290 .output()
13291 .await?;
13292
13293 anyhow::ensure!(
13294 output.status.success(),
13295 "{}, stdout: {:?}, stderr: {:?}",
13296 output.status,
13297 String::from_utf8_lossy(&output.stdout),
13298 String::from_utf8_lossy(&output.stderr)
13299 );
13300 Ok(())
13301 }
13302
13303 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13304 self.language_registry
13305 .update_lsp_binary_status(server_name, status);
13306 }
13307
13308 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13309 self.language_registry
13310 .all_lsp_adapters()
13311 .into_iter()
13312 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13313 .collect()
13314 }
13315
13316 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13317 let dir = self.language_registry.language_server_download_dir(name)?;
13318
13319 if !dir.exists() {
13320 smol::fs::create_dir_all(&dir)
13321 .await
13322 .context("failed to create container directory")
13323 .log_err()?;
13324 }
13325
13326 Some(dir)
13327 }
13328
13329 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13330 let entry = self
13331 .worktree
13332 .entry_for_path(path)
13333 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13334 let abs_path = self.worktree.absolutize(&entry.path);
13335 self.fs.load(&abs_path).await
13336 }
13337}
13338
13339async fn populate_labels_for_symbols(
13340 symbols: Vec<CoreSymbol>,
13341 language_registry: &Arc<LanguageRegistry>,
13342 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13343 output: &mut Vec<Symbol>,
13344) {
13345 #[allow(clippy::mutable_key_type)]
13346 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13347
13348 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13349 for symbol in symbols {
13350 let Some(file_name) = symbol.path.file_name() else {
13351 continue;
13352 };
13353 let language = language_registry
13354 .load_language_for_file_path(Path::new(file_name))
13355 .await
13356 .ok()
13357 .or_else(|| {
13358 unknown_paths.insert(file_name.into());
13359 None
13360 });
13361 symbols_by_language
13362 .entry(language)
13363 .or_default()
13364 .push(symbol);
13365 }
13366
13367 for unknown_path in unknown_paths {
13368 log::info!("no language found for symbol in file {unknown_path:?}");
13369 }
13370
13371 let mut label_params = Vec::new();
13372 for (language, mut symbols) in symbols_by_language {
13373 label_params.clear();
13374 label_params.extend(
13375 symbols
13376 .iter_mut()
13377 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13378 );
13379
13380 let mut labels = Vec::new();
13381 if let Some(language) = language {
13382 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13383 language_registry
13384 .lsp_adapters(&language.name())
13385 .first()
13386 .cloned()
13387 });
13388 if let Some(lsp_adapter) = lsp_adapter {
13389 labels = lsp_adapter
13390 .labels_for_symbols(&label_params, &language)
13391 .await
13392 .log_err()
13393 .unwrap_or_default();
13394 }
13395 }
13396
13397 for ((symbol, (name, _)), label) in symbols
13398 .into_iter()
13399 .zip(label_params.drain(..))
13400 .zip(labels.into_iter().chain(iter::repeat(None)))
13401 {
13402 output.push(Symbol {
13403 language_server_name: symbol.language_server_name,
13404 source_worktree_id: symbol.source_worktree_id,
13405 source_language_server_id: symbol.source_language_server_id,
13406 path: symbol.path,
13407 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13408 name,
13409 kind: symbol.kind,
13410 range: symbol.range,
13411 });
13412 }
13413 }
13414}
13415
13416fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13417 match server.capabilities().text_document_sync.as_ref()? {
13418 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13419 // Server wants didSave but didn't specify includeText.
13420 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13421 // Server doesn't want didSave at all.
13422 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13423 // Server provided SaveOptions.
13424 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13425 Some(save_options.include_text.unwrap_or(false))
13426 }
13427 },
13428 // We do not have any save info. Kind affects didChange only.
13429 lsp::TextDocumentSyncCapability::Kind(_) => None,
13430 }
13431}
13432
13433/// Completion items are displayed in a `UniformList`.
13434/// Usually, those items are single-line strings, but in LSP responses,
13435/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13436/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13437/// 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,
13438/// breaking the completions menu presentation.
13439///
13440/// 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.
13441fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13442 let mut new_text = String::with_capacity(label.text.len());
13443 let mut offset_map = vec![0; label.text.len() + 1];
13444 let mut last_char_was_space = false;
13445 let mut new_idx = 0;
13446 let chars = label.text.char_indices().fuse();
13447 let mut newlines_removed = false;
13448
13449 for (idx, c) in chars {
13450 offset_map[idx] = new_idx;
13451
13452 match c {
13453 '\n' if last_char_was_space => {
13454 newlines_removed = true;
13455 }
13456 '\t' | ' ' if last_char_was_space => {}
13457 '\n' if !last_char_was_space => {
13458 new_text.push(' ');
13459 new_idx += 1;
13460 last_char_was_space = true;
13461 newlines_removed = true;
13462 }
13463 ' ' | '\t' => {
13464 new_text.push(' ');
13465 new_idx += 1;
13466 last_char_was_space = true;
13467 }
13468 _ => {
13469 new_text.push(c);
13470 new_idx += c.len_utf8();
13471 last_char_was_space = false;
13472 }
13473 }
13474 }
13475 offset_map[label.text.len()] = new_idx;
13476
13477 // Only modify the label if newlines were removed.
13478 if !newlines_removed {
13479 return;
13480 }
13481
13482 let last_index = new_idx;
13483 let mut run_ranges_errors = Vec::new();
13484 label.runs.retain_mut(|(range, _)| {
13485 match offset_map.get(range.start) {
13486 Some(&start) => range.start = start,
13487 None => {
13488 run_ranges_errors.push(range.clone());
13489 return false;
13490 }
13491 }
13492
13493 match offset_map.get(range.end) {
13494 Some(&end) => range.end = end,
13495 None => {
13496 run_ranges_errors.push(range.clone());
13497 range.end = last_index;
13498 }
13499 }
13500 true
13501 });
13502 if !run_ranges_errors.is_empty() {
13503 log::error!(
13504 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13505 label.text
13506 );
13507 }
13508
13509 let mut wrong_filter_range = None;
13510 if label.filter_range == (0..label.text.len()) {
13511 label.filter_range = 0..new_text.len();
13512 } else {
13513 let mut original_filter_range = Some(label.filter_range.clone());
13514 match offset_map.get(label.filter_range.start) {
13515 Some(&start) => label.filter_range.start = start,
13516 None => {
13517 wrong_filter_range = original_filter_range.take();
13518 label.filter_range.start = last_index;
13519 }
13520 }
13521
13522 match offset_map.get(label.filter_range.end) {
13523 Some(&end) => label.filter_range.end = end,
13524 None => {
13525 wrong_filter_range = original_filter_range.take();
13526 label.filter_range.end = last_index;
13527 }
13528 }
13529 }
13530 if let Some(wrong_filter_range) = wrong_filter_range {
13531 log::error!(
13532 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13533 label.text
13534 );
13535 }
13536
13537 label.text = new_text;
13538}
13539
13540#[cfg(test)]
13541mod tests {
13542 use language::HighlightId;
13543
13544 use super::*;
13545
13546 #[test]
13547 fn test_glob_literal_prefix() {
13548 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13549 assert_eq!(
13550 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13551 Path::new("node_modules")
13552 );
13553 assert_eq!(
13554 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13555 Path::new("foo")
13556 );
13557 assert_eq!(
13558 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13559 Path::new("foo/bar/baz.js")
13560 );
13561
13562 #[cfg(target_os = "windows")]
13563 {
13564 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13565 assert_eq!(
13566 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13567 Path::new("node_modules")
13568 );
13569 assert_eq!(
13570 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13571 Path::new("foo")
13572 );
13573 assert_eq!(
13574 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13575 Path::new("foo/bar/baz.js")
13576 );
13577 }
13578 }
13579
13580 #[test]
13581 fn test_multi_len_chars_normalization() {
13582 let mut label = CodeLabel::new(
13583 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13584 0..6,
13585 vec![(0..6, HighlightId(1))],
13586 );
13587 ensure_uniform_list_compatible_label(&mut label);
13588 assert_eq!(
13589 label,
13590 CodeLabel::new(
13591 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13592 0..6,
13593 vec![(0..6, HighlightId(1))],
13594 )
13595 );
13596 }
13597}