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