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