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
4647 for (file, language, buffer_id) in buffers {
4648 let worktree_id = file.worktree_id(cx);
4649 let Some(worktree) = local
4650 .worktree_store
4651 .read(cx)
4652 .worktree_for_id(worktree_id, cx)
4653 else {
4654 continue;
4655 };
4656
4657 if let Some((_, apply)) = local.reuse_existing_language_server(
4658 rebase.server_tree(),
4659 &worktree,
4660 &language.name(),
4661 cx,
4662 ) {
4663 (apply)(rebase.server_tree());
4664 } else if let Some(lsp_delegate) = adapters
4665 .entry(worktree_id)
4666 .or_insert_with(|| get_adapter(worktree_id, cx))
4667 .clone()
4668 {
4669 let delegate =
4670 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4671 let path = file
4672 .path()
4673 .parent()
4674 .map(Arc::from)
4675 .unwrap_or_else(|| file.path().clone());
4676 let worktree_path = ProjectPath { worktree_id, path };
4677 let abs_path = file.abs_path(cx);
4678 let worktree_root = worktree.read(cx).abs_path();
4679 let nodes = rebase
4680 .walk(
4681 worktree_path,
4682 language.name(),
4683 language.manifest(),
4684 delegate.clone(),
4685 cx,
4686 )
4687 .collect::<Vec<_>>();
4688
4689 for node in nodes {
4690 let server_id = node.server_id_or_init(|disposition| {
4691 let path = &disposition.path;
4692 let uri = Url::from_file_path(worktree_root.join(&path.path));
4693 let key = LanguageServerSeed {
4694 worktree_id,
4695 name: disposition.server_name.clone(),
4696 settings: disposition.settings.clone(),
4697 toolchain: local.toolchain_store.read(cx).active_toolchain(
4698 path.worktree_id,
4699 &path.path,
4700 language.name(),
4701 ),
4702 };
4703 local.language_server_ids.remove(&key);
4704
4705 let server_id = local.get_or_insert_language_server(
4706 &worktree,
4707 lsp_delegate.clone(),
4708 disposition,
4709 &language.name(),
4710 cx,
4711 );
4712 if let Some(state) = local.language_servers.get(&server_id)
4713 && let Ok(uri) = uri
4714 {
4715 state.add_workspace_folder(uri);
4716 };
4717 server_id
4718 });
4719
4720 if let Some(language_server_id) = server_id {
4721 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4722 language_server_id,
4723 name: node.name(),
4724 message:
4725 proto::update_language_server::Variant::RegisteredForBuffer(
4726 proto::RegisteredForBuffer {
4727 buffer_abs_path: abs_path.to_string_lossy().to_string(),
4728 buffer_id: buffer_id.to_proto(),
4729 },
4730 ),
4731 });
4732 }
4733 }
4734 } else {
4735 continue;
4736 }
4737 }
4738 rebase.finish()
4739 };
4740 for message in messages_to_report {
4741 cx.emit(message);
4742 }
4743 local.lsp_tree = new_tree;
4744 for (id, _) in to_stop {
4745 self.stop_local_language_server(id, cx).detach();
4746 }
4747 }
4748
4749 pub fn apply_code_action(
4750 &self,
4751 buffer_handle: Entity<Buffer>,
4752 mut action: CodeAction,
4753 push_to_history: bool,
4754 cx: &mut Context<Self>,
4755 ) -> Task<Result<ProjectTransaction>> {
4756 if let Some((upstream_client, project_id)) = self.upstream_client() {
4757 let request = proto::ApplyCodeAction {
4758 project_id,
4759 buffer_id: buffer_handle.read(cx).remote_id().into(),
4760 action: Some(Self::serialize_code_action(&action)),
4761 };
4762 let buffer_store = self.buffer_store();
4763 cx.spawn(async move |_, cx| {
4764 let response = upstream_client
4765 .request(request)
4766 .await?
4767 .transaction
4768 .context("missing transaction")?;
4769
4770 buffer_store
4771 .update(cx, |buffer_store, cx| {
4772 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4773 })?
4774 .await
4775 })
4776 } else if self.mode.is_local() {
4777 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4778 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4779 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4780 }) else {
4781 return Task::ready(Ok(ProjectTransaction::default()));
4782 };
4783 cx.spawn(async move |this, cx| {
4784 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4785 .await
4786 .context("resolving a code action")?;
4787 if let Some(edit) = action.lsp_action.edit()
4788 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4789 return LocalLspStore::deserialize_workspace_edit(
4790 this.upgrade().context("no app present")?,
4791 edit.clone(),
4792 push_to_history,
4793
4794 lang_server.clone(),
4795 cx,
4796 )
4797 .await;
4798 }
4799
4800 if let Some(command) = action.lsp_action.command() {
4801 let server_capabilities = lang_server.capabilities();
4802 let available_commands = server_capabilities
4803 .execute_command_provider
4804 .as_ref()
4805 .map(|options| options.commands.as_slice())
4806 .unwrap_or_default();
4807 if available_commands.contains(&command.command) {
4808 this.update(cx, |this, _| {
4809 this.as_local_mut()
4810 .unwrap()
4811 .last_workspace_edits_by_language_server
4812 .remove(&lang_server.server_id());
4813 })?;
4814
4815 let _result = lang_server
4816 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4817 command: command.command.clone(),
4818 arguments: command.arguments.clone().unwrap_or_default(),
4819 ..lsp::ExecuteCommandParams::default()
4820 })
4821 .await.into_response()
4822 .context("execute command")?;
4823
4824 return this.update(cx, |this, _| {
4825 this.as_local_mut()
4826 .unwrap()
4827 .last_workspace_edits_by_language_server
4828 .remove(&lang_server.server_id())
4829 .unwrap_or_default()
4830 });
4831 } else {
4832 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4833 }
4834 }
4835
4836 Ok(ProjectTransaction::default())
4837 })
4838 } else {
4839 Task::ready(Err(anyhow!("no upstream client and not local")))
4840 }
4841 }
4842
4843 pub fn apply_code_action_kind(
4844 &mut self,
4845 buffers: HashSet<Entity<Buffer>>,
4846 kind: CodeActionKind,
4847 push_to_history: bool,
4848 cx: &mut Context<Self>,
4849 ) -> Task<anyhow::Result<ProjectTransaction>> {
4850 if self.as_local().is_some() {
4851 cx.spawn(async move |lsp_store, cx| {
4852 let buffers = buffers.into_iter().collect::<Vec<_>>();
4853 let result = LocalLspStore::execute_code_action_kind_locally(
4854 lsp_store.clone(),
4855 buffers,
4856 kind,
4857 push_to_history,
4858 cx,
4859 )
4860 .await;
4861 lsp_store.update(cx, |lsp_store, _| {
4862 lsp_store.update_last_formatting_failure(&result);
4863 })?;
4864 result
4865 })
4866 } else if let Some((client, project_id)) = self.upstream_client() {
4867 let buffer_store = self.buffer_store();
4868 cx.spawn(async move |lsp_store, cx| {
4869 let result = client
4870 .request(proto::ApplyCodeActionKind {
4871 project_id,
4872 kind: kind.as_str().to_owned(),
4873 buffer_ids: buffers
4874 .iter()
4875 .map(|buffer| {
4876 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4877 })
4878 .collect::<Result<_>>()?,
4879 })
4880 .await
4881 .and_then(|result| result.transaction.context("missing transaction"));
4882 lsp_store.update(cx, |lsp_store, _| {
4883 lsp_store.update_last_formatting_failure(&result);
4884 })?;
4885
4886 let transaction_response = result?;
4887 buffer_store
4888 .update(cx, |buffer_store, cx| {
4889 buffer_store.deserialize_project_transaction(
4890 transaction_response,
4891 push_to_history,
4892 cx,
4893 )
4894 })?
4895 .await
4896 })
4897 } else {
4898 Task::ready(Ok(ProjectTransaction::default()))
4899 }
4900 }
4901
4902 pub fn resolve_inlay_hint(
4903 &self,
4904 mut hint: InlayHint,
4905 buffer: Entity<Buffer>,
4906 server_id: LanguageServerId,
4907 cx: &mut Context<Self>,
4908 ) -> Task<anyhow::Result<InlayHint>> {
4909 if let Some((upstream_client, project_id)) = self.upstream_client() {
4910 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4911 {
4912 hint.resolve_state = ResolveState::Resolved;
4913 return Task::ready(Ok(hint));
4914 }
4915 let request = proto::ResolveInlayHint {
4916 project_id,
4917 buffer_id: buffer.read(cx).remote_id().into(),
4918 language_server_id: server_id.0 as u64,
4919 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4920 };
4921 cx.background_spawn(async move {
4922 let response = upstream_client
4923 .request(request)
4924 .await
4925 .context("inlay hints proto request")?;
4926 match response.hint {
4927 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
4928 .context("inlay hints proto resolve response conversion"),
4929 None => Ok(hint),
4930 }
4931 })
4932 } else {
4933 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
4934 self.language_server_for_local_buffer(buffer, server_id, cx)
4935 .map(|(_, server)| server.clone())
4936 }) else {
4937 return Task::ready(Ok(hint));
4938 };
4939 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
4940 return Task::ready(Ok(hint));
4941 }
4942 let buffer_snapshot = buffer.read(cx).snapshot();
4943 cx.spawn(async move |_, cx| {
4944 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
4945 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
4946 );
4947 let resolved_hint = resolve_task
4948 .await
4949 .into_response()
4950 .context("inlay hint resolve LSP request")?;
4951 let resolved_hint = InlayHints::lsp_to_project_hint(
4952 resolved_hint,
4953 &buffer,
4954 server_id,
4955 ResolveState::Resolved,
4956 false,
4957 cx,
4958 )
4959 .await?;
4960 Ok(resolved_hint)
4961 })
4962 }
4963 }
4964
4965 pub fn resolve_color_presentation(
4966 &mut self,
4967 mut color: DocumentColor,
4968 buffer: Entity<Buffer>,
4969 server_id: LanguageServerId,
4970 cx: &mut Context<Self>,
4971 ) -> Task<Result<DocumentColor>> {
4972 if color.resolved {
4973 return Task::ready(Ok(color));
4974 }
4975
4976 if let Some((upstream_client, project_id)) = self.upstream_client() {
4977 let start = color.lsp_range.start;
4978 let end = color.lsp_range.end;
4979 let request = proto::GetColorPresentation {
4980 project_id,
4981 server_id: server_id.to_proto(),
4982 buffer_id: buffer.read(cx).remote_id().into(),
4983 color: Some(proto::ColorInformation {
4984 red: color.color.red,
4985 green: color.color.green,
4986 blue: color.color.blue,
4987 alpha: color.color.alpha,
4988 lsp_range_start: Some(proto::PointUtf16 {
4989 row: start.line,
4990 column: start.character,
4991 }),
4992 lsp_range_end: Some(proto::PointUtf16 {
4993 row: end.line,
4994 column: end.character,
4995 }),
4996 }),
4997 };
4998 cx.background_spawn(async move {
4999 let response = upstream_client
5000 .request(request)
5001 .await
5002 .context("color presentation proto request")?;
5003 color.resolved = true;
5004 color.color_presentations = response
5005 .presentations
5006 .into_iter()
5007 .map(|presentation| ColorPresentation {
5008 label: SharedString::from(presentation.label),
5009 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5010 additional_text_edits: presentation
5011 .additional_text_edits
5012 .into_iter()
5013 .filter_map(deserialize_lsp_edit)
5014 .collect(),
5015 })
5016 .collect();
5017 Ok(color)
5018 })
5019 } else {
5020 let path = match buffer
5021 .update(cx, |buffer, cx| {
5022 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5023 })
5024 .context("buffer with the missing path")
5025 {
5026 Ok(path) => path,
5027 Err(e) => return Task::ready(Err(e)),
5028 };
5029 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5030 self.language_server_for_local_buffer(buffer, server_id, cx)
5031 .map(|(_, server)| server.clone())
5032 }) else {
5033 return Task::ready(Ok(color));
5034 };
5035 cx.background_spawn(async move {
5036 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5037 lsp::ColorPresentationParams {
5038 text_document: make_text_document_identifier(&path)?,
5039 color: color.color,
5040 range: color.lsp_range,
5041 work_done_progress_params: Default::default(),
5042 partial_result_params: Default::default(),
5043 },
5044 );
5045 color.color_presentations = resolve_task
5046 .await
5047 .into_response()
5048 .context("color presentation resolve LSP request")?
5049 .into_iter()
5050 .map(|presentation| ColorPresentation {
5051 label: SharedString::from(presentation.label),
5052 text_edit: presentation.text_edit,
5053 additional_text_edits: presentation
5054 .additional_text_edits
5055 .unwrap_or_default(),
5056 })
5057 .collect();
5058 color.resolved = true;
5059 Ok(color)
5060 })
5061 }
5062 }
5063
5064 pub(crate) fn linked_edits(
5065 &mut self,
5066 buffer: &Entity<Buffer>,
5067 position: Anchor,
5068 cx: &mut Context<Self>,
5069 ) -> Task<Result<Vec<Range<Anchor>>>> {
5070 let snapshot = buffer.read(cx).snapshot();
5071 let scope = snapshot.language_scope_at(position);
5072 let Some(server_id) = self
5073 .as_local()
5074 .and_then(|local| {
5075 buffer.update(cx, |buffer, cx| {
5076 local
5077 .language_servers_for_buffer(buffer, cx)
5078 .filter(|(_, server)| {
5079 LinkedEditingRange::check_server_capabilities(server.capabilities())
5080 })
5081 .filter(|(adapter, _)| {
5082 scope
5083 .as_ref()
5084 .map(|scope| scope.language_allowed(&adapter.name))
5085 .unwrap_or(true)
5086 })
5087 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5088 .next()
5089 })
5090 })
5091 .or_else(|| {
5092 self.upstream_client()
5093 .is_some()
5094 .then_some(LanguageServerToQuery::FirstCapable)
5095 })
5096 .filter(|_| {
5097 maybe!({
5098 let language = buffer.read(cx).language_at(position)?;
5099 Some(
5100 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5101 .linked_edits,
5102 )
5103 }) == Some(true)
5104 })
5105 else {
5106 return Task::ready(Ok(Vec::new()));
5107 };
5108
5109 self.request_lsp(
5110 buffer.clone(),
5111 server_id,
5112 LinkedEditingRange { position },
5113 cx,
5114 )
5115 }
5116
5117 fn apply_on_type_formatting(
5118 &mut self,
5119 buffer: Entity<Buffer>,
5120 position: Anchor,
5121 trigger: String,
5122 cx: &mut Context<Self>,
5123 ) -> Task<Result<Option<Transaction>>> {
5124 if let Some((client, project_id)) = self.upstream_client() {
5125 if !self.check_if_capable_for_proto_request(
5126 &buffer,
5127 |capabilities| {
5128 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5129 },
5130 cx,
5131 ) {
5132 return Task::ready(Ok(None));
5133 }
5134 let request = proto::OnTypeFormatting {
5135 project_id,
5136 buffer_id: buffer.read(cx).remote_id().into(),
5137 position: Some(serialize_anchor(&position)),
5138 trigger,
5139 version: serialize_version(&buffer.read(cx).version()),
5140 };
5141 cx.background_spawn(async move {
5142 client
5143 .request(request)
5144 .await?
5145 .transaction
5146 .map(language::proto::deserialize_transaction)
5147 .transpose()
5148 })
5149 } else if let Some(local) = self.as_local_mut() {
5150 let buffer_id = buffer.read(cx).remote_id();
5151 local.buffers_being_formatted.insert(buffer_id);
5152 cx.spawn(async move |this, cx| {
5153 let _cleanup = defer({
5154 let this = this.clone();
5155 let mut cx = cx.clone();
5156 move || {
5157 this.update(&mut cx, |this, _| {
5158 if let Some(local) = this.as_local_mut() {
5159 local.buffers_being_formatted.remove(&buffer_id);
5160 }
5161 })
5162 .ok();
5163 }
5164 });
5165
5166 buffer
5167 .update(cx, |buffer, _| {
5168 buffer.wait_for_edits(Some(position.timestamp))
5169 })?
5170 .await?;
5171 this.update(cx, |this, cx| {
5172 let position = position.to_point_utf16(buffer.read(cx));
5173 this.on_type_format(buffer, position, trigger, false, cx)
5174 })?
5175 .await
5176 })
5177 } else {
5178 Task::ready(Err(anyhow!("No upstream client or local language server")))
5179 }
5180 }
5181
5182 pub fn on_type_format<T: ToPointUtf16>(
5183 &mut self,
5184 buffer: Entity<Buffer>,
5185 position: T,
5186 trigger: String,
5187 push_to_history: bool,
5188 cx: &mut Context<Self>,
5189 ) -> Task<Result<Option<Transaction>>> {
5190 let position = position.to_point_utf16(buffer.read(cx));
5191 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5192 }
5193
5194 fn on_type_format_impl(
5195 &mut self,
5196 buffer: Entity<Buffer>,
5197 position: PointUtf16,
5198 trigger: String,
5199 push_to_history: bool,
5200 cx: &mut Context<Self>,
5201 ) -> Task<Result<Option<Transaction>>> {
5202 let options = buffer.update(cx, |buffer, cx| {
5203 lsp_command::lsp_formatting_options(
5204 language_settings(
5205 buffer.language_at(position).map(|l| l.name()),
5206 buffer.file(),
5207 cx,
5208 )
5209 .as_ref(),
5210 )
5211 });
5212
5213 cx.spawn(async move |this, cx| {
5214 if let Some(waiter) =
5215 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5216 {
5217 waiter.await?;
5218 }
5219 cx.update(|cx| {
5220 this.update(cx, |this, cx| {
5221 this.request_lsp(
5222 buffer.clone(),
5223 LanguageServerToQuery::FirstCapable,
5224 OnTypeFormatting {
5225 position,
5226 trigger,
5227 options,
5228 push_to_history,
5229 },
5230 cx,
5231 )
5232 })
5233 })??
5234 .await
5235 })
5236 }
5237
5238 pub fn definitions(
5239 &mut self,
5240 buffer: &Entity<Buffer>,
5241 position: PointUtf16,
5242 cx: &mut Context<Self>,
5243 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5244 if let Some((upstream_client, project_id)) = self.upstream_client() {
5245 let request = GetDefinitions { position };
5246 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5247 return Task::ready(Ok(None));
5248 }
5249 let request_task = upstream_client.request_lsp(
5250 project_id,
5251 LSP_REQUEST_TIMEOUT,
5252 cx.background_executor().clone(),
5253 request.to_proto(project_id, buffer.read(cx)),
5254 );
5255 let buffer = buffer.clone();
5256 cx.spawn(async move |weak_project, cx| {
5257 let Some(project) = weak_project.upgrade() else {
5258 return Ok(None);
5259 };
5260 let Some(responses) = request_task.await? else {
5261 return Ok(None);
5262 };
5263 let actions = join_all(responses.payload.into_iter().map(|response| {
5264 GetDefinitions { position }.response_from_proto(
5265 response.response,
5266 project.clone(),
5267 buffer.clone(),
5268 cx.clone(),
5269 )
5270 }))
5271 .await;
5272
5273 Ok(Some(
5274 actions
5275 .into_iter()
5276 .collect::<Result<Vec<Vec<_>>>>()?
5277 .into_iter()
5278 .flatten()
5279 .dedup()
5280 .collect(),
5281 ))
5282 })
5283 } else {
5284 let definitions_task = self.request_multiple_lsp_locally(
5285 buffer,
5286 Some(position),
5287 GetDefinitions { position },
5288 cx,
5289 );
5290 cx.background_spawn(async move {
5291 Ok(Some(
5292 definitions_task
5293 .await
5294 .into_iter()
5295 .flat_map(|(_, definitions)| definitions)
5296 .dedup()
5297 .collect(),
5298 ))
5299 })
5300 }
5301 }
5302
5303 pub fn declarations(
5304 &mut self,
5305 buffer: &Entity<Buffer>,
5306 position: PointUtf16,
5307 cx: &mut Context<Self>,
5308 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5309 if let Some((upstream_client, project_id)) = self.upstream_client() {
5310 let request = GetDeclarations { position };
5311 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5312 return Task::ready(Ok(None));
5313 }
5314 let request_task = upstream_client.request_lsp(
5315 project_id,
5316 LSP_REQUEST_TIMEOUT,
5317 cx.background_executor().clone(),
5318 request.to_proto(project_id, buffer.read(cx)),
5319 );
5320 let buffer = buffer.clone();
5321 cx.spawn(async move |weak_project, cx| {
5322 let Some(project) = weak_project.upgrade() else {
5323 return Ok(None);
5324 };
5325 let Some(responses) = request_task.await? else {
5326 return Ok(None);
5327 };
5328 let actions = join_all(responses.payload.into_iter().map(|response| {
5329 GetDeclarations { position }.response_from_proto(
5330 response.response,
5331 project.clone(),
5332 buffer.clone(),
5333 cx.clone(),
5334 )
5335 }))
5336 .await;
5337
5338 Ok(Some(
5339 actions
5340 .into_iter()
5341 .collect::<Result<Vec<Vec<_>>>>()?
5342 .into_iter()
5343 .flatten()
5344 .dedup()
5345 .collect(),
5346 ))
5347 })
5348 } else {
5349 let declarations_task = self.request_multiple_lsp_locally(
5350 buffer,
5351 Some(position),
5352 GetDeclarations { position },
5353 cx,
5354 );
5355 cx.background_spawn(async move {
5356 Ok(Some(
5357 declarations_task
5358 .await
5359 .into_iter()
5360 .flat_map(|(_, declarations)| declarations)
5361 .dedup()
5362 .collect(),
5363 ))
5364 })
5365 }
5366 }
5367
5368 pub fn type_definitions(
5369 &mut self,
5370 buffer: &Entity<Buffer>,
5371 position: PointUtf16,
5372 cx: &mut Context<Self>,
5373 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5374 if let Some((upstream_client, project_id)) = self.upstream_client() {
5375 let request = GetTypeDefinitions { position };
5376 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5377 return Task::ready(Ok(None));
5378 }
5379 let request_task = upstream_client.request_lsp(
5380 project_id,
5381 LSP_REQUEST_TIMEOUT,
5382 cx.background_executor().clone(),
5383 request.to_proto(project_id, buffer.read(cx)),
5384 );
5385 let buffer = buffer.clone();
5386 cx.spawn(async move |weak_project, cx| {
5387 let Some(project) = weak_project.upgrade() else {
5388 return Ok(None);
5389 };
5390 let Some(responses) = request_task.await? else {
5391 return Ok(None);
5392 };
5393 let actions = join_all(responses.payload.into_iter().map(|response| {
5394 GetTypeDefinitions { position }.response_from_proto(
5395 response.response,
5396 project.clone(),
5397 buffer.clone(),
5398 cx.clone(),
5399 )
5400 }))
5401 .await;
5402
5403 Ok(Some(
5404 actions
5405 .into_iter()
5406 .collect::<Result<Vec<Vec<_>>>>()?
5407 .into_iter()
5408 .flatten()
5409 .dedup()
5410 .collect(),
5411 ))
5412 })
5413 } else {
5414 let type_definitions_task = self.request_multiple_lsp_locally(
5415 buffer,
5416 Some(position),
5417 GetTypeDefinitions { position },
5418 cx,
5419 );
5420 cx.background_spawn(async move {
5421 Ok(Some(
5422 type_definitions_task
5423 .await
5424 .into_iter()
5425 .flat_map(|(_, type_definitions)| type_definitions)
5426 .dedup()
5427 .collect(),
5428 ))
5429 })
5430 }
5431 }
5432
5433 pub fn implementations(
5434 &mut self,
5435 buffer: &Entity<Buffer>,
5436 position: PointUtf16,
5437 cx: &mut Context<Self>,
5438 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5439 if let Some((upstream_client, project_id)) = self.upstream_client() {
5440 let request = GetImplementations { position };
5441 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5442 return Task::ready(Ok(None));
5443 }
5444 let request_task = upstream_client.request_lsp(
5445 project_id,
5446 LSP_REQUEST_TIMEOUT,
5447 cx.background_executor().clone(),
5448 request.to_proto(project_id, buffer.read(cx)),
5449 );
5450 let buffer = buffer.clone();
5451 cx.spawn(async move |weak_project, cx| {
5452 let Some(project) = weak_project.upgrade() else {
5453 return Ok(None);
5454 };
5455 let Some(responses) = request_task.await? else {
5456 return Ok(None);
5457 };
5458 let actions = join_all(responses.payload.into_iter().map(|response| {
5459 GetImplementations { position }.response_from_proto(
5460 response.response,
5461 project.clone(),
5462 buffer.clone(),
5463 cx.clone(),
5464 )
5465 }))
5466 .await;
5467
5468 Ok(Some(
5469 actions
5470 .into_iter()
5471 .collect::<Result<Vec<Vec<_>>>>()?
5472 .into_iter()
5473 .flatten()
5474 .dedup()
5475 .collect(),
5476 ))
5477 })
5478 } else {
5479 let implementations_task = self.request_multiple_lsp_locally(
5480 buffer,
5481 Some(position),
5482 GetImplementations { position },
5483 cx,
5484 );
5485 cx.background_spawn(async move {
5486 Ok(Some(
5487 implementations_task
5488 .await
5489 .into_iter()
5490 .flat_map(|(_, implementations)| implementations)
5491 .dedup()
5492 .collect(),
5493 ))
5494 })
5495 }
5496 }
5497
5498 pub fn references(
5499 &mut self,
5500 buffer: &Entity<Buffer>,
5501 position: PointUtf16,
5502 cx: &mut Context<Self>,
5503 ) -> Task<Result<Option<Vec<Location>>>> {
5504 if let Some((upstream_client, project_id)) = self.upstream_client() {
5505 let request = GetReferences { position };
5506 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5507 return Task::ready(Ok(None));
5508 }
5509
5510 let request_task = upstream_client.request_lsp(
5511 project_id,
5512 LSP_REQUEST_TIMEOUT,
5513 cx.background_executor().clone(),
5514 request.to_proto(project_id, buffer.read(cx)),
5515 );
5516 let buffer = buffer.clone();
5517 cx.spawn(async move |weak_project, cx| {
5518 let Some(project) = weak_project.upgrade() else {
5519 return Ok(None);
5520 };
5521 let Some(responses) = request_task.await? else {
5522 return Ok(None);
5523 };
5524
5525 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5526 GetReferences { position }.response_from_proto(
5527 lsp_response.response,
5528 project.clone(),
5529 buffer.clone(),
5530 cx.clone(),
5531 )
5532 }))
5533 .await
5534 .into_iter()
5535 .collect::<Result<Vec<Vec<_>>>>()?
5536 .into_iter()
5537 .flatten()
5538 .dedup()
5539 .collect();
5540 Ok(Some(locations))
5541 })
5542 } else {
5543 let references_task = self.request_multiple_lsp_locally(
5544 buffer,
5545 Some(position),
5546 GetReferences { position },
5547 cx,
5548 );
5549 cx.background_spawn(async move {
5550 Ok(Some(
5551 references_task
5552 .await
5553 .into_iter()
5554 .flat_map(|(_, references)| references)
5555 .dedup()
5556 .collect(),
5557 ))
5558 })
5559 }
5560 }
5561
5562 pub fn code_actions(
5563 &mut self,
5564 buffer: &Entity<Buffer>,
5565 range: Range<Anchor>,
5566 kinds: Option<Vec<CodeActionKind>>,
5567 cx: &mut Context<Self>,
5568 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5569 if let Some((upstream_client, project_id)) = self.upstream_client() {
5570 let request = GetCodeActions {
5571 range: range.clone(),
5572 kinds: kinds.clone(),
5573 };
5574 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5575 return Task::ready(Ok(None));
5576 }
5577 let request_task = upstream_client.request_lsp(
5578 project_id,
5579 LSP_REQUEST_TIMEOUT,
5580 cx.background_executor().clone(),
5581 request.to_proto(project_id, buffer.read(cx)),
5582 );
5583 let buffer = buffer.clone();
5584 cx.spawn(async move |weak_project, cx| {
5585 let Some(project) = weak_project.upgrade() else {
5586 return Ok(None);
5587 };
5588 let Some(responses) = request_task.await? else {
5589 return Ok(None);
5590 };
5591 let actions = join_all(responses.payload.into_iter().map(|response| {
5592 GetCodeActions {
5593 range: range.clone(),
5594 kinds: kinds.clone(),
5595 }
5596 .response_from_proto(
5597 response.response,
5598 project.clone(),
5599 buffer.clone(),
5600 cx.clone(),
5601 )
5602 }))
5603 .await;
5604
5605 Ok(Some(
5606 actions
5607 .into_iter()
5608 .collect::<Result<Vec<Vec<_>>>>()?
5609 .into_iter()
5610 .flatten()
5611 .collect(),
5612 ))
5613 })
5614 } else {
5615 let all_actions_task = self.request_multiple_lsp_locally(
5616 buffer,
5617 Some(range.start),
5618 GetCodeActions { range, kinds },
5619 cx,
5620 );
5621 cx.background_spawn(async move {
5622 Ok(Some(
5623 all_actions_task
5624 .await
5625 .into_iter()
5626 .flat_map(|(_, actions)| actions)
5627 .collect(),
5628 ))
5629 })
5630 }
5631 }
5632
5633 pub fn code_lens_actions(
5634 &mut self,
5635 buffer: &Entity<Buffer>,
5636 cx: &mut Context<Self>,
5637 ) -> CodeLensTask {
5638 let version_queried_for = buffer.read(cx).version();
5639 let buffer_id = buffer.read(cx).remote_id();
5640
5641 if let Some(cached_data) = self.lsp_code_lens.get(&buffer_id)
5642 && !version_queried_for.changed_since(&cached_data.lens_for_version)
5643 {
5644 let has_different_servers = self.as_local().is_some_and(|local| {
5645 local
5646 .buffers_opened_in_servers
5647 .get(&buffer_id)
5648 .cloned()
5649 .unwrap_or_default()
5650 != cached_data.lens.keys().copied().collect()
5651 });
5652 if !has_different_servers {
5653 return Task::ready(Ok(Some(
5654 cached_data.lens.values().flatten().cloned().collect(),
5655 )))
5656 .shared();
5657 }
5658 }
5659
5660 let lsp_data = self.lsp_code_lens.entry(buffer_id).or_default();
5661 if let Some((updating_for, running_update)) = &lsp_data.update
5662 && !version_queried_for.changed_since(updating_for)
5663 {
5664 return running_update.clone();
5665 }
5666 let buffer = buffer.clone();
5667 let query_version_queried_for = version_queried_for.clone();
5668 let new_task = cx
5669 .spawn(async move |lsp_store, cx| {
5670 cx.background_executor()
5671 .timer(Duration::from_millis(30))
5672 .await;
5673 let fetched_lens = lsp_store
5674 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5675 .map_err(Arc::new)?
5676 .await
5677 .context("fetching code lens")
5678 .map_err(Arc::new);
5679 let fetched_lens = match fetched_lens {
5680 Ok(fetched_lens) => fetched_lens,
5681 Err(e) => {
5682 lsp_store
5683 .update(cx, |lsp_store, _| {
5684 lsp_store.lsp_code_lens.entry(buffer_id).or_default().update = None;
5685 })
5686 .ok();
5687 return Err(e);
5688 }
5689 };
5690
5691 lsp_store
5692 .update(cx, |lsp_store, _| {
5693 let lsp_data = lsp_store.lsp_code_lens.entry(buffer_id).or_default();
5694 if let Some(fetched_lens) = fetched_lens {
5695 if lsp_data.lens_for_version == query_version_queried_for {
5696 lsp_data.lens.extend(fetched_lens);
5697 } else if !lsp_data
5698 .lens_for_version
5699 .changed_since(&query_version_queried_for)
5700 {
5701 lsp_data.lens_for_version = query_version_queried_for;
5702 lsp_data.lens = fetched_lens;
5703 }
5704 }
5705 lsp_data.update = None;
5706 Some(lsp_data.lens.values().flatten().cloned().collect())
5707 })
5708 .map_err(Arc::new)
5709 })
5710 .shared();
5711 lsp_data.update = Some((version_queried_for, new_task.clone()));
5712 new_task
5713 }
5714
5715 fn fetch_code_lens(
5716 &mut self,
5717 buffer: &Entity<Buffer>,
5718 cx: &mut Context<Self>,
5719 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5720 if let Some((upstream_client, project_id)) = self.upstream_client() {
5721 let request = GetCodeLens;
5722 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5723 return Task::ready(Ok(None));
5724 }
5725 let request_task = upstream_client.request_lsp(
5726 project_id,
5727 LSP_REQUEST_TIMEOUT,
5728 cx.background_executor().clone(),
5729 request.to_proto(project_id, buffer.read(cx)),
5730 );
5731 let buffer = buffer.clone();
5732 cx.spawn(async move |weak_lsp_store, cx| {
5733 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5734 return Ok(None);
5735 };
5736 let Some(responses) = request_task.await? else {
5737 return Ok(None);
5738 };
5739
5740 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5741 let lsp_store = lsp_store.clone();
5742 let buffer = buffer.clone();
5743 let cx = cx.clone();
5744 async move {
5745 (
5746 LanguageServerId::from_proto(response.server_id),
5747 GetCodeLens
5748 .response_from_proto(response.response, lsp_store, buffer, cx)
5749 .await,
5750 )
5751 }
5752 }))
5753 .await;
5754
5755 let mut has_errors = false;
5756 let code_lens_actions = code_lens_actions
5757 .into_iter()
5758 .filter_map(|(server_id, code_lens)| match code_lens {
5759 Ok(code_lens) => Some((server_id, code_lens)),
5760 Err(e) => {
5761 has_errors = true;
5762 log::error!("{e:#}");
5763 None
5764 }
5765 })
5766 .collect::<HashMap<_, _>>();
5767 anyhow::ensure!(
5768 !has_errors || !code_lens_actions.is_empty(),
5769 "Failed to fetch code lens"
5770 );
5771 Ok(Some(code_lens_actions))
5772 })
5773 } else {
5774 let code_lens_actions_task =
5775 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5776 cx.background_spawn(async move {
5777 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5778 })
5779 }
5780 }
5781
5782 #[inline(never)]
5783 pub fn completions(
5784 &self,
5785 buffer: &Entity<Buffer>,
5786 position: PointUtf16,
5787 context: CompletionContext,
5788 cx: &mut Context<Self>,
5789 ) -> Task<Result<Vec<CompletionResponse>>> {
5790 let language_registry = self.languages.clone();
5791
5792 if let Some((upstream_client, project_id)) = self.upstream_client() {
5793 let request = GetCompletions { position, context };
5794 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5795 return Task::ready(Ok(Vec::new()));
5796 }
5797 let task = self.send_lsp_proto_request(
5798 buffer.clone(),
5799 upstream_client,
5800 project_id,
5801 request,
5802 cx,
5803 );
5804 let language = buffer.read(cx).language().cloned();
5805
5806 // In the future, we should provide project guests with the names of LSP adapters,
5807 // so that they can use the correct LSP adapter when computing labels. For now,
5808 // guests just use the first LSP adapter associated with the buffer's language.
5809 let lsp_adapter = language.as_ref().and_then(|language| {
5810 language_registry
5811 .lsp_adapters(&language.name())
5812 .first()
5813 .cloned()
5814 });
5815
5816 cx.foreground_executor().spawn(async move {
5817 let completion_response = task.await?;
5818 let completions = populate_labels_for_completions(
5819 completion_response.completions,
5820 language,
5821 lsp_adapter,
5822 )
5823 .await;
5824 Ok(vec![CompletionResponse {
5825 completions,
5826 is_incomplete: completion_response.is_incomplete,
5827 }])
5828 })
5829 } else if let Some(local) = self.as_local() {
5830 let snapshot = buffer.read(cx).snapshot();
5831 let offset = position.to_offset(&snapshot);
5832 let scope = snapshot.language_scope_at(offset);
5833 let language = snapshot.language().cloned();
5834 let completion_settings = language_settings(
5835 language.as_ref().map(|language| language.name()),
5836 buffer.read(cx).file(),
5837 cx,
5838 )
5839 .completions;
5840 if !completion_settings.lsp {
5841 return Task::ready(Ok(Vec::new()));
5842 }
5843
5844 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5845 local
5846 .language_servers_for_buffer(buffer, cx)
5847 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5848 .filter(|(adapter, _)| {
5849 scope
5850 .as_ref()
5851 .map(|scope| scope.language_allowed(&adapter.name))
5852 .unwrap_or(true)
5853 })
5854 .map(|(_, server)| server.server_id())
5855 .collect()
5856 });
5857
5858 let buffer = buffer.clone();
5859 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5860 let lsp_timeout = if lsp_timeout > 0 {
5861 Some(Duration::from_millis(lsp_timeout))
5862 } else {
5863 None
5864 };
5865 cx.spawn(async move |this, cx| {
5866 let mut tasks = Vec::with_capacity(server_ids.len());
5867 this.update(cx, |lsp_store, cx| {
5868 for server_id in server_ids {
5869 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5870 let lsp_timeout = lsp_timeout
5871 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5872 let mut timeout = cx.background_spawn(async move {
5873 match lsp_timeout {
5874 Some(lsp_timeout) => {
5875 lsp_timeout.await;
5876 true
5877 },
5878 None => false,
5879 }
5880 }).fuse();
5881 let mut lsp_request = lsp_store.request_lsp(
5882 buffer.clone(),
5883 LanguageServerToQuery::Other(server_id),
5884 GetCompletions {
5885 position,
5886 context: context.clone(),
5887 },
5888 cx,
5889 ).fuse();
5890 let new_task = cx.background_spawn(async move {
5891 select_biased! {
5892 response = lsp_request => anyhow::Ok(Some(response?)),
5893 timeout_happened = timeout => {
5894 if timeout_happened {
5895 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5896 Ok(None)
5897 } else {
5898 let completions = lsp_request.await?;
5899 Ok(Some(completions))
5900 }
5901 },
5902 }
5903 });
5904 tasks.push((lsp_adapter, new_task));
5905 }
5906 })?;
5907
5908 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
5909 let completion_response = task.await.ok()??;
5910 let completions = populate_labels_for_completions(
5911 completion_response.completions,
5912 language.clone(),
5913 lsp_adapter,
5914 )
5915 .await;
5916 Some(CompletionResponse {
5917 completions,
5918 is_incomplete: completion_response.is_incomplete,
5919 })
5920 });
5921
5922 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
5923
5924 Ok(responses.into_iter().flatten().collect())
5925 })
5926 } else {
5927 Task::ready(Err(anyhow!("No upstream client or local language server")))
5928 }
5929 }
5930
5931 pub fn resolve_completions(
5932 &self,
5933 buffer: Entity<Buffer>,
5934 completion_indices: Vec<usize>,
5935 completions: Rc<RefCell<Box<[Completion]>>>,
5936 cx: &mut Context<Self>,
5937 ) -> Task<Result<bool>> {
5938 let client = self.upstream_client();
5939 let buffer_id = buffer.read(cx).remote_id();
5940 let buffer_snapshot = buffer.read(cx).snapshot();
5941
5942 if !self.check_if_capable_for_proto_request(
5943 &buffer,
5944 GetCompletions::can_resolve_completions,
5945 cx,
5946 ) {
5947 return Task::ready(Ok(false));
5948 }
5949 cx.spawn(async move |lsp_store, cx| {
5950 let mut did_resolve = false;
5951 if let Some((client, project_id)) = client {
5952 for completion_index in completion_indices {
5953 let server_id = {
5954 let completion = &completions.borrow()[completion_index];
5955 completion.source.server_id()
5956 };
5957 if let Some(server_id) = server_id {
5958 if Self::resolve_completion_remote(
5959 project_id,
5960 server_id,
5961 buffer_id,
5962 completions.clone(),
5963 completion_index,
5964 client.clone(),
5965 )
5966 .await
5967 .log_err()
5968 .is_some()
5969 {
5970 did_resolve = true;
5971 }
5972 } else {
5973 resolve_word_completion(
5974 &buffer_snapshot,
5975 &mut completions.borrow_mut()[completion_index],
5976 );
5977 }
5978 }
5979 } else {
5980 for completion_index in completion_indices {
5981 let server_id = {
5982 let completion = &completions.borrow()[completion_index];
5983 completion.source.server_id()
5984 };
5985 if let Some(server_id) = server_id {
5986 let server_and_adapter = lsp_store
5987 .read_with(cx, |lsp_store, _| {
5988 let server = lsp_store.language_server_for_id(server_id)?;
5989 let adapter =
5990 lsp_store.language_server_adapter_for_id(server.server_id())?;
5991 Some((server, adapter))
5992 })
5993 .ok()
5994 .flatten();
5995 let Some((server, adapter)) = server_and_adapter else {
5996 continue;
5997 };
5998
5999 let resolved = Self::resolve_completion_local(
6000 server,
6001 completions.clone(),
6002 completion_index,
6003 )
6004 .await
6005 .log_err()
6006 .is_some();
6007 if resolved {
6008 Self::regenerate_completion_labels(
6009 adapter,
6010 &buffer_snapshot,
6011 completions.clone(),
6012 completion_index,
6013 )
6014 .await
6015 .log_err();
6016 did_resolve = true;
6017 }
6018 } else {
6019 resolve_word_completion(
6020 &buffer_snapshot,
6021 &mut completions.borrow_mut()[completion_index],
6022 );
6023 }
6024 }
6025 }
6026
6027 Ok(did_resolve)
6028 })
6029 }
6030
6031 async fn resolve_completion_local(
6032 server: Arc<lsp::LanguageServer>,
6033 completions: Rc<RefCell<Box<[Completion]>>>,
6034 completion_index: usize,
6035 ) -> Result<()> {
6036 let server_id = server.server_id();
6037 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6038 return Ok(());
6039 }
6040
6041 let request = {
6042 let completion = &completions.borrow()[completion_index];
6043 match &completion.source {
6044 CompletionSource::Lsp {
6045 lsp_completion,
6046 resolved,
6047 server_id: completion_server_id,
6048 ..
6049 } => {
6050 if *resolved {
6051 return Ok(());
6052 }
6053 anyhow::ensure!(
6054 server_id == *completion_server_id,
6055 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6056 );
6057 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6058 }
6059 CompletionSource::BufferWord { .. }
6060 | CompletionSource::Dap { .. }
6061 | CompletionSource::Custom => {
6062 return Ok(());
6063 }
6064 }
6065 };
6066 let resolved_completion = request
6067 .await
6068 .into_response()
6069 .context("resolve completion")?;
6070
6071 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6072 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6073
6074 let mut completions = completions.borrow_mut();
6075 let completion = &mut completions[completion_index];
6076 if let CompletionSource::Lsp {
6077 lsp_completion,
6078 resolved,
6079 server_id: completion_server_id,
6080 ..
6081 } = &mut completion.source
6082 {
6083 if *resolved {
6084 return Ok(());
6085 }
6086 anyhow::ensure!(
6087 server_id == *completion_server_id,
6088 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6089 );
6090 *lsp_completion = Box::new(resolved_completion);
6091 *resolved = true;
6092 }
6093 Ok(())
6094 }
6095
6096 async fn regenerate_completion_labels(
6097 adapter: Arc<CachedLspAdapter>,
6098 snapshot: &BufferSnapshot,
6099 completions: Rc<RefCell<Box<[Completion]>>>,
6100 completion_index: usize,
6101 ) -> Result<()> {
6102 let completion_item = completions.borrow()[completion_index]
6103 .source
6104 .lsp_completion(true)
6105 .map(Cow::into_owned);
6106 if let Some(lsp_documentation) = completion_item
6107 .as_ref()
6108 .and_then(|completion_item| completion_item.documentation.clone())
6109 {
6110 let mut completions = completions.borrow_mut();
6111 let completion = &mut completions[completion_index];
6112 completion.documentation = Some(lsp_documentation.into());
6113 } else {
6114 let mut completions = completions.borrow_mut();
6115 let completion = &mut completions[completion_index];
6116 completion.documentation = Some(CompletionDocumentation::Undocumented);
6117 }
6118
6119 let mut new_label = match completion_item {
6120 Some(completion_item) => {
6121 // 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
6122 // So we have to update the label here anyway...
6123 let language = snapshot.language();
6124 match language {
6125 Some(language) => {
6126 adapter
6127 .labels_for_completions(
6128 std::slice::from_ref(&completion_item),
6129 language,
6130 )
6131 .await?
6132 }
6133 None => Vec::new(),
6134 }
6135 .pop()
6136 .flatten()
6137 .unwrap_or_else(|| {
6138 CodeLabel::fallback_for_completion(
6139 &completion_item,
6140 language.map(|language| language.as_ref()),
6141 )
6142 })
6143 }
6144 None => CodeLabel::plain(
6145 completions.borrow()[completion_index].new_text.clone(),
6146 None,
6147 ),
6148 };
6149 ensure_uniform_list_compatible_label(&mut new_label);
6150
6151 let mut completions = completions.borrow_mut();
6152 let completion = &mut completions[completion_index];
6153 if completion.label.filter_text() == new_label.filter_text() {
6154 completion.label = new_label;
6155 } else {
6156 log::error!(
6157 "Resolved completion changed display label from {} to {}. \
6158 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6159 completion.label.text(),
6160 new_label.text(),
6161 completion.label.filter_text(),
6162 new_label.filter_text()
6163 );
6164 }
6165
6166 Ok(())
6167 }
6168
6169 async fn resolve_completion_remote(
6170 project_id: u64,
6171 server_id: LanguageServerId,
6172 buffer_id: BufferId,
6173 completions: Rc<RefCell<Box<[Completion]>>>,
6174 completion_index: usize,
6175 client: AnyProtoClient,
6176 ) -> Result<()> {
6177 let lsp_completion = {
6178 let completion = &completions.borrow()[completion_index];
6179 match &completion.source {
6180 CompletionSource::Lsp {
6181 lsp_completion,
6182 resolved,
6183 server_id: completion_server_id,
6184 ..
6185 } => {
6186 anyhow::ensure!(
6187 server_id == *completion_server_id,
6188 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6189 );
6190 if *resolved {
6191 return Ok(());
6192 }
6193 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6194 }
6195 CompletionSource::Custom
6196 | CompletionSource::Dap { .. }
6197 | CompletionSource::BufferWord { .. } => {
6198 return Ok(());
6199 }
6200 }
6201 };
6202 let request = proto::ResolveCompletionDocumentation {
6203 project_id,
6204 language_server_id: server_id.0 as u64,
6205 lsp_completion,
6206 buffer_id: buffer_id.into(),
6207 };
6208
6209 let response = client
6210 .request(request)
6211 .await
6212 .context("completion documentation resolve proto request")?;
6213 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6214
6215 let documentation = if response.documentation.is_empty() {
6216 CompletionDocumentation::Undocumented
6217 } else if response.documentation_is_markdown {
6218 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6219 } else if response.documentation.lines().count() <= 1 {
6220 CompletionDocumentation::SingleLine(response.documentation.into())
6221 } else {
6222 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6223 };
6224
6225 let mut completions = completions.borrow_mut();
6226 let completion = &mut completions[completion_index];
6227 completion.documentation = Some(documentation);
6228 if let CompletionSource::Lsp {
6229 insert_range,
6230 lsp_completion,
6231 resolved,
6232 server_id: completion_server_id,
6233 lsp_defaults: _,
6234 } = &mut completion.source
6235 {
6236 let completion_insert_range = response
6237 .old_insert_start
6238 .and_then(deserialize_anchor)
6239 .zip(response.old_insert_end.and_then(deserialize_anchor));
6240 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6241
6242 if *resolved {
6243 return Ok(());
6244 }
6245 anyhow::ensure!(
6246 server_id == *completion_server_id,
6247 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6248 );
6249 *lsp_completion = Box::new(resolved_lsp_completion);
6250 *resolved = true;
6251 }
6252
6253 let replace_range = response
6254 .old_replace_start
6255 .and_then(deserialize_anchor)
6256 .zip(response.old_replace_end.and_then(deserialize_anchor));
6257 if let Some((old_replace_start, old_replace_end)) = replace_range
6258 && !response.new_text.is_empty()
6259 {
6260 completion.new_text = response.new_text;
6261 completion.replace_range = old_replace_start..old_replace_end;
6262 }
6263
6264 Ok(())
6265 }
6266
6267 pub fn apply_additional_edits_for_completion(
6268 &self,
6269 buffer_handle: Entity<Buffer>,
6270 completions: Rc<RefCell<Box<[Completion]>>>,
6271 completion_index: usize,
6272 push_to_history: bool,
6273 cx: &mut Context<Self>,
6274 ) -> Task<Result<Option<Transaction>>> {
6275 if let Some((client, project_id)) = self.upstream_client() {
6276 let buffer = buffer_handle.read(cx);
6277 let buffer_id = buffer.remote_id();
6278 cx.spawn(async move |_, cx| {
6279 let request = {
6280 let completion = completions.borrow()[completion_index].clone();
6281 proto::ApplyCompletionAdditionalEdits {
6282 project_id,
6283 buffer_id: buffer_id.into(),
6284 completion: Some(Self::serialize_completion(&CoreCompletion {
6285 replace_range: completion.replace_range,
6286 new_text: completion.new_text,
6287 source: completion.source,
6288 })),
6289 }
6290 };
6291
6292 if let Some(transaction) = client.request(request).await?.transaction {
6293 let transaction = language::proto::deserialize_transaction(transaction)?;
6294 buffer_handle
6295 .update(cx, |buffer, _| {
6296 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6297 })?
6298 .await?;
6299 if push_to_history {
6300 buffer_handle.update(cx, |buffer, _| {
6301 buffer.push_transaction(transaction.clone(), Instant::now());
6302 buffer.finalize_last_transaction();
6303 })?;
6304 }
6305 Ok(Some(transaction))
6306 } else {
6307 Ok(None)
6308 }
6309 })
6310 } else {
6311 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6312 let completion = &completions.borrow()[completion_index];
6313 let server_id = completion.source.server_id()?;
6314 Some(
6315 self.language_server_for_local_buffer(buffer, server_id, cx)?
6316 .1
6317 .clone(),
6318 )
6319 }) else {
6320 return Task::ready(Ok(None));
6321 };
6322
6323 cx.spawn(async move |this, cx| {
6324 Self::resolve_completion_local(
6325 server.clone(),
6326 completions.clone(),
6327 completion_index,
6328 )
6329 .await
6330 .context("resolving completion")?;
6331 let completion = completions.borrow()[completion_index].clone();
6332 let additional_text_edits = completion
6333 .source
6334 .lsp_completion(true)
6335 .as_ref()
6336 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6337 if let Some(edits) = additional_text_edits {
6338 let edits = this
6339 .update(cx, |this, cx| {
6340 this.as_local_mut().unwrap().edits_from_lsp(
6341 &buffer_handle,
6342 edits,
6343 server.server_id(),
6344 None,
6345 cx,
6346 )
6347 })?
6348 .await?;
6349
6350 buffer_handle.update(cx, |buffer, cx| {
6351 buffer.finalize_last_transaction();
6352 buffer.start_transaction();
6353
6354 for (range, text) in edits {
6355 let primary = &completion.replace_range;
6356 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6357 && primary.end.cmp(&range.start, buffer).is_ge();
6358 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6359 && range.end.cmp(&primary.end, buffer).is_ge();
6360
6361 //Skip additional edits which overlap with the primary completion edit
6362 //https://github.com/zed-industries/zed/pull/1871
6363 if !start_within && !end_within {
6364 buffer.edit([(range, text)], None, cx);
6365 }
6366 }
6367
6368 let transaction = if buffer.end_transaction(cx).is_some() {
6369 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6370 if !push_to_history {
6371 buffer.forget_transaction(transaction.id);
6372 }
6373 Some(transaction)
6374 } else {
6375 None
6376 };
6377 Ok(transaction)
6378 })?
6379 } else {
6380 Ok(None)
6381 }
6382 })
6383 }
6384 }
6385
6386 pub fn pull_diagnostics(
6387 &mut self,
6388 buffer: Entity<Buffer>,
6389 cx: &mut Context<Self>,
6390 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6391 let buffer_id = buffer.read(cx).remote_id();
6392
6393 if let Some((client, upstream_project_id)) = self.upstream_client() {
6394 let request = GetDocumentDiagnostics {
6395 previous_result_id: None,
6396 };
6397 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6398 return Task::ready(Ok(None));
6399 }
6400 let request_task = client.request_lsp(
6401 upstream_project_id,
6402 LSP_REQUEST_TIMEOUT,
6403 cx.background_executor().clone(),
6404 request.to_proto(upstream_project_id, buffer.read(cx)),
6405 );
6406 cx.background_spawn(async move {
6407 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6408 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6409 // Do not attempt to further process the dummy responses here.
6410 let _response = request_task.await?;
6411 Ok(None)
6412 })
6413 } else {
6414 let server_ids = buffer.update(cx, |buffer, cx| {
6415 self.language_servers_for_local_buffer(buffer, cx)
6416 .map(|(_, server)| server.server_id())
6417 .collect::<Vec<_>>()
6418 });
6419 let pull_diagnostics = server_ids
6420 .into_iter()
6421 .map(|server_id| {
6422 let result_id = self.result_id(server_id, buffer_id, cx);
6423 self.request_lsp(
6424 buffer.clone(),
6425 LanguageServerToQuery::Other(server_id),
6426 GetDocumentDiagnostics {
6427 previous_result_id: result_id,
6428 },
6429 cx,
6430 )
6431 })
6432 .collect::<Vec<_>>();
6433
6434 cx.background_spawn(async move {
6435 let mut responses = Vec::new();
6436 for diagnostics in join_all(pull_diagnostics).await {
6437 responses.extend(diagnostics?);
6438 }
6439 Ok(Some(responses))
6440 })
6441 }
6442 }
6443
6444 pub fn inlay_hints(
6445 &mut self,
6446 buffer: Entity<Buffer>,
6447 range: Range<Anchor>,
6448 cx: &mut Context<Self>,
6449 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6450 let range_start = range.start;
6451 let range_end = range.end;
6452 let buffer_id = buffer.read(cx).remote_id().into();
6453 let request = InlayHints { range };
6454
6455 if let Some((client, project_id)) = self.upstream_client() {
6456 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6457 return Task::ready(Ok(Vec::new()));
6458 }
6459 let proto_request = proto::InlayHints {
6460 project_id,
6461 buffer_id,
6462 start: Some(serialize_anchor(&range_start)),
6463 end: Some(serialize_anchor(&range_end)),
6464 version: serialize_version(&buffer.read(cx).version()),
6465 };
6466 cx.spawn(async move |project, cx| {
6467 let response = client
6468 .request(proto_request)
6469 .await
6470 .context("inlay hints proto request")?;
6471 LspCommand::response_from_proto(
6472 request,
6473 response,
6474 project.upgrade().context("No project")?,
6475 buffer.clone(),
6476 cx.clone(),
6477 )
6478 .await
6479 .context("inlay hints proto response conversion")
6480 })
6481 } else {
6482 let lsp_request_task = self.request_lsp(
6483 buffer.clone(),
6484 LanguageServerToQuery::FirstCapable,
6485 request,
6486 cx,
6487 );
6488 cx.spawn(async move |_, cx| {
6489 buffer
6490 .update(cx, |buffer, _| {
6491 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6492 })?
6493 .await
6494 .context("waiting for inlay hint request range edits")?;
6495 lsp_request_task.await.context("inlay hints LSP request")
6496 })
6497 }
6498 }
6499
6500 pub fn pull_diagnostics_for_buffer(
6501 &mut self,
6502 buffer: Entity<Buffer>,
6503 cx: &mut Context<Self>,
6504 ) -> Task<anyhow::Result<()>> {
6505 let diagnostics = self.pull_diagnostics(buffer, cx);
6506 cx.spawn(async move |lsp_store, cx| {
6507 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6508 return Ok(());
6509 };
6510 lsp_store.update(cx, |lsp_store, cx| {
6511 if lsp_store.as_local().is_none() {
6512 return;
6513 }
6514
6515 let mut unchanged_buffers = HashSet::default();
6516 let mut changed_buffers = HashSet::default();
6517 let server_diagnostics_updates = diagnostics
6518 .into_iter()
6519 .filter_map(|diagnostics_set| match diagnostics_set {
6520 LspPullDiagnostics::Response {
6521 server_id,
6522 uri,
6523 diagnostics,
6524 } => Some((server_id, uri, diagnostics)),
6525 LspPullDiagnostics::Default => None,
6526 })
6527 .fold(
6528 HashMap::default(),
6529 |mut acc, (server_id, uri, diagnostics)| {
6530 let (result_id, diagnostics) = match diagnostics {
6531 PulledDiagnostics::Unchanged { result_id } => {
6532 unchanged_buffers.insert(uri.clone());
6533 (Some(result_id), Vec::new())
6534 }
6535 PulledDiagnostics::Changed {
6536 result_id,
6537 diagnostics,
6538 } => {
6539 changed_buffers.insert(uri.clone());
6540 (result_id, diagnostics)
6541 }
6542 };
6543 let disk_based_sources = Cow::Owned(
6544 lsp_store
6545 .language_server_adapter_for_id(server_id)
6546 .as_ref()
6547 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6548 .unwrap_or(&[])
6549 .to_vec(),
6550 );
6551 acc.entry(server_id).or_insert_with(Vec::new).push(
6552 DocumentDiagnosticsUpdate {
6553 server_id,
6554 diagnostics: lsp::PublishDiagnosticsParams {
6555 uri,
6556 diagnostics,
6557 version: None,
6558 },
6559 result_id,
6560 disk_based_sources,
6561 },
6562 );
6563 acc
6564 },
6565 );
6566
6567 for diagnostic_updates in server_diagnostics_updates.into_values() {
6568 lsp_store
6569 .merge_lsp_diagnostics(
6570 DiagnosticSourceKind::Pulled,
6571 diagnostic_updates,
6572 |buffer, old_diagnostic, cx| {
6573 File::from_dyn(buffer.file())
6574 .and_then(|file| {
6575 let abs_path = file.as_local()?.abs_path(cx);
6576 lsp::Url::from_file_path(abs_path).ok()
6577 })
6578 .is_none_or(|buffer_uri| {
6579 unchanged_buffers.contains(&buffer_uri)
6580 || match old_diagnostic.source_kind {
6581 DiagnosticSourceKind::Pulled => {
6582 !changed_buffers.contains(&buffer_uri)
6583 }
6584 DiagnosticSourceKind::Other
6585 | DiagnosticSourceKind::Pushed => true,
6586 }
6587 })
6588 },
6589 cx,
6590 )
6591 .log_err();
6592 }
6593 })
6594 })
6595 }
6596
6597 pub fn document_colors(
6598 &mut self,
6599 fetch_strategy: LspFetchStrategy,
6600 buffer: Entity<Buffer>,
6601 cx: &mut Context<Self>,
6602 ) -> Option<DocumentColorTask> {
6603 let version_queried_for = buffer.read(cx).version();
6604 let buffer_id = buffer.read(cx).remote_id();
6605
6606 match fetch_strategy {
6607 LspFetchStrategy::IgnoreCache => {}
6608 LspFetchStrategy::UseCache {
6609 known_cache_version,
6610 } => {
6611 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id)
6612 && !version_queried_for.changed_since(&cached_data.colors_for_version)
6613 {
6614 let has_different_servers = self.as_local().is_some_and(|local| {
6615 local
6616 .buffers_opened_in_servers
6617 .get(&buffer_id)
6618 .cloned()
6619 .unwrap_or_default()
6620 != cached_data.colors.keys().copied().collect()
6621 });
6622 if !has_different_servers {
6623 if Some(cached_data.cache_version) == known_cache_version {
6624 return None;
6625 } else {
6626 return Some(
6627 Task::ready(Ok(DocumentColors {
6628 colors: cached_data
6629 .colors
6630 .values()
6631 .flatten()
6632 .cloned()
6633 .collect(),
6634 cache_version: Some(cached_data.cache_version),
6635 }))
6636 .shared(),
6637 );
6638 }
6639 }
6640 }
6641 }
6642 }
6643
6644 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6645 if let Some((updating_for, running_update)) = &lsp_data.colors_update
6646 && !version_queried_for.changed_since(updating_for)
6647 {
6648 return Some(running_update.clone());
6649 }
6650 let query_version_queried_for = version_queried_for.clone();
6651 let new_task = cx
6652 .spawn(async move |lsp_store, cx| {
6653 cx.background_executor()
6654 .timer(Duration::from_millis(30))
6655 .await;
6656 let fetched_colors = lsp_store
6657 .update(cx, |lsp_store, cx| {
6658 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6659 })?
6660 .await
6661 .context("fetching document colors")
6662 .map_err(Arc::new);
6663 let fetched_colors = match fetched_colors {
6664 Ok(fetched_colors) => {
6665 if fetch_strategy != LspFetchStrategy::IgnoreCache
6666 && Some(true)
6667 == buffer
6668 .update(cx, |buffer, _| {
6669 buffer.version() != query_version_queried_for
6670 })
6671 .ok()
6672 {
6673 return Ok(DocumentColors::default());
6674 }
6675 fetched_colors
6676 }
6677 Err(e) => {
6678 lsp_store
6679 .update(cx, |lsp_store, _| {
6680 lsp_store
6681 .lsp_document_colors
6682 .entry(buffer_id)
6683 .or_default()
6684 .colors_update = None;
6685 })
6686 .ok();
6687 return Err(e);
6688 }
6689 };
6690
6691 lsp_store
6692 .update(cx, |lsp_store, _| {
6693 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6694
6695 if let Some(fetched_colors) = fetched_colors {
6696 if lsp_data.colors_for_version == query_version_queried_for {
6697 lsp_data.colors.extend(fetched_colors);
6698 lsp_data.cache_version += 1;
6699 } else if !lsp_data
6700 .colors_for_version
6701 .changed_since(&query_version_queried_for)
6702 {
6703 lsp_data.colors_for_version = query_version_queried_for;
6704 lsp_data.colors = fetched_colors;
6705 lsp_data.cache_version += 1;
6706 }
6707 }
6708 lsp_data.colors_update = None;
6709 let colors = lsp_data
6710 .colors
6711 .values()
6712 .flatten()
6713 .cloned()
6714 .collect::<HashSet<_>>();
6715 DocumentColors {
6716 colors,
6717 cache_version: Some(lsp_data.cache_version),
6718 }
6719 })
6720 .map_err(Arc::new)
6721 })
6722 .shared();
6723 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6724 Some(new_task)
6725 }
6726
6727 fn fetch_document_colors_for_buffer(
6728 &mut self,
6729 buffer: &Entity<Buffer>,
6730 cx: &mut Context<Self>,
6731 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
6732 if let Some((client, project_id)) = self.upstream_client() {
6733 let request = GetDocumentColor {};
6734 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6735 return Task::ready(Ok(None));
6736 }
6737
6738 let request_task = client.request_lsp(
6739 project_id,
6740 LSP_REQUEST_TIMEOUT,
6741 cx.background_executor().clone(),
6742 request.to_proto(project_id, buffer.read(cx)),
6743 );
6744 let buffer = buffer.clone();
6745 cx.spawn(async move |lsp_store, cx| {
6746 let Some(project) = lsp_store.upgrade() else {
6747 return Ok(None);
6748 };
6749 let colors = join_all(
6750 request_task
6751 .await
6752 .log_err()
6753 .flatten()
6754 .map(|response| response.payload)
6755 .unwrap_or_default()
6756 .into_iter()
6757 .map(|color_response| {
6758 let response = request.response_from_proto(
6759 color_response.response,
6760 project.clone(),
6761 buffer.clone(),
6762 cx.clone(),
6763 );
6764 async move {
6765 (
6766 LanguageServerId::from_proto(color_response.server_id),
6767 response.await.log_err().unwrap_or_default(),
6768 )
6769 }
6770 }),
6771 )
6772 .await
6773 .into_iter()
6774 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6775 acc.entry(server_id)
6776 .or_insert_with(HashSet::default)
6777 .extend(colors);
6778 acc
6779 });
6780 Ok(Some(colors))
6781 })
6782 } else {
6783 let document_colors_task =
6784 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
6785 cx.background_spawn(async move {
6786 Ok(Some(
6787 document_colors_task
6788 .await
6789 .into_iter()
6790 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
6791 acc.entry(server_id)
6792 .or_insert_with(HashSet::default)
6793 .extend(colors);
6794 acc
6795 })
6796 .into_iter()
6797 .collect(),
6798 ))
6799 })
6800 }
6801 }
6802
6803 pub fn signature_help<T: ToPointUtf16>(
6804 &mut self,
6805 buffer: &Entity<Buffer>,
6806 position: T,
6807 cx: &mut Context<Self>,
6808 ) -> Task<Option<Vec<SignatureHelp>>> {
6809 let position = position.to_point_utf16(buffer.read(cx));
6810
6811 if let Some((client, upstream_project_id)) = self.upstream_client() {
6812 let request = GetSignatureHelp { position };
6813 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6814 return Task::ready(None);
6815 }
6816 let request_task = client.request_lsp(
6817 upstream_project_id,
6818 LSP_REQUEST_TIMEOUT,
6819 cx.background_executor().clone(),
6820 request.to_proto(upstream_project_id, buffer.read(cx)),
6821 );
6822 let buffer = buffer.clone();
6823 cx.spawn(async move |weak_project, cx| {
6824 let project = weak_project.upgrade()?;
6825 let signatures = join_all(
6826 request_task
6827 .await
6828 .log_err()
6829 .flatten()
6830 .map(|response| response.payload)
6831 .unwrap_or_default()
6832 .into_iter()
6833 .map(|response| {
6834 let response = GetSignatureHelp { position }.response_from_proto(
6835 response.response,
6836 project.clone(),
6837 buffer.clone(),
6838 cx.clone(),
6839 );
6840 async move { response.await.log_err().flatten() }
6841 }),
6842 )
6843 .await
6844 .into_iter()
6845 .flatten()
6846 .collect();
6847 Some(signatures)
6848 })
6849 } else {
6850 let all_actions_task = self.request_multiple_lsp_locally(
6851 buffer,
6852 Some(position),
6853 GetSignatureHelp { position },
6854 cx,
6855 );
6856 cx.background_spawn(async move {
6857 Some(
6858 all_actions_task
6859 .await
6860 .into_iter()
6861 .flat_map(|(_, actions)| actions)
6862 .collect::<Vec<_>>(),
6863 )
6864 })
6865 }
6866 }
6867
6868 pub fn hover(
6869 &mut self,
6870 buffer: &Entity<Buffer>,
6871 position: PointUtf16,
6872 cx: &mut Context<Self>,
6873 ) -> Task<Option<Vec<Hover>>> {
6874 if let Some((client, upstream_project_id)) = self.upstream_client() {
6875 let request = GetHover { position };
6876 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6877 return Task::ready(None);
6878 }
6879 let request_task = client.request_lsp(
6880 upstream_project_id,
6881 LSP_REQUEST_TIMEOUT,
6882 cx.background_executor().clone(),
6883 request.to_proto(upstream_project_id, buffer.read(cx)),
6884 );
6885 let buffer = buffer.clone();
6886 cx.spawn(async move |weak_project, cx| {
6887 let project = weak_project.upgrade()?;
6888 let hovers = join_all(
6889 request_task
6890 .await
6891 .log_err()
6892 .flatten()
6893 .map(|response| response.payload)
6894 .unwrap_or_default()
6895 .into_iter()
6896 .map(|response| {
6897 let response = GetHover { position }.response_from_proto(
6898 response.response,
6899 project.clone(),
6900 buffer.clone(),
6901 cx.clone(),
6902 );
6903 async move {
6904 response
6905 .await
6906 .log_err()
6907 .flatten()
6908 .and_then(remove_empty_hover_blocks)
6909 }
6910 }),
6911 )
6912 .await
6913 .into_iter()
6914 .flatten()
6915 .collect();
6916 Some(hovers)
6917 })
6918 } else {
6919 let all_actions_task = self.request_multiple_lsp_locally(
6920 buffer,
6921 Some(position),
6922 GetHover { position },
6923 cx,
6924 );
6925 cx.background_spawn(async move {
6926 Some(
6927 all_actions_task
6928 .await
6929 .into_iter()
6930 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
6931 .collect::<Vec<Hover>>(),
6932 )
6933 })
6934 }
6935 }
6936
6937 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
6938 let language_registry = self.languages.clone();
6939
6940 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
6941 let request = upstream_client.request(proto::GetProjectSymbols {
6942 project_id: *project_id,
6943 query: query.to_string(),
6944 });
6945 cx.foreground_executor().spawn(async move {
6946 let response = request.await?;
6947 let mut symbols = Vec::new();
6948 let core_symbols = response
6949 .symbols
6950 .into_iter()
6951 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
6952 .collect::<Vec<_>>();
6953 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
6954 .await;
6955 Ok(symbols)
6956 })
6957 } else if let Some(local) = self.as_local() {
6958 struct WorkspaceSymbolsResult {
6959 server_id: LanguageServerId,
6960 lsp_adapter: Arc<CachedLspAdapter>,
6961 worktree: WeakEntity<Worktree>,
6962 worktree_abs_path: Arc<Path>,
6963 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
6964 }
6965
6966 let mut requests = Vec::new();
6967 let mut requested_servers = BTreeSet::new();
6968 for (seed, state) in local.language_server_ids.iter() {
6969 let Some(worktree_handle) = self
6970 .worktree_store
6971 .read(cx)
6972 .worktree_for_id(seed.worktree_id, cx)
6973 else {
6974 continue;
6975 };
6976 let worktree = worktree_handle.read(cx);
6977 if !worktree.is_visible() {
6978 continue;
6979 }
6980
6981 if !requested_servers.insert(state.id) {
6982 continue;
6983 }
6984
6985 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
6986 Some(LanguageServerState::Running {
6987 adapter, server, ..
6988 }) => (adapter.clone(), server),
6989
6990 _ => continue,
6991 };
6992 let supports_workspace_symbol_request =
6993 match server.capabilities().workspace_symbol_provider {
6994 Some(OneOf::Left(supported)) => supported,
6995 Some(OneOf::Right(_)) => true,
6996 None => false,
6997 };
6998 if !supports_workspace_symbol_request {
6999 continue;
7000 }
7001 let worktree_abs_path = worktree.abs_path().clone();
7002 let worktree_handle = worktree_handle.clone();
7003 let server_id = server.server_id();
7004 requests.push(
7005 server
7006 .request::<lsp::request::WorkspaceSymbolRequest>(
7007 lsp::WorkspaceSymbolParams {
7008 query: query.to_string(),
7009 ..Default::default()
7010 },
7011 )
7012 .map(move |response| {
7013 let lsp_symbols = response.into_response()
7014 .context("workspace symbols request")
7015 .log_err()
7016 .flatten()
7017 .map(|symbol_response| match symbol_response {
7018 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7019 flat_responses.into_iter().map(|lsp_symbol| {
7020 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7021 }).collect::<Vec<_>>()
7022 }
7023 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7024 nested_responses.into_iter().filter_map(|lsp_symbol| {
7025 let location = match lsp_symbol.location {
7026 OneOf::Left(location) => location,
7027 OneOf::Right(_) => {
7028 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7029 return None
7030 }
7031 };
7032 Some((lsp_symbol.name, lsp_symbol.kind, location))
7033 }).collect::<Vec<_>>()
7034 }
7035 }).unwrap_or_default();
7036
7037 WorkspaceSymbolsResult {
7038 server_id,
7039 lsp_adapter,
7040 worktree: worktree_handle.downgrade(),
7041 worktree_abs_path,
7042 lsp_symbols,
7043 }
7044 }),
7045 );
7046 }
7047
7048 cx.spawn(async move |this, cx| {
7049 let responses = futures::future::join_all(requests).await;
7050 let this = match this.upgrade() {
7051 Some(this) => this,
7052 None => return Ok(Vec::new()),
7053 };
7054
7055 let mut symbols = Vec::new();
7056 for result in responses {
7057 let core_symbols = this.update(cx, |this, cx| {
7058 result
7059 .lsp_symbols
7060 .into_iter()
7061 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7062 let abs_path = symbol_location.uri.to_file_path().ok()?;
7063 let source_worktree = result.worktree.upgrade()?;
7064 let source_worktree_id = source_worktree.read(cx).id();
7065
7066 let path;
7067 let worktree;
7068 if let Some((tree, rel_path)) =
7069 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7070 {
7071 worktree = tree;
7072 path = rel_path;
7073 } else {
7074 worktree = source_worktree;
7075 path = relativize_path(&result.worktree_abs_path, &abs_path);
7076 }
7077
7078 let worktree_id = worktree.read(cx).id();
7079 let project_path = ProjectPath {
7080 worktree_id,
7081 path: path.into(),
7082 };
7083 let signature = this.symbol_signature(&project_path);
7084 Some(CoreSymbol {
7085 source_language_server_id: result.server_id,
7086 language_server_name: result.lsp_adapter.name.clone(),
7087 source_worktree_id,
7088 path: project_path,
7089 kind: symbol_kind,
7090 name: symbol_name,
7091 range: range_from_lsp(symbol_location.range),
7092 signature,
7093 })
7094 })
7095 .collect()
7096 })?;
7097
7098 populate_labels_for_symbols(
7099 core_symbols,
7100 &language_registry,
7101 Some(result.lsp_adapter),
7102 &mut symbols,
7103 )
7104 .await;
7105 }
7106
7107 Ok(symbols)
7108 })
7109 } else {
7110 Task::ready(Err(anyhow!("No upstream client or local language server")))
7111 }
7112 }
7113
7114 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7115 let mut summary = DiagnosticSummary::default();
7116 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7117 summary.error_count += path_summary.error_count;
7118 summary.warning_count += path_summary.warning_count;
7119 }
7120 summary
7121 }
7122
7123 pub fn diagnostic_summaries<'a>(
7124 &'a self,
7125 include_ignored: bool,
7126 cx: &'a App,
7127 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7128 self.worktree_store
7129 .read(cx)
7130 .visible_worktrees(cx)
7131 .filter_map(|worktree| {
7132 let worktree = worktree.read(cx);
7133 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7134 })
7135 .flat_map(move |(worktree, summaries)| {
7136 let worktree_id = worktree.id();
7137 summaries
7138 .iter()
7139 .filter(move |(path, _)| {
7140 include_ignored
7141 || worktree
7142 .entry_for_path(path.as_ref())
7143 .is_some_and(|entry| !entry.is_ignored)
7144 })
7145 .flat_map(move |(path, summaries)| {
7146 summaries.iter().map(move |(server_id, summary)| {
7147 (
7148 ProjectPath {
7149 worktree_id,
7150 path: path.clone(),
7151 },
7152 *server_id,
7153 *summary,
7154 )
7155 })
7156 })
7157 })
7158 }
7159
7160 pub fn on_buffer_edited(
7161 &mut self,
7162 buffer: Entity<Buffer>,
7163 cx: &mut Context<Self>,
7164 ) -> Option<()> {
7165 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7166 Some(
7167 self.as_local()?
7168 .language_servers_for_buffer(buffer, cx)
7169 .map(|i| i.1.clone())
7170 .collect(),
7171 )
7172 })?;
7173
7174 let buffer = buffer.read(cx);
7175 let file = File::from_dyn(buffer.file())?;
7176 let abs_path = file.as_local()?.abs_path(cx);
7177 let uri = lsp::Url::from_file_path(abs_path).unwrap();
7178 let next_snapshot = buffer.text_snapshot();
7179 for language_server in language_servers {
7180 let language_server = language_server.clone();
7181
7182 let buffer_snapshots = self
7183 .as_local_mut()
7184 .unwrap()
7185 .buffer_snapshots
7186 .get_mut(&buffer.remote_id())
7187 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7188 let previous_snapshot = buffer_snapshots.last()?;
7189
7190 let build_incremental_change = || {
7191 buffer
7192 .edits_since::<Dimensions<PointUtf16, usize>>(
7193 previous_snapshot.snapshot.version(),
7194 )
7195 .map(|edit| {
7196 let edit_start = edit.new.start.0;
7197 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7198 let new_text = next_snapshot
7199 .text_for_range(edit.new.start.1..edit.new.end.1)
7200 .collect();
7201 lsp::TextDocumentContentChangeEvent {
7202 range: Some(lsp::Range::new(
7203 point_to_lsp(edit_start),
7204 point_to_lsp(edit_end),
7205 )),
7206 range_length: None,
7207 text: new_text,
7208 }
7209 })
7210 .collect()
7211 };
7212
7213 let document_sync_kind = language_server
7214 .capabilities()
7215 .text_document_sync
7216 .as_ref()
7217 .and_then(|sync| match sync {
7218 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7219 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7220 });
7221
7222 let content_changes: Vec<_> = match document_sync_kind {
7223 Some(lsp::TextDocumentSyncKind::FULL) => {
7224 vec![lsp::TextDocumentContentChangeEvent {
7225 range: None,
7226 range_length: None,
7227 text: next_snapshot.text(),
7228 }]
7229 }
7230 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7231 _ => {
7232 #[cfg(any(test, feature = "test-support"))]
7233 {
7234 build_incremental_change()
7235 }
7236
7237 #[cfg(not(any(test, feature = "test-support")))]
7238 {
7239 continue;
7240 }
7241 }
7242 };
7243
7244 let next_version = previous_snapshot.version + 1;
7245 buffer_snapshots.push(LspBufferSnapshot {
7246 version: next_version,
7247 snapshot: next_snapshot.clone(),
7248 });
7249
7250 language_server
7251 .notify::<lsp::notification::DidChangeTextDocument>(
7252 &lsp::DidChangeTextDocumentParams {
7253 text_document: lsp::VersionedTextDocumentIdentifier::new(
7254 uri.clone(),
7255 next_version,
7256 ),
7257 content_changes,
7258 },
7259 )
7260 .ok();
7261 self.pull_workspace_diagnostics(language_server.server_id());
7262 }
7263
7264 None
7265 }
7266
7267 pub fn on_buffer_saved(
7268 &mut self,
7269 buffer: Entity<Buffer>,
7270 cx: &mut Context<Self>,
7271 ) -> Option<()> {
7272 let file = File::from_dyn(buffer.read(cx).file())?;
7273 let worktree_id = file.worktree_id(cx);
7274 let abs_path = file.as_local()?.abs_path(cx);
7275 let text_document = lsp::TextDocumentIdentifier {
7276 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7277 };
7278 let local = self.as_local()?;
7279
7280 for server in local.language_servers_for_worktree(worktree_id) {
7281 if let Some(include_text) = include_text(server.as_ref()) {
7282 let text = if include_text {
7283 Some(buffer.read(cx).text())
7284 } else {
7285 None
7286 };
7287 server
7288 .notify::<lsp::notification::DidSaveTextDocument>(
7289 &lsp::DidSaveTextDocumentParams {
7290 text_document: text_document.clone(),
7291 text,
7292 },
7293 )
7294 .ok();
7295 }
7296 }
7297
7298 let language_servers = buffer.update(cx, |buffer, cx| {
7299 local.language_server_ids_for_buffer(buffer, cx)
7300 });
7301 for language_server_id in language_servers {
7302 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7303 }
7304
7305 None
7306 }
7307
7308 async fn refresh_workspace_configurations(
7309 lsp_store: &WeakEntity<Self>,
7310 fs: Arc<dyn Fs>,
7311 cx: &mut AsyncApp,
7312 ) {
7313 maybe!(async move {
7314 let mut refreshed_servers = HashSet::default();
7315 let servers = lsp_store
7316 .update(cx, |lsp_store, cx| {
7317 let local = lsp_store.as_local()?;
7318
7319 let servers = local
7320 .language_server_ids
7321 .iter()
7322 .filter_map(|(seed, state)| {
7323 let worktree = lsp_store
7324 .worktree_store
7325 .read(cx)
7326 .worktree_for_id(seed.worktree_id, cx);
7327 let delegate: Arc<dyn LspAdapterDelegate> =
7328 worktree.map(|worktree| {
7329 LocalLspAdapterDelegate::new(
7330 local.languages.clone(),
7331 &local.environment,
7332 cx.weak_entity(),
7333 &worktree,
7334 local.http_client.clone(),
7335 local.fs.clone(),
7336 cx,
7337 )
7338 })?;
7339 let server_id = state.id;
7340
7341 let states = local.language_servers.get(&server_id)?;
7342
7343 match states {
7344 LanguageServerState::Starting { .. } => None,
7345 LanguageServerState::Running {
7346 adapter, server, ..
7347 } => {
7348 let fs = fs.clone();
7349
7350 let adapter = adapter.clone();
7351 let server = server.clone();
7352 refreshed_servers.insert(server.name());
7353 let toolchain = seed.toolchain.clone();
7354 Some(cx.spawn(async move |_, cx| {
7355 let settings =
7356 LocalLspStore::workspace_configuration_for_adapter(
7357 adapter.adapter.clone(),
7358 fs.as_ref(),
7359 &delegate,
7360 toolchain,
7361 cx,
7362 )
7363 .await
7364 .ok()?;
7365 server
7366 .notify::<lsp::notification::DidChangeConfiguration>(
7367 &lsp::DidChangeConfigurationParams { settings },
7368 )
7369 .ok()?;
7370 Some(())
7371 }))
7372 }
7373 }
7374 })
7375 .collect::<Vec<_>>();
7376
7377 Some(servers)
7378 })
7379 .ok()
7380 .flatten()?;
7381
7382 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7383 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7384 // to stop and unregister its language server wrapper.
7385 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7386 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7387 let _: Vec<Option<()>> = join_all(servers).await;
7388
7389 Some(())
7390 })
7391 .await;
7392 }
7393
7394 fn maintain_workspace_config(
7395 fs: Arc<dyn Fs>,
7396 external_refresh_requests: watch::Receiver<()>,
7397 cx: &mut Context<Self>,
7398 ) -> Task<Result<()>> {
7399 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7400 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7401
7402 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7403 *settings_changed_tx.borrow_mut() = ();
7404 });
7405
7406 let mut joint_future =
7407 futures::stream::select(settings_changed_rx, external_refresh_requests);
7408 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7409 // - 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).
7410 // - 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.
7411 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7412 // - 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,
7413 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7414 cx.spawn(async move |this, cx| {
7415 while let Some(()) = joint_future.next().await {
7416 this.update(cx, |this, cx| {
7417 this.refresh_server_tree(cx);
7418 })
7419 .ok();
7420
7421 Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
7422 }
7423
7424 drop(settings_observation);
7425 anyhow::Ok(())
7426 })
7427 }
7428
7429 pub fn language_servers_for_local_buffer<'a>(
7430 &'a self,
7431 buffer: &Buffer,
7432 cx: &mut App,
7433 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7434 let local = self.as_local();
7435 let language_server_ids = local
7436 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7437 .unwrap_or_default();
7438
7439 language_server_ids
7440 .into_iter()
7441 .filter_map(
7442 move |server_id| match local?.language_servers.get(&server_id)? {
7443 LanguageServerState::Running {
7444 adapter, server, ..
7445 } => Some((adapter, server)),
7446 _ => None,
7447 },
7448 )
7449 }
7450
7451 pub fn language_server_for_local_buffer<'a>(
7452 &'a self,
7453 buffer: &'a Buffer,
7454 server_id: LanguageServerId,
7455 cx: &'a mut App,
7456 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7457 self.as_local()?
7458 .language_servers_for_buffer(buffer, cx)
7459 .find(|(_, s)| s.server_id() == server_id)
7460 }
7461
7462 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7463 self.diagnostic_summaries.remove(&id_to_remove);
7464 if let Some(local) = self.as_local_mut() {
7465 let to_remove = local.remove_worktree(id_to_remove, cx);
7466 for server in to_remove {
7467 self.language_server_statuses.remove(&server);
7468 }
7469 }
7470 }
7471
7472 pub fn shared(
7473 &mut self,
7474 project_id: u64,
7475 downstream_client: AnyProtoClient,
7476 _: &mut Context<Self>,
7477 ) {
7478 self.downstream_client = Some((downstream_client.clone(), project_id));
7479
7480 for (server_id, status) in &self.language_server_statuses {
7481 if let Some(server) = self.language_server_for_id(*server_id) {
7482 downstream_client
7483 .send(proto::StartLanguageServer {
7484 project_id,
7485 server: Some(proto::LanguageServer {
7486 id: server_id.to_proto(),
7487 name: status.name.to_string(),
7488 worktree_id: None,
7489 }),
7490 capabilities: serde_json::to_string(&server.capabilities())
7491 .expect("serializing server LSP capabilities"),
7492 })
7493 .log_err();
7494 }
7495 }
7496 }
7497
7498 pub fn disconnected_from_host(&mut self) {
7499 self.downstream_client.take();
7500 }
7501
7502 pub fn disconnected_from_ssh_remote(&mut self) {
7503 if let LspStoreMode::Remote(RemoteLspStore {
7504 upstream_client, ..
7505 }) = &mut self.mode
7506 {
7507 upstream_client.take();
7508 }
7509 }
7510
7511 pub(crate) fn set_language_server_statuses_from_proto(
7512 &mut self,
7513 language_servers: Vec<proto::LanguageServer>,
7514 server_capabilities: Vec<String>,
7515 ) {
7516 self.language_server_statuses = language_servers
7517 .into_iter()
7518 .zip(server_capabilities)
7519 .map(|(server, server_capabilities)| {
7520 let server_id = LanguageServerId(server.id as usize);
7521 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7522 self.lsp_server_capabilities
7523 .insert(server_id, server_capabilities);
7524 }
7525 (
7526 server_id,
7527 LanguageServerStatus {
7528 name: LanguageServerName::from_proto(server.name),
7529 pending_work: Default::default(),
7530 has_pending_diagnostic_updates: false,
7531 progress_tokens: Default::default(),
7532 },
7533 )
7534 })
7535 .collect();
7536 }
7537
7538 #[cfg(test)]
7539 pub fn update_diagnostic_entries(
7540 &mut self,
7541 server_id: LanguageServerId,
7542 abs_path: PathBuf,
7543 result_id: Option<String>,
7544 version: Option<i32>,
7545 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7546 cx: &mut Context<Self>,
7547 ) -> anyhow::Result<()> {
7548 self.merge_diagnostic_entries(
7549 vec![DocumentDiagnosticsUpdate {
7550 diagnostics: DocumentDiagnostics {
7551 diagnostics,
7552 document_abs_path: abs_path,
7553 version,
7554 },
7555 result_id,
7556 server_id,
7557 disk_based_sources: Cow::Borrowed(&[]),
7558 }],
7559 |_, _, _| false,
7560 cx,
7561 )?;
7562 Ok(())
7563 }
7564
7565 pub fn merge_diagnostic_entries<'a>(
7566 &mut self,
7567 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7568 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7569 cx: &mut Context<Self>,
7570 ) -> anyhow::Result<()> {
7571 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7572 let mut updated_diagnostics_paths = HashMap::default();
7573 for mut update in diagnostic_updates {
7574 let abs_path = &update.diagnostics.document_abs_path;
7575 let server_id = update.server_id;
7576 let Some((worktree, relative_path)) =
7577 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7578 else {
7579 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7580 return Ok(());
7581 };
7582
7583 let worktree_id = worktree.read(cx).id();
7584 let project_path = ProjectPath {
7585 worktree_id,
7586 path: relative_path.into(),
7587 };
7588
7589 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7590 let snapshot = buffer_handle.read(cx).snapshot();
7591 let buffer = buffer_handle.read(cx);
7592 let reused_diagnostics = buffer
7593 .get_diagnostics(server_id)
7594 .into_iter()
7595 .flat_map(|diag| {
7596 diag.iter()
7597 .filter(|v| merge(buffer, &v.diagnostic, cx))
7598 .map(|v| {
7599 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7600 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7601 DiagnosticEntry {
7602 range: start..end,
7603 diagnostic: v.diagnostic.clone(),
7604 }
7605 })
7606 })
7607 .collect::<Vec<_>>();
7608
7609 self.as_local_mut()
7610 .context("cannot merge diagnostics on a remote LspStore")?
7611 .update_buffer_diagnostics(
7612 &buffer_handle,
7613 server_id,
7614 update.result_id,
7615 update.diagnostics.version,
7616 update.diagnostics.diagnostics.clone(),
7617 reused_diagnostics.clone(),
7618 cx,
7619 )?;
7620
7621 update.diagnostics.diagnostics.extend(reused_diagnostics);
7622 }
7623
7624 let updated = worktree.update(cx, |worktree, cx| {
7625 self.update_worktree_diagnostics(
7626 worktree.id(),
7627 server_id,
7628 project_path.path.clone(),
7629 update.diagnostics.diagnostics,
7630 cx,
7631 )
7632 })?;
7633 match updated {
7634 ControlFlow::Continue(new_summary) => {
7635 if let Some((project_id, new_summary)) = new_summary {
7636 match &mut diagnostics_summary {
7637 Some(diagnostics_summary) => {
7638 diagnostics_summary
7639 .more_summaries
7640 .push(proto::DiagnosticSummary {
7641 path: project_path.path.as_ref().to_proto(),
7642 language_server_id: server_id.0 as u64,
7643 error_count: new_summary.error_count,
7644 warning_count: new_summary.warning_count,
7645 })
7646 }
7647 None => {
7648 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7649 project_id,
7650 worktree_id: worktree_id.to_proto(),
7651 summary: Some(proto::DiagnosticSummary {
7652 path: project_path.path.as_ref().to_proto(),
7653 language_server_id: server_id.0 as u64,
7654 error_count: new_summary.error_count,
7655 warning_count: new_summary.warning_count,
7656 }),
7657 more_summaries: Vec::new(),
7658 })
7659 }
7660 }
7661 }
7662 updated_diagnostics_paths
7663 .entry(server_id)
7664 .or_insert_with(Vec::new)
7665 .push(project_path);
7666 }
7667 ControlFlow::Break(()) => {}
7668 }
7669 }
7670
7671 if let Some((diagnostics_summary, (downstream_client, _))) =
7672 diagnostics_summary.zip(self.downstream_client.as_ref())
7673 {
7674 downstream_client.send(diagnostics_summary).log_err();
7675 }
7676 for (server_id, paths) in updated_diagnostics_paths {
7677 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7678 }
7679 Ok(())
7680 }
7681
7682 fn update_worktree_diagnostics(
7683 &mut self,
7684 worktree_id: WorktreeId,
7685 server_id: LanguageServerId,
7686 path_in_worktree: Arc<Path>,
7687 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7688 _: &mut Context<Worktree>,
7689 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7690 let local = match &mut self.mode {
7691 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7692 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7693 };
7694
7695 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7696 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7697 let summaries_by_server_id = summaries_for_tree
7698 .entry(path_in_worktree.clone())
7699 .or_default();
7700
7701 let old_summary = summaries_by_server_id
7702 .remove(&server_id)
7703 .unwrap_or_default();
7704
7705 let new_summary = DiagnosticSummary::new(&diagnostics);
7706 if new_summary.is_empty() {
7707 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7708 {
7709 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7710 diagnostics_by_server_id.remove(ix);
7711 }
7712 if diagnostics_by_server_id.is_empty() {
7713 diagnostics_for_tree.remove(&path_in_worktree);
7714 }
7715 }
7716 } else {
7717 summaries_by_server_id.insert(server_id, new_summary);
7718 let diagnostics_by_server_id = diagnostics_for_tree
7719 .entry(path_in_worktree.clone())
7720 .or_default();
7721 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
7722 Ok(ix) => {
7723 diagnostics_by_server_id[ix] = (server_id, diagnostics);
7724 }
7725 Err(ix) => {
7726 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
7727 }
7728 }
7729 }
7730
7731 if !old_summary.is_empty() || !new_summary.is_empty() {
7732 if let Some((_, project_id)) = &self.downstream_client {
7733 Ok(ControlFlow::Continue(Some((
7734 *project_id,
7735 proto::DiagnosticSummary {
7736 path: path_in_worktree.to_proto(),
7737 language_server_id: server_id.0 as u64,
7738 error_count: new_summary.error_count as u32,
7739 warning_count: new_summary.warning_count as u32,
7740 },
7741 ))))
7742 } else {
7743 Ok(ControlFlow::Continue(None))
7744 }
7745 } else {
7746 Ok(ControlFlow::Break(()))
7747 }
7748 }
7749
7750 pub fn open_buffer_for_symbol(
7751 &mut self,
7752 symbol: &Symbol,
7753 cx: &mut Context<Self>,
7754 ) -> Task<Result<Entity<Buffer>>> {
7755 if let Some((client, project_id)) = self.upstream_client() {
7756 let request = client.request(proto::OpenBufferForSymbol {
7757 project_id,
7758 symbol: Some(Self::serialize_symbol(symbol)),
7759 });
7760 cx.spawn(async move |this, cx| {
7761 let response = request.await?;
7762 let buffer_id = BufferId::new(response.buffer_id)?;
7763 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
7764 .await
7765 })
7766 } else if let Some(local) = self.as_local() {
7767 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
7768 seed.worktree_id == symbol.source_worktree_id
7769 && state.id == symbol.source_language_server_id
7770 && symbol.language_server_name == seed.name
7771 });
7772 if !is_valid {
7773 return Task::ready(Err(anyhow!(
7774 "language server for worktree and language not found"
7775 )));
7776 };
7777
7778 let worktree_abs_path = if let Some(worktree_abs_path) = self
7779 .worktree_store
7780 .read(cx)
7781 .worktree_for_id(symbol.path.worktree_id, cx)
7782 .map(|worktree| worktree.read(cx).abs_path())
7783 {
7784 worktree_abs_path
7785 } else {
7786 return Task::ready(Err(anyhow!("worktree not found for symbol")));
7787 };
7788
7789 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
7790 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
7791 uri
7792 } else {
7793 return Task::ready(Err(anyhow!("invalid symbol path")));
7794 };
7795
7796 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
7797 } else {
7798 Task::ready(Err(anyhow!("no upstream client or local store")))
7799 }
7800 }
7801
7802 pub(crate) fn open_local_buffer_via_lsp(
7803 &mut self,
7804 mut abs_path: lsp::Url,
7805 language_server_id: LanguageServerId,
7806 cx: &mut Context<Self>,
7807 ) -> Task<Result<Entity<Buffer>>> {
7808 cx.spawn(async move |lsp_store, cx| {
7809 // Escape percent-encoded string.
7810 let current_scheme = abs_path.scheme().to_owned();
7811 let _ = abs_path.set_scheme("file");
7812
7813 let abs_path = abs_path
7814 .to_file_path()
7815 .map_err(|()| anyhow!("can't convert URI to path"))?;
7816 let p = abs_path.clone();
7817 let yarn_worktree = lsp_store
7818 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
7819 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
7820 cx.spawn(async move |this, cx| {
7821 let t = this
7822 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
7823 .ok()?;
7824 t.await
7825 })
7826 }),
7827 None => Task::ready(None),
7828 })?
7829 .await;
7830 let (worktree_root_target, known_relative_path) =
7831 if let Some((zip_root, relative_path)) = yarn_worktree {
7832 (zip_root, Some(relative_path))
7833 } else {
7834 (Arc::<Path>::from(abs_path.as_path()), None)
7835 };
7836 let (worktree, relative_path) = if let Some(result) =
7837 lsp_store.update(cx, |lsp_store, cx| {
7838 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7839 worktree_store.find_worktree(&worktree_root_target, cx)
7840 })
7841 })? {
7842 let relative_path =
7843 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
7844 (result.0, relative_path)
7845 } else {
7846 let worktree = lsp_store
7847 .update(cx, |lsp_store, cx| {
7848 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
7849 worktree_store.create_worktree(&worktree_root_target, false, cx)
7850 })
7851 })?
7852 .await?;
7853 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
7854 lsp_store
7855 .update(cx, |lsp_store, cx| {
7856 if let Some(local) = lsp_store.as_local_mut() {
7857 local.register_language_server_for_invisible_worktree(
7858 &worktree,
7859 language_server_id,
7860 cx,
7861 )
7862 }
7863 })
7864 .ok();
7865 }
7866 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
7867 let relative_path = if let Some(known_path) = known_relative_path {
7868 known_path
7869 } else {
7870 abs_path.strip_prefix(worktree_root)?.into()
7871 };
7872 (worktree, relative_path)
7873 };
7874 let project_path = ProjectPath {
7875 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
7876 path: relative_path,
7877 };
7878 lsp_store
7879 .update(cx, |lsp_store, cx| {
7880 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
7881 buffer_store.open_buffer(project_path, cx)
7882 })
7883 })?
7884 .await
7885 })
7886 }
7887
7888 fn request_multiple_lsp_locally<P, R>(
7889 &mut self,
7890 buffer: &Entity<Buffer>,
7891 position: Option<P>,
7892 request: R,
7893 cx: &mut Context<Self>,
7894 ) -> Task<Vec<(LanguageServerId, R::Response)>>
7895 where
7896 P: ToOffset,
7897 R: LspCommand + Clone,
7898 <R::LspRequest as lsp::request::Request>::Result: Send,
7899 <R::LspRequest as lsp::request::Request>::Params: Send,
7900 {
7901 let Some(local) = self.as_local() else {
7902 return Task::ready(Vec::new());
7903 };
7904
7905 let snapshot = buffer.read(cx).snapshot();
7906 let scope = position.and_then(|position| snapshot.language_scope_at(position));
7907
7908 let server_ids = buffer.update(cx, |buffer, cx| {
7909 local
7910 .language_servers_for_buffer(buffer, cx)
7911 .filter(|(adapter, _)| {
7912 scope
7913 .as_ref()
7914 .map(|scope| scope.language_allowed(&adapter.name))
7915 .unwrap_or(true)
7916 })
7917 .map(|(_, server)| server.server_id())
7918 .filter(|server_id| {
7919 self.as_local().is_none_or(|local| {
7920 local
7921 .buffers_opened_in_servers
7922 .get(&snapshot.remote_id())
7923 .is_some_and(|servers| servers.contains(server_id))
7924 })
7925 })
7926 .collect::<Vec<_>>()
7927 });
7928
7929 let mut response_results = server_ids
7930 .into_iter()
7931 .map(|server_id| {
7932 let task = self.request_lsp(
7933 buffer.clone(),
7934 LanguageServerToQuery::Other(server_id),
7935 request.clone(),
7936 cx,
7937 );
7938 async move { (server_id, task.await) }
7939 })
7940 .collect::<FuturesUnordered<_>>();
7941
7942 cx.background_spawn(async move {
7943 let mut responses = Vec::with_capacity(response_results.len());
7944 while let Some((server_id, response_result)) = response_results.next().await {
7945 if let Some(response) = response_result.log_err() {
7946 responses.push((server_id, response));
7947 }
7948 }
7949 responses
7950 })
7951 }
7952
7953 async fn handle_lsp_command<T: LspCommand>(
7954 this: Entity<Self>,
7955 envelope: TypedEnvelope<T::ProtoRequest>,
7956 mut cx: AsyncApp,
7957 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
7958 where
7959 <T::LspRequest as lsp::request::Request>::Params: Send,
7960 <T::LspRequest as lsp::request::Request>::Result: Send,
7961 {
7962 let sender_id = envelope.original_sender_id().unwrap_or_default();
7963 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
7964 let buffer_handle = this.update(&mut cx, |this, cx| {
7965 this.buffer_store.read(cx).get_existing(buffer_id)
7966 })??;
7967 let request = T::from_proto(
7968 envelope.payload,
7969 this.clone(),
7970 buffer_handle.clone(),
7971 cx.clone(),
7972 )
7973 .await?;
7974 let response = this
7975 .update(&mut cx, |this, cx| {
7976 this.request_lsp(
7977 buffer_handle.clone(),
7978 LanguageServerToQuery::FirstCapable,
7979 request,
7980 cx,
7981 )
7982 })?
7983 .await?;
7984 this.update(&mut cx, |this, cx| {
7985 Ok(T::response_to_proto(
7986 response,
7987 this,
7988 sender_id,
7989 &buffer_handle.read(cx).version(),
7990 cx,
7991 ))
7992 })?
7993 }
7994
7995 async fn handle_lsp_query(
7996 lsp_store: Entity<Self>,
7997 envelope: TypedEnvelope<proto::LspQuery>,
7998 mut cx: AsyncApp,
7999 ) -> Result<proto::Ack> {
8000 use proto::lsp_query::Request;
8001 let sender_id = envelope.original_sender_id().unwrap_or_default();
8002 let lsp_query = envelope.payload;
8003 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8004 match lsp_query.request.context("invalid LSP query request")? {
8005 Request::GetReferences(get_references) => {
8006 let position = get_references.position.clone().and_then(deserialize_anchor);
8007 Self::query_lsp_locally::<GetReferences>(
8008 lsp_store,
8009 sender_id,
8010 lsp_request_id,
8011 get_references,
8012 position,
8013 cx.clone(),
8014 )
8015 .await?;
8016 }
8017 Request::GetDocumentColor(get_document_color) => {
8018 Self::query_lsp_locally::<GetDocumentColor>(
8019 lsp_store,
8020 sender_id,
8021 lsp_request_id,
8022 get_document_color,
8023 None,
8024 cx.clone(),
8025 )
8026 .await?;
8027 }
8028 Request::GetHover(get_hover) => {
8029 let position = get_hover.position.clone().and_then(deserialize_anchor);
8030 Self::query_lsp_locally::<GetHover>(
8031 lsp_store,
8032 sender_id,
8033 lsp_request_id,
8034 get_hover,
8035 position,
8036 cx.clone(),
8037 )
8038 .await?;
8039 }
8040 Request::GetCodeActions(get_code_actions) => {
8041 Self::query_lsp_locally::<GetCodeActions>(
8042 lsp_store,
8043 sender_id,
8044 lsp_request_id,
8045 get_code_actions,
8046 None,
8047 cx.clone(),
8048 )
8049 .await?;
8050 }
8051 Request::GetSignatureHelp(get_signature_help) => {
8052 let position = get_signature_help
8053 .position
8054 .clone()
8055 .and_then(deserialize_anchor);
8056 Self::query_lsp_locally::<GetSignatureHelp>(
8057 lsp_store,
8058 sender_id,
8059 lsp_request_id,
8060 get_signature_help,
8061 position,
8062 cx.clone(),
8063 )
8064 .await?;
8065 }
8066 Request::GetCodeLens(get_code_lens) => {
8067 Self::query_lsp_locally::<GetCodeLens>(
8068 lsp_store,
8069 sender_id,
8070 lsp_request_id,
8071 get_code_lens,
8072 None,
8073 cx.clone(),
8074 )
8075 .await?;
8076 }
8077 Request::GetDefinition(get_definition) => {
8078 let position = get_definition.position.clone().and_then(deserialize_anchor);
8079 Self::query_lsp_locally::<GetDefinitions>(
8080 lsp_store,
8081 sender_id,
8082 lsp_request_id,
8083 get_definition,
8084 position,
8085 cx.clone(),
8086 )
8087 .await?;
8088 }
8089 Request::GetDeclaration(get_declaration) => {
8090 let position = get_declaration
8091 .position
8092 .clone()
8093 .and_then(deserialize_anchor);
8094 Self::query_lsp_locally::<GetDeclarations>(
8095 lsp_store,
8096 sender_id,
8097 lsp_request_id,
8098 get_declaration,
8099 position,
8100 cx.clone(),
8101 )
8102 .await?;
8103 }
8104 Request::GetTypeDefinition(get_type_definition) => {
8105 let position = get_type_definition
8106 .position
8107 .clone()
8108 .and_then(deserialize_anchor);
8109 Self::query_lsp_locally::<GetTypeDefinitions>(
8110 lsp_store,
8111 sender_id,
8112 lsp_request_id,
8113 get_type_definition,
8114 position,
8115 cx.clone(),
8116 )
8117 .await?;
8118 }
8119 Request::GetImplementation(get_implementation) => {
8120 let position = get_implementation
8121 .position
8122 .clone()
8123 .and_then(deserialize_anchor);
8124 Self::query_lsp_locally::<GetImplementations>(
8125 lsp_store,
8126 sender_id,
8127 lsp_request_id,
8128 get_implementation,
8129 position,
8130 cx.clone(),
8131 )
8132 .await?;
8133 }
8134 // Diagnostics pull synchronizes internally via the buffer state, and cannot be handled generically as the other requests.
8135 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8136 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8137 let version = deserialize_version(get_document_diagnostics.buffer_version());
8138 let buffer = lsp_store.update(&mut cx, |this, cx| {
8139 this.buffer_store.read(cx).get_existing(buffer_id)
8140 })??;
8141 buffer
8142 .update(&mut cx, |buffer, _| {
8143 buffer.wait_for_version(version.clone())
8144 })?
8145 .await?;
8146 lsp_store.update(&mut cx, |lsp_store, cx| {
8147 let existing_queries = lsp_store
8148 .running_lsp_requests
8149 .entry(TypeId::of::<GetDocumentDiagnostics>())
8150 .or_default();
8151 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8152 ) || buffer.read(cx).version.changed_since(&existing_queries.0)
8153 {
8154 existing_queries.1.clear();
8155 }
8156 existing_queries.1.insert(
8157 lsp_request_id,
8158 cx.spawn(async move |lsp_store, cx| {
8159 let diagnostics_pull = lsp_store
8160 .update(cx, |lsp_store, cx| {
8161 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8162 })
8163 .ok();
8164 if let Some(diagnostics_pull) = diagnostics_pull {
8165 match diagnostics_pull.await {
8166 Ok(()) => {}
8167 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8168 };
8169 }
8170 }),
8171 );
8172 })?;
8173 }
8174 }
8175 Ok(proto::Ack {})
8176 }
8177
8178 async fn handle_lsp_query_response(
8179 lsp_store: Entity<Self>,
8180 envelope: TypedEnvelope<proto::LspQueryResponse>,
8181 cx: AsyncApp,
8182 ) -> Result<()> {
8183 lsp_store.read_with(&cx, |lsp_store, _| {
8184 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8185 upstream_client.handle_lsp_response(envelope.clone());
8186 }
8187 })?;
8188 Ok(())
8189 }
8190
8191 // todo(lsp) remove after Zed Stable hits v0.204.x
8192 async fn handle_multi_lsp_query(
8193 lsp_store: Entity<Self>,
8194 envelope: TypedEnvelope<proto::MultiLspQuery>,
8195 mut cx: AsyncApp,
8196 ) -> Result<proto::MultiLspQueryResponse> {
8197 let response_from_ssh = lsp_store.read_with(&cx, |this, _| {
8198 let (upstream_client, project_id) = this.upstream_client()?;
8199 let mut payload = envelope.payload.clone();
8200 payload.project_id = project_id;
8201
8202 Some(upstream_client.request(payload))
8203 })?;
8204 if let Some(response_from_ssh) = response_from_ssh {
8205 return response_from_ssh.await;
8206 }
8207
8208 let sender_id = envelope.original_sender_id().unwrap_or_default();
8209 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8210 let version = deserialize_version(&envelope.payload.version);
8211 let buffer = lsp_store.update(&mut cx, |this, cx| {
8212 this.buffer_store.read(cx).get_existing(buffer_id)
8213 })??;
8214 buffer
8215 .update(&mut cx, |buffer, _| {
8216 buffer.wait_for_version(version.clone())
8217 })?
8218 .await?;
8219 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
8220 match envelope
8221 .payload
8222 .strategy
8223 .context("invalid request without the strategy")?
8224 {
8225 proto::multi_lsp_query::Strategy::All(_) => {
8226 // currently, there's only one multiple language servers query strategy,
8227 // so just ensure it's specified correctly
8228 }
8229 }
8230 match envelope.payload.request {
8231 Some(proto::multi_lsp_query::Request::GetHover(message)) => {
8232 buffer
8233 .update(&mut cx, |buffer, _| {
8234 buffer.wait_for_version(deserialize_version(&message.version))
8235 })?
8236 .await?;
8237 let get_hover =
8238 GetHover::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8239 .await?;
8240 let all_hovers = lsp_store
8241 .update(&mut cx, |this, cx| {
8242 this.request_multiple_lsp_locally(
8243 &buffer,
8244 Some(get_hover.position),
8245 get_hover,
8246 cx,
8247 )
8248 })?
8249 .await
8250 .into_iter()
8251 .filter_map(|(server_id, hover)| {
8252 Some((server_id, remove_empty_hover_blocks(hover?)?))
8253 });
8254 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8255 responses: all_hovers
8256 .map(|(server_id, hover)| proto::LspResponse {
8257 server_id: server_id.to_proto(),
8258 response: Some(proto::lsp_response::Response::GetHoverResponse(
8259 GetHover::response_to_proto(
8260 Some(hover),
8261 project,
8262 sender_id,
8263 &buffer_version,
8264 cx,
8265 ),
8266 )),
8267 })
8268 .collect(),
8269 })
8270 }
8271 Some(proto::multi_lsp_query::Request::GetCodeActions(message)) => {
8272 buffer
8273 .update(&mut cx, |buffer, _| {
8274 buffer.wait_for_version(deserialize_version(&message.version))
8275 })?
8276 .await?;
8277 let get_code_actions = GetCodeActions::from_proto(
8278 message,
8279 lsp_store.clone(),
8280 buffer.clone(),
8281 cx.clone(),
8282 )
8283 .await?;
8284
8285 let all_actions = lsp_store
8286 .update(&mut cx, |project, cx| {
8287 project.request_multiple_lsp_locally(
8288 &buffer,
8289 Some(get_code_actions.range.start),
8290 get_code_actions,
8291 cx,
8292 )
8293 })?
8294 .await
8295 .into_iter();
8296
8297 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8298 responses: all_actions
8299 .map(|(server_id, code_actions)| proto::LspResponse {
8300 server_id: server_id.to_proto(),
8301 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
8302 GetCodeActions::response_to_proto(
8303 code_actions,
8304 project,
8305 sender_id,
8306 &buffer_version,
8307 cx,
8308 ),
8309 )),
8310 })
8311 .collect(),
8312 })
8313 }
8314 Some(proto::multi_lsp_query::Request::GetSignatureHelp(message)) => {
8315 buffer
8316 .update(&mut cx, |buffer, _| {
8317 buffer.wait_for_version(deserialize_version(&message.version))
8318 })?
8319 .await?;
8320 let get_signature_help = GetSignatureHelp::from_proto(
8321 message,
8322 lsp_store.clone(),
8323 buffer.clone(),
8324 cx.clone(),
8325 )
8326 .await?;
8327
8328 let all_signatures = lsp_store
8329 .update(&mut cx, |project, cx| {
8330 project.request_multiple_lsp_locally(
8331 &buffer,
8332 Some(get_signature_help.position),
8333 get_signature_help,
8334 cx,
8335 )
8336 })?
8337 .await
8338 .into_iter();
8339
8340 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8341 responses: all_signatures
8342 .map(|(server_id, signature_help)| proto::LspResponse {
8343 server_id: server_id.to_proto(),
8344 response: Some(
8345 proto::lsp_response::Response::GetSignatureHelpResponse(
8346 GetSignatureHelp::response_to_proto(
8347 signature_help,
8348 project,
8349 sender_id,
8350 &buffer_version,
8351 cx,
8352 ),
8353 ),
8354 ),
8355 })
8356 .collect(),
8357 })
8358 }
8359 Some(proto::multi_lsp_query::Request::GetCodeLens(message)) => {
8360 buffer
8361 .update(&mut cx, |buffer, _| {
8362 buffer.wait_for_version(deserialize_version(&message.version))
8363 })?
8364 .await?;
8365 let get_code_lens =
8366 GetCodeLens::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8367 .await?;
8368
8369 let code_lens_actions = lsp_store
8370 .update(&mut cx, |project, cx| {
8371 project.request_multiple_lsp_locally(
8372 &buffer,
8373 None::<usize>,
8374 get_code_lens,
8375 cx,
8376 )
8377 })?
8378 .await
8379 .into_iter();
8380
8381 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8382 responses: code_lens_actions
8383 .map(|(server_id, actions)| proto::LspResponse {
8384 server_id: server_id.to_proto(),
8385 response: Some(proto::lsp_response::Response::GetCodeLensResponse(
8386 GetCodeLens::response_to_proto(
8387 actions,
8388 project,
8389 sender_id,
8390 &buffer_version,
8391 cx,
8392 ),
8393 )),
8394 })
8395 .collect(),
8396 })
8397 }
8398 Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(message)) => {
8399 buffer
8400 .update(&mut cx, |buffer, _| {
8401 buffer.wait_for_version(deserialize_version(&message.version))
8402 })?
8403 .await?;
8404 lsp_store
8405 .update(&mut cx, |lsp_store, cx| {
8406 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8407 })?
8408 .await?;
8409 // `pull_diagnostics_for_buffer` will merge in the new diagnostics and send them to the client.
8410 // The client cannot merge anything into its non-local LspStore, so we do not need to return anything.
8411 Ok(proto::MultiLspQueryResponse {
8412 responses: Vec::new(),
8413 })
8414 }
8415 Some(proto::multi_lsp_query::Request::GetDocumentColor(message)) => {
8416 buffer
8417 .update(&mut cx, |buffer, _| {
8418 buffer.wait_for_version(deserialize_version(&message.version))
8419 })?
8420 .await?;
8421 let get_document_color = GetDocumentColor::from_proto(
8422 message,
8423 lsp_store.clone(),
8424 buffer.clone(),
8425 cx.clone(),
8426 )
8427 .await?;
8428
8429 let all_colors = lsp_store
8430 .update(&mut cx, |project, cx| {
8431 project.request_multiple_lsp_locally(
8432 &buffer,
8433 None::<usize>,
8434 get_document_color,
8435 cx,
8436 )
8437 })?
8438 .await
8439 .into_iter();
8440
8441 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8442 responses: all_colors
8443 .map(|(server_id, colors)| proto::LspResponse {
8444 server_id: server_id.to_proto(),
8445 response: Some(
8446 proto::lsp_response::Response::GetDocumentColorResponse(
8447 GetDocumentColor::response_to_proto(
8448 colors,
8449 project,
8450 sender_id,
8451 &buffer_version,
8452 cx,
8453 ),
8454 ),
8455 ),
8456 })
8457 .collect(),
8458 })
8459 }
8460 Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
8461 let get_definitions = GetDefinitions::from_proto(
8462 message,
8463 lsp_store.clone(),
8464 buffer.clone(),
8465 cx.clone(),
8466 )
8467 .await?;
8468
8469 let definitions = lsp_store
8470 .update(&mut cx, |project, cx| {
8471 project.request_multiple_lsp_locally(
8472 &buffer,
8473 Some(get_definitions.position),
8474 get_definitions,
8475 cx,
8476 )
8477 })?
8478 .await
8479 .into_iter();
8480
8481 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8482 responses: definitions
8483 .map(|(server_id, definitions)| proto::LspResponse {
8484 server_id: server_id.to_proto(),
8485 response: Some(proto::lsp_response::Response::GetDefinitionResponse(
8486 GetDefinitions::response_to_proto(
8487 definitions,
8488 project,
8489 sender_id,
8490 &buffer_version,
8491 cx,
8492 ),
8493 )),
8494 })
8495 .collect(),
8496 })
8497 }
8498 Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
8499 let get_declarations = GetDeclarations::from_proto(
8500 message,
8501 lsp_store.clone(),
8502 buffer.clone(),
8503 cx.clone(),
8504 )
8505 .await?;
8506
8507 let declarations = lsp_store
8508 .update(&mut cx, |project, cx| {
8509 project.request_multiple_lsp_locally(
8510 &buffer,
8511 Some(get_declarations.position),
8512 get_declarations,
8513 cx,
8514 )
8515 })?
8516 .await
8517 .into_iter();
8518
8519 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8520 responses: declarations
8521 .map(|(server_id, declarations)| proto::LspResponse {
8522 server_id: server_id.to_proto(),
8523 response: Some(proto::lsp_response::Response::GetDeclarationResponse(
8524 GetDeclarations::response_to_proto(
8525 declarations,
8526 project,
8527 sender_id,
8528 &buffer_version,
8529 cx,
8530 ),
8531 )),
8532 })
8533 .collect(),
8534 })
8535 }
8536 Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
8537 let get_type_definitions = GetTypeDefinitions::from_proto(
8538 message,
8539 lsp_store.clone(),
8540 buffer.clone(),
8541 cx.clone(),
8542 )
8543 .await?;
8544
8545 let type_definitions = lsp_store
8546 .update(&mut cx, |project, cx| {
8547 project.request_multiple_lsp_locally(
8548 &buffer,
8549 Some(get_type_definitions.position),
8550 get_type_definitions,
8551 cx,
8552 )
8553 })?
8554 .await
8555 .into_iter();
8556
8557 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8558 responses: type_definitions
8559 .map(|(server_id, type_definitions)| proto::LspResponse {
8560 server_id: server_id.to_proto(),
8561 response: Some(
8562 proto::lsp_response::Response::GetTypeDefinitionResponse(
8563 GetTypeDefinitions::response_to_proto(
8564 type_definitions,
8565 project,
8566 sender_id,
8567 &buffer_version,
8568 cx,
8569 ),
8570 ),
8571 ),
8572 })
8573 .collect(),
8574 })
8575 }
8576 Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
8577 let get_implementations = GetImplementations::from_proto(
8578 message,
8579 lsp_store.clone(),
8580 buffer.clone(),
8581 cx.clone(),
8582 )
8583 .await?;
8584
8585 let implementations = lsp_store
8586 .update(&mut cx, |project, cx| {
8587 project.request_multiple_lsp_locally(
8588 &buffer,
8589 Some(get_implementations.position),
8590 get_implementations,
8591 cx,
8592 )
8593 })?
8594 .await
8595 .into_iter();
8596
8597 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8598 responses: implementations
8599 .map(|(server_id, implementations)| proto::LspResponse {
8600 server_id: server_id.to_proto(),
8601 response: Some(
8602 proto::lsp_response::Response::GetImplementationResponse(
8603 GetImplementations::response_to_proto(
8604 implementations,
8605 project,
8606 sender_id,
8607 &buffer_version,
8608 cx,
8609 ),
8610 ),
8611 ),
8612 })
8613 .collect(),
8614 })
8615 }
8616 Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
8617 let get_references = GetReferences::from_proto(
8618 message,
8619 lsp_store.clone(),
8620 buffer.clone(),
8621 cx.clone(),
8622 )
8623 .await?;
8624
8625 let references = lsp_store
8626 .update(&mut cx, |project, cx| {
8627 project.request_multiple_lsp_locally(
8628 &buffer,
8629 Some(get_references.position),
8630 get_references,
8631 cx,
8632 )
8633 })?
8634 .await
8635 .into_iter();
8636
8637 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8638 responses: references
8639 .map(|(server_id, references)| proto::LspResponse {
8640 server_id: server_id.to_proto(),
8641 response: Some(proto::lsp_response::Response::GetReferencesResponse(
8642 GetReferences::response_to_proto(
8643 references,
8644 project,
8645 sender_id,
8646 &buffer_version,
8647 cx,
8648 ),
8649 )),
8650 })
8651 .collect(),
8652 })
8653 }
8654 None => anyhow::bail!("empty multi lsp query request"),
8655 }
8656 }
8657
8658 async fn handle_apply_code_action(
8659 this: Entity<Self>,
8660 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8661 mut cx: AsyncApp,
8662 ) -> Result<proto::ApplyCodeActionResponse> {
8663 let sender_id = envelope.original_sender_id().unwrap_or_default();
8664 let action =
8665 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8666 let apply_code_action = this.update(&mut cx, |this, cx| {
8667 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8668 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8669 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8670 })??;
8671
8672 let project_transaction = apply_code_action.await?;
8673 let project_transaction = this.update(&mut cx, |this, cx| {
8674 this.buffer_store.update(cx, |buffer_store, cx| {
8675 buffer_store.serialize_project_transaction_for_peer(
8676 project_transaction,
8677 sender_id,
8678 cx,
8679 )
8680 })
8681 })?;
8682 Ok(proto::ApplyCodeActionResponse {
8683 transaction: Some(project_transaction),
8684 })
8685 }
8686
8687 async fn handle_register_buffer_with_language_servers(
8688 this: Entity<Self>,
8689 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8690 mut cx: AsyncApp,
8691 ) -> Result<proto::Ack> {
8692 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8693 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8694 this.update(&mut cx, |this, cx| {
8695 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8696 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8697 project_id: upstream_project_id,
8698 buffer_id: buffer_id.to_proto(),
8699 only_servers: envelope.payload.only_servers,
8700 });
8701 }
8702
8703 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8704 anyhow::bail!("buffer is not open");
8705 };
8706
8707 let handle = this.register_buffer_with_language_servers(
8708 &buffer,
8709 envelope
8710 .payload
8711 .only_servers
8712 .into_iter()
8713 .filter_map(|selector| {
8714 Some(match selector.selector? {
8715 proto::language_server_selector::Selector::ServerId(server_id) => {
8716 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8717 }
8718 proto::language_server_selector::Selector::Name(name) => {
8719 LanguageServerSelector::Name(LanguageServerName(
8720 SharedString::from(name),
8721 ))
8722 }
8723 })
8724 })
8725 .collect(),
8726 false,
8727 cx,
8728 );
8729 this.buffer_store().update(cx, |buffer_store, _| {
8730 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8731 });
8732
8733 Ok(())
8734 })??;
8735 Ok(proto::Ack {})
8736 }
8737
8738 async fn handle_rename_project_entry(
8739 this: Entity<Self>,
8740 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8741 mut cx: AsyncApp,
8742 ) -> Result<proto::ProjectEntryResponse> {
8743 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8744 let (worktree_id, worktree, old_path, is_dir) = this
8745 .update(&mut cx, |this, cx| {
8746 this.worktree_store
8747 .read(cx)
8748 .worktree_and_entry_for_id(entry_id, cx)
8749 .map(|(worktree, entry)| {
8750 (
8751 worktree.read(cx).id(),
8752 worktree,
8753 entry.path.clone(),
8754 entry.is_dir(),
8755 )
8756 })
8757 })?
8758 .context("worktree not found")?;
8759 let (old_abs_path, new_abs_path) = {
8760 let root_path = worktree.read_with(&cx, |this, _| this.abs_path())?;
8761 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8762 (root_path.join(&old_path), root_path.join(&new_path))
8763 };
8764
8765 Self::will_rename_entry(
8766 this.downgrade(),
8767 worktree_id,
8768 &old_abs_path,
8769 &new_abs_path,
8770 is_dir,
8771 cx.clone(),
8772 )
8773 .await;
8774 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8775 this.read_with(&cx, |this, _| {
8776 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8777 })
8778 .ok();
8779 response
8780 }
8781
8782 async fn handle_update_diagnostic_summary(
8783 this: Entity<Self>,
8784 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8785 mut cx: AsyncApp,
8786 ) -> Result<()> {
8787 this.update(&mut cx, |lsp_store, cx| {
8788 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8789 let mut updated_diagnostics_paths = HashMap::default();
8790 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8791 for message_summary in envelope
8792 .payload
8793 .summary
8794 .into_iter()
8795 .chain(envelope.payload.more_summaries)
8796 {
8797 let project_path = ProjectPath {
8798 worktree_id,
8799 path: Arc::<Path>::from_proto(message_summary.path),
8800 };
8801 let path = project_path.path.clone();
8802 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8803 let summary = DiagnosticSummary {
8804 error_count: message_summary.error_count as usize,
8805 warning_count: message_summary.warning_count as usize,
8806 };
8807
8808 if summary.is_empty() {
8809 if let Some(worktree_summaries) =
8810 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8811 && let Some(summaries) = worktree_summaries.get_mut(&path)
8812 {
8813 summaries.remove(&server_id);
8814 if summaries.is_empty() {
8815 worktree_summaries.remove(&path);
8816 }
8817 }
8818 } else {
8819 lsp_store
8820 .diagnostic_summaries
8821 .entry(worktree_id)
8822 .or_default()
8823 .entry(path)
8824 .or_default()
8825 .insert(server_id, summary);
8826 }
8827
8828 if let Some((_, project_id)) = &lsp_store.downstream_client {
8829 match &mut diagnostics_summary {
8830 Some(diagnostics_summary) => {
8831 diagnostics_summary
8832 .more_summaries
8833 .push(proto::DiagnosticSummary {
8834 path: project_path.path.as_ref().to_proto(),
8835 language_server_id: server_id.0 as u64,
8836 error_count: summary.error_count as u32,
8837 warning_count: summary.warning_count as u32,
8838 })
8839 }
8840 None => {
8841 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8842 project_id: *project_id,
8843 worktree_id: worktree_id.to_proto(),
8844 summary: Some(proto::DiagnosticSummary {
8845 path: project_path.path.as_ref().to_proto(),
8846 language_server_id: server_id.0 as u64,
8847 error_count: summary.error_count as u32,
8848 warning_count: summary.warning_count as u32,
8849 }),
8850 more_summaries: Vec::new(),
8851 })
8852 }
8853 }
8854 }
8855 updated_diagnostics_paths
8856 .entry(server_id)
8857 .or_insert_with(Vec::new)
8858 .push(project_path);
8859 }
8860
8861 if let Some((diagnostics_summary, (downstream_client, _))) =
8862 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8863 {
8864 downstream_client.send(diagnostics_summary).log_err();
8865 }
8866 for (server_id, paths) in updated_diagnostics_paths {
8867 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8868 }
8869 Ok(())
8870 })?
8871 }
8872
8873 async fn handle_start_language_server(
8874 lsp_store: Entity<Self>,
8875 envelope: TypedEnvelope<proto::StartLanguageServer>,
8876 mut cx: AsyncApp,
8877 ) -> Result<()> {
8878 let server = envelope.payload.server.context("invalid server")?;
8879 let server_capabilities =
8880 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8881 .with_context(|| {
8882 format!(
8883 "incorrect server capabilities {}",
8884 envelope.payload.capabilities
8885 )
8886 })?;
8887 lsp_store.update(&mut cx, |lsp_store, cx| {
8888 let server_id = LanguageServerId(server.id as usize);
8889 let server_name = LanguageServerName::from_proto(server.name.clone());
8890 lsp_store
8891 .lsp_server_capabilities
8892 .insert(server_id, server_capabilities);
8893 lsp_store.language_server_statuses.insert(
8894 server_id,
8895 LanguageServerStatus {
8896 name: server_name.clone(),
8897 pending_work: Default::default(),
8898 has_pending_diagnostic_updates: false,
8899 progress_tokens: Default::default(),
8900 },
8901 );
8902 cx.emit(LspStoreEvent::LanguageServerAdded(
8903 server_id,
8904 server_name,
8905 server.worktree_id.map(WorktreeId::from_proto),
8906 ));
8907 cx.notify();
8908 })?;
8909 Ok(())
8910 }
8911
8912 async fn handle_update_language_server(
8913 lsp_store: Entity<Self>,
8914 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8915 mut cx: AsyncApp,
8916 ) -> Result<()> {
8917 lsp_store.update(&mut cx, |lsp_store, cx| {
8918 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8919
8920 match envelope.payload.variant.context("invalid variant")? {
8921 proto::update_language_server::Variant::WorkStart(payload) => {
8922 lsp_store.on_lsp_work_start(
8923 language_server_id,
8924 payload.token,
8925 LanguageServerProgress {
8926 title: payload.title,
8927 is_disk_based_diagnostics_progress: false,
8928 is_cancellable: payload.is_cancellable.unwrap_or(false),
8929 message: payload.message,
8930 percentage: payload.percentage.map(|p| p as usize),
8931 last_update_at: cx.background_executor().now(),
8932 },
8933 cx,
8934 );
8935 }
8936 proto::update_language_server::Variant::WorkProgress(payload) => {
8937 lsp_store.on_lsp_work_progress(
8938 language_server_id,
8939 payload.token,
8940 LanguageServerProgress {
8941 title: None,
8942 is_disk_based_diagnostics_progress: false,
8943 is_cancellable: payload.is_cancellable.unwrap_or(false),
8944 message: payload.message,
8945 percentage: payload.percentage.map(|p| p as usize),
8946 last_update_at: cx.background_executor().now(),
8947 },
8948 cx,
8949 );
8950 }
8951
8952 proto::update_language_server::Variant::WorkEnd(payload) => {
8953 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
8954 }
8955
8956 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
8957 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
8958 }
8959
8960 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
8961 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
8962 }
8963
8964 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
8965 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
8966 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
8967 cx.emit(LspStoreEvent::LanguageServerUpdate {
8968 language_server_id,
8969 name: envelope
8970 .payload
8971 .server_name
8972 .map(SharedString::new)
8973 .map(LanguageServerName),
8974 message: non_lsp,
8975 });
8976 }
8977 }
8978
8979 Ok(())
8980 })?
8981 }
8982
8983 async fn handle_language_server_log(
8984 this: Entity<Self>,
8985 envelope: TypedEnvelope<proto::LanguageServerLog>,
8986 mut cx: AsyncApp,
8987 ) -> Result<()> {
8988 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8989 let log_type = envelope
8990 .payload
8991 .log_type
8992 .map(LanguageServerLogType::from_proto)
8993 .context("invalid language server log type")?;
8994
8995 let message = envelope.payload.message;
8996
8997 this.update(&mut cx, |_, cx| {
8998 cx.emit(LspStoreEvent::LanguageServerLog(
8999 language_server_id,
9000 log_type,
9001 message,
9002 ));
9003 })
9004 }
9005
9006 async fn handle_lsp_ext_cancel_flycheck(
9007 lsp_store: Entity<Self>,
9008 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9009 cx: AsyncApp,
9010 ) -> Result<proto::Ack> {
9011 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9012 lsp_store.read_with(&cx, |lsp_store, _| {
9013 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9014 server
9015 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
9016 .context("handling lsp ext cancel flycheck")
9017 } else {
9018 anyhow::Ok(())
9019 }
9020 })??;
9021
9022 Ok(proto::Ack {})
9023 }
9024
9025 async fn handle_lsp_ext_run_flycheck(
9026 lsp_store: Entity<Self>,
9027 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9028 mut cx: AsyncApp,
9029 ) -> Result<proto::Ack> {
9030 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9031 lsp_store.update(&mut cx, |lsp_store, cx| {
9032 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9033 let text_document = if envelope.payload.current_file_only {
9034 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9035 lsp_store
9036 .buffer_store()
9037 .read(cx)
9038 .get(buffer_id)
9039 .and_then(|buffer| Some(buffer.read(cx).file()?.as_local()?.abs_path(cx)))
9040 .map(|path| make_text_document_identifier(&path))
9041 .transpose()?
9042 } else {
9043 None
9044 };
9045 server
9046 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9047 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9048 )
9049 .context("handling lsp ext run flycheck")
9050 } else {
9051 anyhow::Ok(())
9052 }
9053 })??;
9054
9055 Ok(proto::Ack {})
9056 }
9057
9058 async fn handle_lsp_ext_clear_flycheck(
9059 lsp_store: Entity<Self>,
9060 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9061 cx: AsyncApp,
9062 ) -> Result<proto::Ack> {
9063 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9064 lsp_store.read_with(&cx, |lsp_store, _| {
9065 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9066 server
9067 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
9068 .context("handling lsp ext clear flycheck")
9069 } else {
9070 anyhow::Ok(())
9071 }
9072 })??;
9073
9074 Ok(proto::Ack {})
9075 }
9076
9077 pub fn disk_based_diagnostics_started(
9078 &mut self,
9079 language_server_id: LanguageServerId,
9080 cx: &mut Context<Self>,
9081 ) {
9082 if let Some(language_server_status) =
9083 self.language_server_statuses.get_mut(&language_server_id)
9084 {
9085 language_server_status.has_pending_diagnostic_updates = true;
9086 }
9087
9088 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9089 cx.emit(LspStoreEvent::LanguageServerUpdate {
9090 language_server_id,
9091 name: self
9092 .language_server_adapter_for_id(language_server_id)
9093 .map(|adapter| adapter.name()),
9094 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9095 Default::default(),
9096 ),
9097 })
9098 }
9099
9100 pub fn disk_based_diagnostics_finished(
9101 &mut self,
9102 language_server_id: LanguageServerId,
9103 cx: &mut Context<Self>,
9104 ) {
9105 if let Some(language_server_status) =
9106 self.language_server_statuses.get_mut(&language_server_id)
9107 {
9108 language_server_status.has_pending_diagnostic_updates = false;
9109 }
9110
9111 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9112 cx.emit(LspStoreEvent::LanguageServerUpdate {
9113 language_server_id,
9114 name: self
9115 .language_server_adapter_for_id(language_server_id)
9116 .map(|adapter| adapter.name()),
9117 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9118 Default::default(),
9119 ),
9120 })
9121 }
9122
9123 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9124 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9125 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9126 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9127 // the language server might take some time to publish diagnostics.
9128 fn simulate_disk_based_diagnostics_events_if_needed(
9129 &mut self,
9130 language_server_id: LanguageServerId,
9131 cx: &mut Context<Self>,
9132 ) {
9133 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9134
9135 let Some(LanguageServerState::Running {
9136 simulate_disk_based_diagnostics_completion,
9137 adapter,
9138 ..
9139 }) = self
9140 .as_local_mut()
9141 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9142 else {
9143 return;
9144 };
9145
9146 if adapter.disk_based_diagnostics_progress_token.is_some() {
9147 return;
9148 }
9149
9150 let prev_task =
9151 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9152 cx.background_executor()
9153 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9154 .await;
9155
9156 this.update(cx, |this, cx| {
9157 this.disk_based_diagnostics_finished(language_server_id, cx);
9158
9159 if let Some(LanguageServerState::Running {
9160 simulate_disk_based_diagnostics_completion,
9161 ..
9162 }) = this.as_local_mut().and_then(|local_store| {
9163 local_store.language_servers.get_mut(&language_server_id)
9164 }) {
9165 *simulate_disk_based_diagnostics_completion = None;
9166 }
9167 })
9168 .ok();
9169 }));
9170
9171 if prev_task.is_none() {
9172 self.disk_based_diagnostics_started(language_server_id, cx);
9173 }
9174 }
9175
9176 pub fn language_server_statuses(
9177 &self,
9178 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9179 self.language_server_statuses
9180 .iter()
9181 .map(|(key, value)| (*key, value))
9182 }
9183
9184 pub(super) fn did_rename_entry(
9185 &self,
9186 worktree_id: WorktreeId,
9187 old_path: &Path,
9188 new_path: &Path,
9189 is_dir: bool,
9190 ) {
9191 maybe!({
9192 let local_store = self.as_local()?;
9193
9194 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from)?;
9195 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from)?;
9196
9197 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9198 let Some(filter) = local_store
9199 .language_server_paths_watched_for_rename
9200 .get(&language_server.server_id())
9201 else {
9202 continue;
9203 };
9204
9205 if filter.should_send_did_rename(&old_uri, is_dir) {
9206 language_server
9207 .notify::<DidRenameFiles>(&RenameFilesParams {
9208 files: vec![FileRename {
9209 old_uri: old_uri.clone(),
9210 new_uri: new_uri.clone(),
9211 }],
9212 })
9213 .ok();
9214 }
9215 }
9216 Some(())
9217 });
9218 }
9219
9220 pub(super) fn will_rename_entry(
9221 this: WeakEntity<Self>,
9222 worktree_id: WorktreeId,
9223 old_path: &Path,
9224 new_path: &Path,
9225 is_dir: bool,
9226 cx: AsyncApp,
9227 ) -> Task<()> {
9228 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from);
9229 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from);
9230 cx.spawn(async move |cx| {
9231 let mut tasks = vec![];
9232 this.update(cx, |this, cx| {
9233 let local_store = this.as_local()?;
9234 let old_uri = old_uri?;
9235 let new_uri = new_uri?;
9236 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9237 let Some(filter) = local_store
9238 .language_server_paths_watched_for_rename
9239 .get(&language_server.server_id())
9240 else {
9241 continue;
9242 };
9243
9244 if filter.should_send_will_rename(&old_uri, is_dir) {
9245 let apply_edit = cx.spawn({
9246 let old_uri = old_uri.clone();
9247 let new_uri = new_uri.clone();
9248 let language_server = language_server.clone();
9249 async move |this, cx| {
9250 let edit = language_server
9251 .request::<WillRenameFiles>(RenameFilesParams {
9252 files: vec![FileRename { old_uri, new_uri }],
9253 })
9254 .await
9255 .into_response()
9256 .context("will rename files")
9257 .log_err()
9258 .flatten()?;
9259
9260 LocalLspStore::deserialize_workspace_edit(
9261 this.upgrade()?,
9262 edit,
9263 false,
9264 language_server.clone(),
9265 cx,
9266 )
9267 .await
9268 .ok();
9269 Some(())
9270 }
9271 });
9272 tasks.push(apply_edit);
9273 }
9274 }
9275 Some(())
9276 })
9277 .ok()
9278 .flatten();
9279 for task in tasks {
9280 // Await on tasks sequentially so that the order of application of edits is deterministic
9281 // (at least with regards to the order of registration of language servers)
9282 task.await;
9283 }
9284 })
9285 }
9286
9287 fn lsp_notify_abs_paths_changed(
9288 &mut self,
9289 server_id: LanguageServerId,
9290 changes: Vec<PathEvent>,
9291 ) {
9292 maybe!({
9293 let server = self.language_server_for_id(server_id)?;
9294 let changes = changes
9295 .into_iter()
9296 .filter_map(|event| {
9297 let typ = match event.kind? {
9298 PathEventKind::Created => lsp::FileChangeType::CREATED,
9299 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9300 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9301 };
9302 Some(lsp::FileEvent {
9303 uri: file_path_to_lsp_url(&event.path).log_err()?,
9304 typ,
9305 })
9306 })
9307 .collect::<Vec<_>>();
9308 if !changes.is_empty() {
9309 server
9310 .notify::<lsp::notification::DidChangeWatchedFiles>(
9311 &lsp::DidChangeWatchedFilesParams { changes },
9312 )
9313 .ok();
9314 }
9315 Some(())
9316 });
9317 }
9318
9319 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9320 self.as_local()?.language_server_for_id(id)
9321 }
9322
9323 fn on_lsp_progress(
9324 &mut self,
9325 progress: lsp::ProgressParams,
9326 language_server_id: LanguageServerId,
9327 disk_based_diagnostics_progress_token: Option<String>,
9328 cx: &mut Context<Self>,
9329 ) {
9330 let token = match progress.token {
9331 lsp::NumberOrString::String(token) => token,
9332 lsp::NumberOrString::Number(token) => {
9333 log::info!("skipping numeric progress token {}", token);
9334 return;
9335 }
9336 };
9337
9338 match progress.value {
9339 lsp::ProgressParamsValue::WorkDone(progress) => {
9340 self.handle_work_done_progress(
9341 progress,
9342 language_server_id,
9343 disk_based_diagnostics_progress_token,
9344 token,
9345 cx,
9346 );
9347 }
9348 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9349 if let Some(LanguageServerState::Running {
9350 workspace_refresh_task: Some(workspace_refresh_task),
9351 ..
9352 }) = self
9353 .as_local_mut()
9354 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9355 {
9356 workspace_refresh_task.progress_tx.try_send(()).ok();
9357 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9358 }
9359 }
9360 }
9361 }
9362
9363 fn handle_work_done_progress(
9364 &mut self,
9365 progress: lsp::WorkDoneProgress,
9366 language_server_id: LanguageServerId,
9367 disk_based_diagnostics_progress_token: Option<String>,
9368 token: String,
9369 cx: &mut Context<Self>,
9370 ) {
9371 let language_server_status =
9372 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9373 status
9374 } else {
9375 return;
9376 };
9377
9378 if !language_server_status.progress_tokens.contains(&token) {
9379 return;
9380 }
9381
9382 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9383 .as_ref()
9384 .is_some_and(|disk_based_token| token.starts_with(disk_based_token));
9385
9386 match progress {
9387 lsp::WorkDoneProgress::Begin(report) => {
9388 if is_disk_based_diagnostics_progress {
9389 self.disk_based_diagnostics_started(language_server_id, cx);
9390 }
9391 self.on_lsp_work_start(
9392 language_server_id,
9393 token.clone(),
9394 LanguageServerProgress {
9395 title: Some(report.title),
9396 is_disk_based_diagnostics_progress,
9397 is_cancellable: report.cancellable.unwrap_or(false),
9398 message: report.message.clone(),
9399 percentage: report.percentage.map(|p| p as usize),
9400 last_update_at: cx.background_executor().now(),
9401 },
9402 cx,
9403 );
9404 }
9405 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9406 language_server_id,
9407 token,
9408 LanguageServerProgress {
9409 title: None,
9410 is_disk_based_diagnostics_progress,
9411 is_cancellable: report.cancellable.unwrap_or(false),
9412 message: report.message,
9413 percentage: report.percentage.map(|p| p as usize),
9414 last_update_at: cx.background_executor().now(),
9415 },
9416 cx,
9417 ),
9418 lsp::WorkDoneProgress::End(_) => {
9419 language_server_status.progress_tokens.remove(&token);
9420 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9421 if is_disk_based_diagnostics_progress {
9422 self.disk_based_diagnostics_finished(language_server_id, cx);
9423 }
9424 }
9425 }
9426 }
9427
9428 fn on_lsp_work_start(
9429 &mut self,
9430 language_server_id: LanguageServerId,
9431 token: String,
9432 progress: LanguageServerProgress,
9433 cx: &mut Context<Self>,
9434 ) {
9435 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9436 status.pending_work.insert(token.clone(), progress.clone());
9437 cx.notify();
9438 }
9439 cx.emit(LspStoreEvent::LanguageServerUpdate {
9440 language_server_id,
9441 name: self
9442 .language_server_adapter_for_id(language_server_id)
9443 .map(|adapter| adapter.name()),
9444 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9445 token,
9446 title: progress.title,
9447 message: progress.message,
9448 percentage: progress.percentage.map(|p| p as u32),
9449 is_cancellable: Some(progress.is_cancellable),
9450 }),
9451 })
9452 }
9453
9454 fn on_lsp_work_progress(
9455 &mut self,
9456 language_server_id: LanguageServerId,
9457 token: String,
9458 progress: LanguageServerProgress,
9459 cx: &mut Context<Self>,
9460 ) {
9461 let mut did_update = false;
9462 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9463 match status.pending_work.entry(token.clone()) {
9464 btree_map::Entry::Vacant(entry) => {
9465 entry.insert(progress.clone());
9466 did_update = true;
9467 }
9468 btree_map::Entry::Occupied(mut entry) => {
9469 let entry = entry.get_mut();
9470 if (progress.last_update_at - entry.last_update_at)
9471 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9472 {
9473 entry.last_update_at = progress.last_update_at;
9474 if progress.message.is_some() {
9475 entry.message = progress.message.clone();
9476 }
9477 if progress.percentage.is_some() {
9478 entry.percentage = progress.percentage;
9479 }
9480 if progress.is_cancellable != entry.is_cancellable {
9481 entry.is_cancellable = progress.is_cancellable;
9482 }
9483 did_update = true;
9484 }
9485 }
9486 }
9487 }
9488
9489 if did_update {
9490 cx.emit(LspStoreEvent::LanguageServerUpdate {
9491 language_server_id,
9492 name: self
9493 .language_server_adapter_for_id(language_server_id)
9494 .map(|adapter| adapter.name()),
9495 message: proto::update_language_server::Variant::WorkProgress(
9496 proto::LspWorkProgress {
9497 token,
9498 message: progress.message,
9499 percentage: progress.percentage.map(|p| p as u32),
9500 is_cancellable: Some(progress.is_cancellable),
9501 },
9502 ),
9503 })
9504 }
9505 }
9506
9507 fn on_lsp_work_end(
9508 &mut self,
9509 language_server_id: LanguageServerId,
9510 token: String,
9511 cx: &mut Context<Self>,
9512 ) {
9513 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9514 if let Some(work) = status.pending_work.remove(&token)
9515 && !work.is_disk_based_diagnostics_progress
9516 {
9517 cx.emit(LspStoreEvent::RefreshInlayHints);
9518 }
9519 cx.notify();
9520 }
9521
9522 cx.emit(LspStoreEvent::LanguageServerUpdate {
9523 language_server_id,
9524 name: self
9525 .language_server_adapter_for_id(language_server_id)
9526 .map(|adapter| adapter.name()),
9527 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9528 })
9529 }
9530
9531 pub async fn handle_resolve_completion_documentation(
9532 this: Entity<Self>,
9533 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9534 mut cx: AsyncApp,
9535 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9536 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9537
9538 let completion = this
9539 .read_with(&cx, |this, cx| {
9540 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9541 let server = this
9542 .language_server_for_id(id)
9543 .with_context(|| format!("No language server {id}"))?;
9544
9545 anyhow::Ok(cx.background_spawn(async move {
9546 let can_resolve = server
9547 .capabilities()
9548 .completion_provider
9549 .as_ref()
9550 .and_then(|options| options.resolve_provider)
9551 .unwrap_or(false);
9552 if can_resolve {
9553 server
9554 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9555 .await
9556 .into_response()
9557 .context("resolve completion item")
9558 } else {
9559 anyhow::Ok(lsp_completion)
9560 }
9561 }))
9562 })??
9563 .await?;
9564
9565 let mut documentation_is_markdown = false;
9566 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9567 let documentation = match completion.documentation {
9568 Some(lsp::Documentation::String(text)) => text,
9569
9570 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9571 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9572 value
9573 }
9574
9575 _ => String::new(),
9576 };
9577
9578 // If we have a new buffer_id, that means we're talking to a new client
9579 // and want to check for new text_edits in the completion too.
9580 let mut old_replace_start = None;
9581 let mut old_replace_end = None;
9582 let mut old_insert_start = None;
9583 let mut old_insert_end = None;
9584 let mut new_text = String::default();
9585 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9586 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9587 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9588 anyhow::Ok(buffer.read(cx).snapshot())
9589 })??;
9590
9591 if let Some(text_edit) = completion.text_edit.as_ref() {
9592 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9593
9594 if let Some(mut edit) = edit {
9595 LineEnding::normalize(&mut edit.new_text);
9596
9597 new_text = edit.new_text;
9598 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9599 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9600 if let Some(insert_range) = edit.insert_range {
9601 old_insert_start = Some(serialize_anchor(&insert_range.start));
9602 old_insert_end = Some(serialize_anchor(&insert_range.end));
9603 }
9604 }
9605 }
9606 }
9607
9608 Ok(proto::ResolveCompletionDocumentationResponse {
9609 documentation,
9610 documentation_is_markdown,
9611 old_replace_start,
9612 old_replace_end,
9613 new_text,
9614 lsp_completion,
9615 old_insert_start,
9616 old_insert_end,
9617 })
9618 }
9619
9620 async fn handle_on_type_formatting(
9621 this: Entity<Self>,
9622 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9623 mut cx: AsyncApp,
9624 ) -> Result<proto::OnTypeFormattingResponse> {
9625 let on_type_formatting = this.update(&mut cx, |this, cx| {
9626 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9627 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9628 let position = envelope
9629 .payload
9630 .position
9631 .and_then(deserialize_anchor)
9632 .context("invalid position")?;
9633 anyhow::Ok(this.apply_on_type_formatting(
9634 buffer,
9635 position,
9636 envelope.payload.trigger.clone(),
9637 cx,
9638 ))
9639 })??;
9640
9641 let transaction = on_type_formatting
9642 .await?
9643 .as_ref()
9644 .map(language::proto::serialize_transaction);
9645 Ok(proto::OnTypeFormattingResponse { transaction })
9646 }
9647
9648 async fn handle_refresh_inlay_hints(
9649 this: Entity<Self>,
9650 _: TypedEnvelope<proto::RefreshInlayHints>,
9651 mut cx: AsyncApp,
9652 ) -> Result<proto::Ack> {
9653 this.update(&mut cx, |_, cx| {
9654 cx.emit(LspStoreEvent::RefreshInlayHints);
9655 })?;
9656 Ok(proto::Ack {})
9657 }
9658
9659 async fn handle_pull_workspace_diagnostics(
9660 lsp_store: Entity<Self>,
9661 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9662 mut cx: AsyncApp,
9663 ) -> Result<proto::Ack> {
9664 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9665 lsp_store.update(&mut cx, |lsp_store, _| {
9666 lsp_store.pull_workspace_diagnostics(server_id);
9667 })?;
9668 Ok(proto::Ack {})
9669 }
9670
9671 async fn handle_inlay_hints(
9672 this: Entity<Self>,
9673 envelope: TypedEnvelope<proto::InlayHints>,
9674 mut cx: AsyncApp,
9675 ) -> Result<proto::InlayHintsResponse> {
9676 let sender_id = envelope.original_sender_id().unwrap_or_default();
9677 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9678 let buffer = this.update(&mut cx, |this, cx| {
9679 this.buffer_store.read(cx).get_existing(buffer_id)
9680 })??;
9681 buffer
9682 .update(&mut cx, |buffer, _| {
9683 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9684 })?
9685 .await
9686 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9687
9688 let start = envelope
9689 .payload
9690 .start
9691 .and_then(deserialize_anchor)
9692 .context("missing range start")?;
9693 let end = envelope
9694 .payload
9695 .end
9696 .and_then(deserialize_anchor)
9697 .context("missing range end")?;
9698 let buffer_hints = this
9699 .update(&mut cx, |lsp_store, cx| {
9700 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9701 })?
9702 .await
9703 .context("inlay hints fetch")?;
9704
9705 this.update(&mut cx, |project, cx| {
9706 InlayHints::response_to_proto(
9707 buffer_hints,
9708 project,
9709 sender_id,
9710 &buffer.read(cx).version(),
9711 cx,
9712 )
9713 })
9714 }
9715
9716 async fn handle_get_color_presentation(
9717 lsp_store: Entity<Self>,
9718 envelope: TypedEnvelope<proto::GetColorPresentation>,
9719 mut cx: AsyncApp,
9720 ) -> Result<proto::GetColorPresentationResponse> {
9721 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9722 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9723 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9724 })??;
9725
9726 let color = envelope
9727 .payload
9728 .color
9729 .context("invalid color resolve request")?;
9730 let start = color
9731 .lsp_range_start
9732 .context("invalid color resolve request")?;
9733 let end = color
9734 .lsp_range_end
9735 .context("invalid color resolve request")?;
9736
9737 let color = DocumentColor {
9738 lsp_range: lsp::Range {
9739 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9740 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9741 },
9742 color: lsp::Color {
9743 red: color.red,
9744 green: color.green,
9745 blue: color.blue,
9746 alpha: color.alpha,
9747 },
9748 resolved: false,
9749 color_presentations: Vec::new(),
9750 };
9751 let resolved_color = lsp_store
9752 .update(&mut cx, |lsp_store, cx| {
9753 lsp_store.resolve_color_presentation(
9754 color,
9755 buffer.clone(),
9756 LanguageServerId(envelope.payload.server_id as usize),
9757 cx,
9758 )
9759 })?
9760 .await
9761 .context("resolving color presentation")?;
9762
9763 Ok(proto::GetColorPresentationResponse {
9764 presentations: resolved_color
9765 .color_presentations
9766 .into_iter()
9767 .map(|presentation| proto::ColorPresentation {
9768 label: presentation.label.to_string(),
9769 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9770 additional_text_edits: presentation
9771 .additional_text_edits
9772 .into_iter()
9773 .map(serialize_lsp_edit)
9774 .collect(),
9775 })
9776 .collect(),
9777 })
9778 }
9779
9780 async fn handle_resolve_inlay_hint(
9781 this: Entity<Self>,
9782 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9783 mut cx: AsyncApp,
9784 ) -> Result<proto::ResolveInlayHintResponse> {
9785 let proto_hint = envelope
9786 .payload
9787 .hint
9788 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9789 let hint = InlayHints::proto_to_project_hint(proto_hint)
9790 .context("resolved proto inlay hint conversion")?;
9791 let buffer = this.update(&mut cx, |this, cx| {
9792 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9793 this.buffer_store.read(cx).get_existing(buffer_id)
9794 })??;
9795 let response_hint = this
9796 .update(&mut cx, |this, cx| {
9797 this.resolve_inlay_hint(
9798 hint,
9799 buffer,
9800 LanguageServerId(envelope.payload.language_server_id as usize),
9801 cx,
9802 )
9803 })?
9804 .await
9805 .context("inlay hints fetch")?;
9806 Ok(proto::ResolveInlayHintResponse {
9807 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9808 })
9809 }
9810
9811 async fn handle_refresh_code_lens(
9812 this: Entity<Self>,
9813 _: TypedEnvelope<proto::RefreshCodeLens>,
9814 mut cx: AsyncApp,
9815 ) -> Result<proto::Ack> {
9816 this.update(&mut cx, |_, cx| {
9817 cx.emit(LspStoreEvent::RefreshCodeLens);
9818 })?;
9819 Ok(proto::Ack {})
9820 }
9821
9822 async fn handle_open_buffer_for_symbol(
9823 this: Entity<Self>,
9824 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9825 mut cx: AsyncApp,
9826 ) -> Result<proto::OpenBufferForSymbolResponse> {
9827 let peer_id = envelope.original_sender_id().unwrap_or_default();
9828 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9829 let symbol = Self::deserialize_symbol(symbol)?;
9830 let symbol = this.read_with(&cx, |this, _| {
9831 let signature = this.symbol_signature(&symbol.path);
9832 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9833 Ok(symbol)
9834 })??;
9835 let buffer = this
9836 .update(&mut cx, |this, cx| {
9837 this.open_buffer_for_symbol(
9838 &Symbol {
9839 language_server_name: symbol.language_server_name,
9840 source_worktree_id: symbol.source_worktree_id,
9841 source_language_server_id: symbol.source_language_server_id,
9842 path: symbol.path,
9843 name: symbol.name,
9844 kind: symbol.kind,
9845 range: symbol.range,
9846 signature: symbol.signature,
9847 label: CodeLabel {
9848 text: Default::default(),
9849 runs: Default::default(),
9850 filter_range: Default::default(),
9851 },
9852 },
9853 cx,
9854 )
9855 })?
9856 .await?;
9857
9858 this.update(&mut cx, |this, cx| {
9859 let is_private = buffer
9860 .read(cx)
9861 .file()
9862 .map(|f| f.is_private())
9863 .unwrap_or_default();
9864 if is_private {
9865 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9866 } else {
9867 this.buffer_store
9868 .update(cx, |buffer_store, cx| {
9869 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9870 })
9871 .detach_and_log_err(cx);
9872 let buffer_id = buffer.read(cx).remote_id().to_proto();
9873 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9874 }
9875 })?
9876 }
9877
9878 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
9879 let mut hasher = Sha256::new();
9880 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
9881 hasher.update(project_path.path.to_string_lossy().as_bytes());
9882 hasher.update(self.nonce.to_be_bytes());
9883 hasher.finalize().as_slice().try_into().unwrap()
9884 }
9885
9886 pub async fn handle_get_project_symbols(
9887 this: Entity<Self>,
9888 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9889 mut cx: AsyncApp,
9890 ) -> Result<proto::GetProjectSymbolsResponse> {
9891 let symbols = this
9892 .update(&mut cx, |this, cx| {
9893 this.symbols(&envelope.payload.query, cx)
9894 })?
9895 .await?;
9896
9897 Ok(proto::GetProjectSymbolsResponse {
9898 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9899 })
9900 }
9901
9902 pub async fn handle_restart_language_servers(
9903 this: Entity<Self>,
9904 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9905 mut cx: AsyncApp,
9906 ) -> Result<proto::Ack> {
9907 this.update(&mut cx, |lsp_store, cx| {
9908 let buffers =
9909 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9910 lsp_store.restart_language_servers_for_buffers(
9911 buffers,
9912 envelope
9913 .payload
9914 .only_servers
9915 .into_iter()
9916 .filter_map(|selector| {
9917 Some(match selector.selector? {
9918 proto::language_server_selector::Selector::ServerId(server_id) => {
9919 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9920 }
9921 proto::language_server_selector::Selector::Name(name) => {
9922 LanguageServerSelector::Name(LanguageServerName(
9923 SharedString::from(name),
9924 ))
9925 }
9926 })
9927 })
9928 .collect(),
9929 cx,
9930 );
9931 })?;
9932
9933 Ok(proto::Ack {})
9934 }
9935
9936 pub async fn handle_stop_language_servers(
9937 lsp_store: Entity<Self>,
9938 envelope: TypedEnvelope<proto::StopLanguageServers>,
9939 mut cx: AsyncApp,
9940 ) -> Result<proto::Ack> {
9941 lsp_store.update(&mut cx, |lsp_store, cx| {
9942 if envelope.payload.all
9943 && envelope.payload.also_servers.is_empty()
9944 && envelope.payload.buffer_ids.is_empty()
9945 {
9946 lsp_store.stop_all_language_servers(cx);
9947 } else {
9948 let buffers =
9949 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9950 lsp_store
9951 .stop_language_servers_for_buffers(
9952 buffers,
9953 envelope
9954 .payload
9955 .also_servers
9956 .into_iter()
9957 .filter_map(|selector| {
9958 Some(match selector.selector? {
9959 proto::language_server_selector::Selector::ServerId(
9960 server_id,
9961 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
9962 server_id,
9963 )),
9964 proto::language_server_selector::Selector::Name(name) => {
9965 LanguageServerSelector::Name(LanguageServerName(
9966 SharedString::from(name),
9967 ))
9968 }
9969 })
9970 })
9971 .collect(),
9972 cx,
9973 )
9974 .detach_and_log_err(cx);
9975 }
9976 })?;
9977
9978 Ok(proto::Ack {})
9979 }
9980
9981 pub async fn handle_cancel_language_server_work(
9982 this: Entity<Self>,
9983 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
9984 mut cx: AsyncApp,
9985 ) -> Result<proto::Ack> {
9986 this.update(&mut cx, |this, cx| {
9987 if let Some(work) = envelope.payload.work {
9988 match work {
9989 proto::cancel_language_server_work::Work::Buffers(buffers) => {
9990 let buffers =
9991 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
9992 this.cancel_language_server_work_for_buffers(buffers, cx);
9993 }
9994 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
9995 let server_id = LanguageServerId::from_proto(work.language_server_id);
9996 this.cancel_language_server_work(server_id, work.token, cx);
9997 }
9998 }
9999 }
10000 })?;
10001
10002 Ok(proto::Ack {})
10003 }
10004
10005 fn buffer_ids_to_buffers(
10006 &mut self,
10007 buffer_ids: impl Iterator<Item = u64>,
10008 cx: &mut Context<Self>,
10009 ) -> Vec<Entity<Buffer>> {
10010 buffer_ids
10011 .into_iter()
10012 .flat_map(|buffer_id| {
10013 self.buffer_store
10014 .read(cx)
10015 .get(BufferId::new(buffer_id).log_err()?)
10016 })
10017 .collect::<Vec<_>>()
10018 }
10019
10020 async fn handle_apply_additional_edits_for_completion(
10021 this: Entity<Self>,
10022 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10023 mut cx: AsyncApp,
10024 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10025 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10026 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10027 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10028 let completion = Self::deserialize_completion(
10029 envelope.payload.completion.context("invalid completion")?,
10030 )?;
10031 anyhow::Ok((buffer, completion))
10032 })??;
10033
10034 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10035 this.apply_additional_edits_for_completion(
10036 buffer,
10037 Rc::new(RefCell::new(Box::new([Completion {
10038 replace_range: completion.replace_range,
10039 new_text: completion.new_text,
10040 source: completion.source,
10041 documentation: None,
10042 label: CodeLabel {
10043 text: Default::default(),
10044 runs: Default::default(),
10045 filter_range: Default::default(),
10046 },
10047 insert_text_mode: None,
10048 icon_path: None,
10049 confirm: None,
10050 }]))),
10051 0,
10052 false,
10053 cx,
10054 )
10055 })?;
10056
10057 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10058 transaction: apply_additional_edits
10059 .await?
10060 .as_ref()
10061 .map(language::proto::serialize_transaction),
10062 })
10063 }
10064
10065 pub fn last_formatting_failure(&self) -> Option<&str> {
10066 self.last_formatting_failure.as_deref()
10067 }
10068
10069 pub fn reset_last_formatting_failure(&mut self) {
10070 self.last_formatting_failure = None;
10071 }
10072
10073 pub fn environment_for_buffer(
10074 &self,
10075 buffer: &Entity<Buffer>,
10076 cx: &mut Context<Self>,
10077 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10078 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10079 environment.update(cx, |env, cx| {
10080 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10081 })
10082 } else {
10083 Task::ready(None).shared()
10084 }
10085 }
10086
10087 pub fn format(
10088 &mut self,
10089 buffers: HashSet<Entity<Buffer>>,
10090 target: LspFormatTarget,
10091 push_to_history: bool,
10092 trigger: FormatTrigger,
10093 cx: &mut Context<Self>,
10094 ) -> Task<anyhow::Result<ProjectTransaction>> {
10095 let logger = zlog::scoped!("format");
10096 if self.as_local().is_some() {
10097 zlog::trace!(logger => "Formatting locally");
10098 let logger = zlog::scoped!(logger => "local");
10099 let buffers = buffers
10100 .into_iter()
10101 .map(|buffer_handle| {
10102 let buffer = buffer_handle.read(cx);
10103 let buffer_abs_path = File::from_dyn(buffer.file())
10104 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10105
10106 (buffer_handle, buffer_abs_path, buffer.remote_id())
10107 })
10108 .collect::<Vec<_>>();
10109
10110 cx.spawn(async move |lsp_store, cx| {
10111 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10112
10113 for (handle, abs_path, id) in buffers {
10114 let env = lsp_store
10115 .update(cx, |lsp_store, cx| {
10116 lsp_store.environment_for_buffer(&handle, cx)
10117 })?
10118 .await;
10119
10120 let ranges = match &target {
10121 LspFormatTarget::Buffers => None,
10122 LspFormatTarget::Ranges(ranges) => {
10123 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10124 }
10125 };
10126
10127 formattable_buffers.push(FormattableBuffer {
10128 handle,
10129 abs_path,
10130 env,
10131 ranges,
10132 });
10133 }
10134 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10135
10136 let format_timer = zlog::time!(logger => "Formatting buffers");
10137 let result = LocalLspStore::format_locally(
10138 lsp_store.clone(),
10139 formattable_buffers,
10140 push_to_history,
10141 trigger,
10142 logger,
10143 cx,
10144 )
10145 .await;
10146 format_timer.end();
10147
10148 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10149
10150 lsp_store.update(cx, |lsp_store, _| {
10151 lsp_store.update_last_formatting_failure(&result);
10152 })?;
10153
10154 result
10155 })
10156 } else if let Some((client, project_id)) = self.upstream_client() {
10157 zlog::trace!(logger => "Formatting remotely");
10158 let logger = zlog::scoped!(logger => "remote");
10159 // Don't support formatting ranges via remote
10160 match target {
10161 LspFormatTarget::Buffers => {}
10162 LspFormatTarget::Ranges(_) => {
10163 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10164 return Task::ready(Ok(ProjectTransaction::default()));
10165 }
10166 }
10167
10168 let buffer_store = self.buffer_store();
10169 cx.spawn(async move |lsp_store, cx| {
10170 zlog::trace!(logger => "Sending remote format request");
10171 let request_timer = zlog::time!(logger => "remote format request");
10172 let result = client
10173 .request(proto::FormatBuffers {
10174 project_id,
10175 trigger: trigger as i32,
10176 buffer_ids: buffers
10177 .iter()
10178 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10179 .collect::<Result<_>>()?,
10180 })
10181 .await
10182 .and_then(|result| result.transaction.context("missing transaction"));
10183 request_timer.end();
10184
10185 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10186
10187 lsp_store.update(cx, |lsp_store, _| {
10188 lsp_store.update_last_formatting_failure(&result);
10189 })?;
10190
10191 let transaction_response = result?;
10192 let _timer = zlog::time!(logger => "deserializing project transaction");
10193 buffer_store
10194 .update(cx, |buffer_store, cx| {
10195 buffer_store.deserialize_project_transaction(
10196 transaction_response,
10197 push_to_history,
10198 cx,
10199 )
10200 })?
10201 .await
10202 })
10203 } else {
10204 zlog::trace!(logger => "Not formatting");
10205 Task::ready(Ok(ProjectTransaction::default()))
10206 }
10207 }
10208
10209 async fn handle_format_buffers(
10210 this: Entity<Self>,
10211 envelope: TypedEnvelope<proto::FormatBuffers>,
10212 mut cx: AsyncApp,
10213 ) -> Result<proto::FormatBuffersResponse> {
10214 let sender_id = envelope.original_sender_id().unwrap_or_default();
10215 let format = this.update(&mut cx, |this, cx| {
10216 let mut buffers = HashSet::default();
10217 for buffer_id in &envelope.payload.buffer_ids {
10218 let buffer_id = BufferId::new(*buffer_id)?;
10219 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10220 }
10221 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10222 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10223 })??;
10224
10225 let project_transaction = format.await?;
10226 let project_transaction = this.update(&mut cx, |this, cx| {
10227 this.buffer_store.update(cx, |buffer_store, cx| {
10228 buffer_store.serialize_project_transaction_for_peer(
10229 project_transaction,
10230 sender_id,
10231 cx,
10232 )
10233 })
10234 })?;
10235 Ok(proto::FormatBuffersResponse {
10236 transaction: Some(project_transaction),
10237 })
10238 }
10239
10240 async fn handle_apply_code_action_kind(
10241 this: Entity<Self>,
10242 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10243 mut cx: AsyncApp,
10244 ) -> Result<proto::ApplyCodeActionKindResponse> {
10245 let sender_id = envelope.original_sender_id().unwrap_or_default();
10246 let format = this.update(&mut cx, |this, cx| {
10247 let mut buffers = HashSet::default();
10248 for buffer_id in &envelope.payload.buffer_ids {
10249 let buffer_id = BufferId::new(*buffer_id)?;
10250 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10251 }
10252 let kind = match envelope.payload.kind.as_str() {
10253 "" => CodeActionKind::EMPTY,
10254 "quickfix" => CodeActionKind::QUICKFIX,
10255 "refactor" => CodeActionKind::REFACTOR,
10256 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10257 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10258 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10259 "source" => CodeActionKind::SOURCE,
10260 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10261 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10262 _ => anyhow::bail!(
10263 "Invalid code action kind {}",
10264 envelope.payload.kind.as_str()
10265 ),
10266 };
10267 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10268 })??;
10269
10270 let project_transaction = format.await?;
10271 let project_transaction = this.update(&mut cx, |this, cx| {
10272 this.buffer_store.update(cx, |buffer_store, cx| {
10273 buffer_store.serialize_project_transaction_for_peer(
10274 project_transaction,
10275 sender_id,
10276 cx,
10277 )
10278 })
10279 })?;
10280 Ok(proto::ApplyCodeActionKindResponse {
10281 transaction: Some(project_transaction),
10282 })
10283 }
10284
10285 async fn shutdown_language_server(
10286 server_state: Option<LanguageServerState>,
10287 name: LanguageServerName,
10288 cx: &mut AsyncApp,
10289 ) {
10290 let server = match server_state {
10291 Some(LanguageServerState::Starting { startup, .. }) => {
10292 let mut timer = cx
10293 .background_executor()
10294 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10295 .fuse();
10296
10297 select! {
10298 server = startup.fuse() => server,
10299 () = timer => {
10300 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10301 None
10302 },
10303 }
10304 }
10305
10306 Some(LanguageServerState::Running { server, .. }) => Some(server),
10307
10308 None => None,
10309 };
10310
10311 if let Some(server) = server
10312 && let Some(shutdown) = server.shutdown()
10313 {
10314 shutdown.await;
10315 }
10316 }
10317
10318 // Returns a list of all of the worktrees which no longer have a language server and the root path
10319 // for the stopped server
10320 fn stop_local_language_server(
10321 &mut self,
10322 server_id: LanguageServerId,
10323 cx: &mut Context<Self>,
10324 ) -> Task<()> {
10325 let local = match &mut self.mode {
10326 LspStoreMode::Local(local) => local,
10327 _ => {
10328 return Task::ready(());
10329 }
10330 };
10331
10332 // Remove this server ID from all entries in the given worktree.
10333 local
10334 .language_server_ids
10335 .retain(|_, state| state.id != server_id);
10336 self.buffer_store.update(cx, |buffer_store, cx| {
10337 for buffer in buffer_store.buffers() {
10338 buffer.update(cx, |buffer, cx| {
10339 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10340 buffer.set_completion_triggers(server_id, Default::default(), cx);
10341 });
10342 }
10343 });
10344
10345 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10346 summaries.retain(|path, summaries_by_server_id| {
10347 if summaries_by_server_id.remove(&server_id).is_some() {
10348 if let Some((client, project_id)) = self.downstream_client.clone() {
10349 client
10350 .send(proto::UpdateDiagnosticSummary {
10351 project_id,
10352 worktree_id: worktree_id.to_proto(),
10353 summary: Some(proto::DiagnosticSummary {
10354 path: path.as_ref().to_proto(),
10355 language_server_id: server_id.0 as u64,
10356 error_count: 0,
10357 warning_count: 0,
10358 }),
10359 more_summaries: Vec::new(),
10360 })
10361 .log_err();
10362 }
10363 !summaries_by_server_id.is_empty()
10364 } else {
10365 true
10366 }
10367 });
10368 }
10369
10370 let local = self.as_local_mut().unwrap();
10371 for diagnostics in local.diagnostics.values_mut() {
10372 diagnostics.retain(|_, diagnostics_by_server_id| {
10373 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10374 diagnostics_by_server_id.remove(ix);
10375 !diagnostics_by_server_id.is_empty()
10376 } else {
10377 true
10378 }
10379 });
10380 }
10381 local.language_server_watched_paths.remove(&server_id);
10382
10383 let server_state = local.language_servers.remove(&server_id);
10384 self.cleanup_lsp_data(server_id);
10385 let name = self
10386 .language_server_statuses
10387 .remove(&server_id)
10388 .map(|status| status.name)
10389 .or_else(|| {
10390 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10391 Some(adapter.name())
10392 } else {
10393 None
10394 }
10395 });
10396
10397 if let Some(name) = name {
10398 log::info!("stopping language server {name}");
10399 self.languages
10400 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10401 cx.notify();
10402
10403 return cx.spawn(async move |lsp_store, cx| {
10404 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10405 lsp_store
10406 .update(cx, |lsp_store, cx| {
10407 lsp_store
10408 .languages
10409 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10410 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10411 cx.notify();
10412 })
10413 .ok();
10414 });
10415 }
10416
10417 if server_state.is_some() {
10418 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10419 }
10420 Task::ready(())
10421 }
10422
10423 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10424 if let Some((client, project_id)) = self.upstream_client() {
10425 let request = client.request(proto::StopLanguageServers {
10426 project_id,
10427 buffer_ids: Vec::new(),
10428 also_servers: Vec::new(),
10429 all: true,
10430 });
10431 cx.background_spawn(request).detach_and_log_err(cx);
10432 } else {
10433 let Some(local) = self.as_local_mut() else {
10434 return;
10435 };
10436 let language_servers_to_stop = local
10437 .language_server_ids
10438 .values()
10439 .map(|state| state.id)
10440 .collect();
10441 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10442 let tasks = language_servers_to_stop
10443 .into_iter()
10444 .map(|server| self.stop_local_language_server(server, cx))
10445 .collect::<Vec<_>>();
10446 cx.background_spawn(async move {
10447 futures::future::join_all(tasks).await;
10448 })
10449 .detach();
10450 }
10451 }
10452
10453 pub fn restart_language_servers_for_buffers(
10454 &mut self,
10455 buffers: Vec<Entity<Buffer>>,
10456 only_restart_servers: HashSet<LanguageServerSelector>,
10457 cx: &mut Context<Self>,
10458 ) {
10459 if let Some((client, project_id)) = self.upstream_client() {
10460 let request = client.request(proto::RestartLanguageServers {
10461 project_id,
10462 buffer_ids: buffers
10463 .into_iter()
10464 .map(|b| b.read(cx).remote_id().to_proto())
10465 .collect(),
10466 only_servers: only_restart_servers
10467 .into_iter()
10468 .map(|selector| {
10469 let selector = match selector {
10470 LanguageServerSelector::Id(language_server_id) => {
10471 proto::language_server_selector::Selector::ServerId(
10472 language_server_id.to_proto(),
10473 )
10474 }
10475 LanguageServerSelector::Name(language_server_name) => {
10476 proto::language_server_selector::Selector::Name(
10477 language_server_name.to_string(),
10478 )
10479 }
10480 };
10481 proto::LanguageServerSelector {
10482 selector: Some(selector),
10483 }
10484 })
10485 .collect(),
10486 all: false,
10487 });
10488 cx.background_spawn(request).detach_and_log_err(cx);
10489 } else {
10490 let stop_task = if only_restart_servers.is_empty() {
10491 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10492 } else {
10493 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10494 };
10495 cx.spawn(async move |lsp_store, cx| {
10496 stop_task.await;
10497 lsp_store
10498 .update(cx, |lsp_store, cx| {
10499 for buffer in buffers {
10500 lsp_store.register_buffer_with_language_servers(
10501 &buffer,
10502 only_restart_servers.clone(),
10503 true,
10504 cx,
10505 );
10506 }
10507 })
10508 .ok()
10509 })
10510 .detach();
10511 }
10512 }
10513
10514 pub fn stop_language_servers_for_buffers(
10515 &mut self,
10516 buffers: Vec<Entity<Buffer>>,
10517 also_stop_servers: HashSet<LanguageServerSelector>,
10518 cx: &mut Context<Self>,
10519 ) -> Task<Result<()>> {
10520 if let Some((client, project_id)) = self.upstream_client() {
10521 let request = client.request(proto::StopLanguageServers {
10522 project_id,
10523 buffer_ids: buffers
10524 .into_iter()
10525 .map(|b| b.read(cx).remote_id().to_proto())
10526 .collect(),
10527 also_servers: also_stop_servers
10528 .into_iter()
10529 .map(|selector| {
10530 let selector = match selector {
10531 LanguageServerSelector::Id(language_server_id) => {
10532 proto::language_server_selector::Selector::ServerId(
10533 language_server_id.to_proto(),
10534 )
10535 }
10536 LanguageServerSelector::Name(language_server_name) => {
10537 proto::language_server_selector::Selector::Name(
10538 language_server_name.to_string(),
10539 )
10540 }
10541 };
10542 proto::LanguageServerSelector {
10543 selector: Some(selector),
10544 }
10545 })
10546 .collect(),
10547 all: false,
10548 });
10549 cx.background_spawn(async move {
10550 let _ = request.await?;
10551 Ok(())
10552 })
10553 } else {
10554 let task =
10555 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10556 cx.background_spawn(async move {
10557 task.await;
10558 Ok(())
10559 })
10560 }
10561 }
10562
10563 fn stop_local_language_servers_for_buffers(
10564 &mut self,
10565 buffers: &[Entity<Buffer>],
10566 also_stop_servers: HashSet<LanguageServerSelector>,
10567 cx: &mut Context<Self>,
10568 ) -> Task<()> {
10569 let Some(local) = self.as_local_mut() else {
10570 return Task::ready(());
10571 };
10572 let mut language_server_names_to_stop = BTreeSet::default();
10573 let mut language_servers_to_stop = also_stop_servers
10574 .into_iter()
10575 .flat_map(|selector| match selector {
10576 LanguageServerSelector::Id(id) => Some(id),
10577 LanguageServerSelector::Name(name) => {
10578 language_server_names_to_stop.insert(name);
10579 None
10580 }
10581 })
10582 .collect::<BTreeSet<_>>();
10583
10584 let mut covered_worktrees = HashSet::default();
10585 for buffer in buffers {
10586 buffer.update(cx, |buffer, cx| {
10587 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10588 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10589 && covered_worktrees.insert(worktree_id)
10590 {
10591 language_server_names_to_stop.retain(|name| {
10592 let old_ids_count = language_servers_to_stop.len();
10593 let all_language_servers_with_this_name = local
10594 .language_server_ids
10595 .iter()
10596 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10597 language_servers_to_stop.extend(all_language_servers_with_this_name);
10598 old_ids_count == language_servers_to_stop.len()
10599 });
10600 }
10601 });
10602 }
10603 for name in language_server_names_to_stop {
10604 language_servers_to_stop.extend(
10605 local
10606 .language_server_ids
10607 .iter()
10608 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10609 );
10610 }
10611
10612 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10613 let tasks = language_servers_to_stop
10614 .into_iter()
10615 .map(|server| self.stop_local_language_server(server, cx))
10616 .collect::<Vec<_>>();
10617
10618 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10619 }
10620
10621 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10622 let (worktree, relative_path) =
10623 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10624
10625 let project_path = ProjectPath {
10626 worktree_id: worktree.read(cx).id(),
10627 path: relative_path.into(),
10628 };
10629
10630 Some(
10631 self.buffer_store()
10632 .read(cx)
10633 .get_by_path(&project_path)?
10634 .read(cx),
10635 )
10636 }
10637
10638 #[cfg(any(test, feature = "test-support"))]
10639 pub fn update_diagnostics(
10640 &mut self,
10641 server_id: LanguageServerId,
10642 diagnostics: lsp::PublishDiagnosticsParams,
10643 result_id: Option<String>,
10644 source_kind: DiagnosticSourceKind,
10645 disk_based_sources: &[String],
10646 cx: &mut Context<Self>,
10647 ) -> Result<()> {
10648 self.merge_lsp_diagnostics(
10649 source_kind,
10650 vec![DocumentDiagnosticsUpdate {
10651 diagnostics,
10652 result_id,
10653 server_id,
10654 disk_based_sources: Cow::Borrowed(disk_based_sources),
10655 }],
10656 |_, _, _| false,
10657 cx,
10658 )
10659 }
10660
10661 pub fn merge_lsp_diagnostics(
10662 &mut self,
10663 source_kind: DiagnosticSourceKind,
10664 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10665 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10666 cx: &mut Context<Self>,
10667 ) -> Result<()> {
10668 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10669 let updates = lsp_diagnostics
10670 .into_iter()
10671 .filter_map(|update| {
10672 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10673 Some(DocumentDiagnosticsUpdate {
10674 diagnostics: self.lsp_to_document_diagnostics(
10675 abs_path,
10676 source_kind,
10677 update.server_id,
10678 update.diagnostics,
10679 &update.disk_based_sources,
10680 ),
10681 result_id: update.result_id,
10682 server_id: update.server_id,
10683 disk_based_sources: update.disk_based_sources,
10684 })
10685 })
10686 .collect();
10687 self.merge_diagnostic_entries(updates, merge, cx)?;
10688 Ok(())
10689 }
10690
10691 fn lsp_to_document_diagnostics(
10692 &mut self,
10693 document_abs_path: PathBuf,
10694 source_kind: DiagnosticSourceKind,
10695 server_id: LanguageServerId,
10696 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10697 disk_based_sources: &[String],
10698 ) -> DocumentDiagnostics {
10699 let mut diagnostics = Vec::default();
10700 let mut primary_diagnostic_group_ids = HashMap::default();
10701 let mut sources_by_group_id = HashMap::default();
10702 let mut supporting_diagnostics = HashMap::default();
10703
10704 let adapter = self.language_server_adapter_for_id(server_id);
10705
10706 // Ensure that primary diagnostics are always the most severe
10707 lsp_diagnostics
10708 .diagnostics
10709 .sort_by_key(|item| item.severity);
10710
10711 for diagnostic in &lsp_diagnostics.diagnostics {
10712 let source = diagnostic.source.as_ref();
10713 let range = range_from_lsp(diagnostic.range);
10714 let is_supporting = diagnostic
10715 .related_information
10716 .as_ref()
10717 .is_some_and(|infos| {
10718 infos.iter().any(|info| {
10719 primary_diagnostic_group_ids.contains_key(&(
10720 source,
10721 diagnostic.code.clone(),
10722 range_from_lsp(info.location.range),
10723 ))
10724 })
10725 });
10726
10727 let is_unnecessary = diagnostic
10728 .tags
10729 .as_ref()
10730 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10731
10732 let underline = self
10733 .language_server_adapter_for_id(server_id)
10734 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10735
10736 if is_supporting {
10737 supporting_diagnostics.insert(
10738 (source, diagnostic.code.clone(), range),
10739 (diagnostic.severity, is_unnecessary),
10740 );
10741 } else {
10742 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10743 let is_disk_based =
10744 source.is_some_and(|source| disk_based_sources.contains(source));
10745
10746 sources_by_group_id.insert(group_id, source);
10747 primary_diagnostic_group_ids
10748 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10749
10750 diagnostics.push(DiagnosticEntry {
10751 range,
10752 diagnostic: Diagnostic {
10753 source: diagnostic.source.clone(),
10754 source_kind,
10755 code: diagnostic.code.clone(),
10756 code_description: diagnostic
10757 .code_description
10758 .as_ref()
10759 .and_then(|d| d.href.clone()),
10760 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10761 markdown: adapter.as_ref().and_then(|adapter| {
10762 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10763 }),
10764 message: diagnostic.message.trim().to_string(),
10765 group_id,
10766 is_primary: true,
10767 is_disk_based,
10768 is_unnecessary,
10769 underline,
10770 data: diagnostic.data.clone(),
10771 },
10772 });
10773 if let Some(infos) = &diagnostic.related_information {
10774 for info in infos {
10775 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10776 let range = range_from_lsp(info.location.range);
10777 diagnostics.push(DiagnosticEntry {
10778 range,
10779 diagnostic: Diagnostic {
10780 source: diagnostic.source.clone(),
10781 source_kind,
10782 code: diagnostic.code.clone(),
10783 code_description: diagnostic
10784 .code_description
10785 .as_ref()
10786 .and_then(|d| d.href.clone()),
10787 severity: DiagnosticSeverity::INFORMATION,
10788 markdown: adapter.as_ref().and_then(|adapter| {
10789 adapter.diagnostic_message_to_markdown(&info.message)
10790 }),
10791 message: info.message.trim().to_string(),
10792 group_id,
10793 is_primary: false,
10794 is_disk_based,
10795 is_unnecessary: false,
10796 underline,
10797 data: diagnostic.data.clone(),
10798 },
10799 });
10800 }
10801 }
10802 }
10803 }
10804 }
10805
10806 for entry in &mut diagnostics {
10807 let diagnostic = &mut entry.diagnostic;
10808 if !diagnostic.is_primary {
10809 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10810 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10811 source,
10812 diagnostic.code.clone(),
10813 entry.range.clone(),
10814 )) {
10815 if let Some(severity) = severity {
10816 diagnostic.severity = severity;
10817 }
10818 diagnostic.is_unnecessary = is_unnecessary;
10819 }
10820 }
10821 }
10822
10823 DocumentDiagnostics {
10824 diagnostics,
10825 document_abs_path,
10826 version: lsp_diagnostics.version,
10827 }
10828 }
10829
10830 fn insert_newly_running_language_server(
10831 &mut self,
10832 adapter: Arc<CachedLspAdapter>,
10833 language_server: Arc<LanguageServer>,
10834 server_id: LanguageServerId,
10835 key: LanguageServerSeed,
10836 workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
10837 cx: &mut Context<Self>,
10838 ) {
10839 let Some(local) = self.as_local_mut() else {
10840 return;
10841 };
10842 // If the language server for this key doesn't match the server id, don't store the
10843 // server. Which will cause it to be dropped, killing the process
10844 if local
10845 .language_server_ids
10846 .get(&key)
10847 .map(|state| state.id != server_id)
10848 .unwrap_or(false)
10849 {
10850 return;
10851 }
10852
10853 // Update language_servers collection with Running variant of LanguageServerState
10854 // indicating that the server is up and running and ready
10855 let workspace_folders = workspace_folders.lock().clone();
10856 language_server.set_workspace_folders(workspace_folders);
10857
10858 local.language_servers.insert(
10859 server_id,
10860 LanguageServerState::Running {
10861 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
10862 language_server.clone(),
10863 cx,
10864 ),
10865 adapter: adapter.clone(),
10866 server: language_server.clone(),
10867 simulate_disk_based_diagnostics_completion: None,
10868 },
10869 );
10870 local
10871 .languages
10872 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10873 if let Some(file_ops_caps) = language_server
10874 .capabilities()
10875 .workspace
10876 .as_ref()
10877 .and_then(|ws| ws.file_operations.as_ref())
10878 {
10879 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10880 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10881 if did_rename_caps.or(will_rename_caps).is_some() {
10882 let watcher = RenamePathsWatchedForServer::default()
10883 .with_did_rename_patterns(did_rename_caps)
10884 .with_will_rename_patterns(will_rename_caps);
10885 local
10886 .language_server_paths_watched_for_rename
10887 .insert(server_id, watcher);
10888 }
10889 }
10890
10891 self.language_server_statuses.insert(
10892 server_id,
10893 LanguageServerStatus {
10894 name: language_server.name(),
10895 pending_work: Default::default(),
10896 has_pending_diagnostic_updates: false,
10897 progress_tokens: Default::default(),
10898 },
10899 );
10900
10901 cx.emit(LspStoreEvent::LanguageServerAdded(
10902 server_id,
10903 language_server.name(),
10904 Some(key.worktree_id),
10905 ));
10906 cx.emit(LspStoreEvent::RefreshInlayHints);
10907
10908 let server_capabilities = language_server.capabilities();
10909 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10910 downstream_client
10911 .send(proto::StartLanguageServer {
10912 project_id: *project_id,
10913 server: Some(proto::LanguageServer {
10914 id: server_id.to_proto(),
10915 name: language_server.name().to_string(),
10916 worktree_id: Some(key.worktree_id.to_proto()),
10917 }),
10918 capabilities: serde_json::to_string(&server_capabilities)
10919 .expect("serializing server LSP capabilities"),
10920 })
10921 .log_err();
10922 }
10923 self.lsp_server_capabilities
10924 .insert(server_id, server_capabilities);
10925
10926 // Tell the language server about every open buffer in the worktree that matches the language.
10927 // Also check for buffers in worktrees that reused this server
10928 let mut worktrees_using_server = vec![key.worktree_id];
10929 if let Some(local) = self.as_local() {
10930 // Find all worktrees that have this server in their language server tree
10931 for (worktree_id, servers) in &local.lsp_tree.instances {
10932 if *worktree_id != key.worktree_id {
10933 for server_map in servers.roots.values() {
10934 if server_map.contains_key(&key.name) {
10935 worktrees_using_server.push(*worktree_id);
10936 }
10937 }
10938 }
10939 }
10940 }
10941
10942 let mut buffer_paths_registered = Vec::new();
10943 self.buffer_store.clone().update(cx, |buffer_store, cx| {
10944 for buffer_handle in buffer_store.buffers() {
10945 let buffer = buffer_handle.read(cx);
10946 let file = match File::from_dyn(buffer.file()) {
10947 Some(file) => file,
10948 None => continue,
10949 };
10950 let language = match buffer.language() {
10951 Some(language) => language,
10952 None => continue,
10953 };
10954
10955 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
10956 || !self
10957 .languages
10958 .lsp_adapters(&language.name())
10959 .iter()
10960 .any(|a| a.name == key.name)
10961 {
10962 continue;
10963 }
10964 // didOpen
10965 let file = match file.as_local() {
10966 Some(file) => file,
10967 None => continue,
10968 };
10969
10970 let local = self.as_local_mut().unwrap();
10971
10972 let buffer_id = buffer.remote_id();
10973 if local.registered_buffers.contains_key(&buffer_id) {
10974 let versions = local
10975 .buffer_snapshots
10976 .entry(buffer_id)
10977 .or_default()
10978 .entry(server_id)
10979 .and_modify(|_| {
10980 assert!(
10981 false,
10982 "There should not be an existing snapshot for a newly inserted buffer"
10983 )
10984 })
10985 .or_insert_with(|| {
10986 vec![LspBufferSnapshot {
10987 version: 0,
10988 snapshot: buffer.text_snapshot(),
10989 }]
10990 });
10991
10992 let snapshot = versions.last().unwrap();
10993 let version = snapshot.version;
10994 let initial_snapshot = &snapshot.snapshot;
10995 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
10996 language_server.register_buffer(
10997 uri,
10998 adapter.language_id(&language.name()),
10999 version,
11000 initial_snapshot.text(),
11001 );
11002 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11003 local
11004 .buffers_opened_in_servers
11005 .entry(buffer_id)
11006 .or_default()
11007 .insert(server_id);
11008 }
11009 buffer_handle.update(cx, |buffer, cx| {
11010 buffer.set_completion_triggers(
11011 server_id,
11012 language_server
11013 .capabilities()
11014 .completion_provider
11015 .as_ref()
11016 .and_then(|provider| {
11017 provider
11018 .trigger_characters
11019 .as_ref()
11020 .map(|characters| characters.iter().cloned().collect())
11021 })
11022 .unwrap_or_default(),
11023 cx,
11024 )
11025 });
11026 }
11027 });
11028
11029 for (buffer_id, abs_path) in buffer_paths_registered {
11030 cx.emit(LspStoreEvent::LanguageServerUpdate {
11031 language_server_id: server_id,
11032 name: Some(adapter.name()),
11033 message: proto::update_language_server::Variant::RegisteredForBuffer(
11034 proto::RegisteredForBuffer {
11035 buffer_abs_path: abs_path.to_string_lossy().to_string(),
11036 buffer_id: buffer_id.to_proto(),
11037 },
11038 ),
11039 });
11040 }
11041
11042 cx.notify();
11043 }
11044
11045 pub fn language_servers_running_disk_based_diagnostics(
11046 &self,
11047 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11048 self.language_server_statuses
11049 .iter()
11050 .filter_map(|(id, status)| {
11051 if status.has_pending_diagnostic_updates {
11052 Some(*id)
11053 } else {
11054 None
11055 }
11056 })
11057 }
11058
11059 pub(crate) fn cancel_language_server_work_for_buffers(
11060 &mut self,
11061 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11062 cx: &mut Context<Self>,
11063 ) {
11064 if let Some((client, project_id)) = self.upstream_client() {
11065 let request = client.request(proto::CancelLanguageServerWork {
11066 project_id,
11067 work: Some(proto::cancel_language_server_work::Work::Buffers(
11068 proto::cancel_language_server_work::Buffers {
11069 buffer_ids: buffers
11070 .into_iter()
11071 .map(|b| b.read(cx).remote_id().to_proto())
11072 .collect(),
11073 },
11074 )),
11075 });
11076 cx.background_spawn(request).detach_and_log_err(cx);
11077 } else if let Some(local) = self.as_local() {
11078 let servers = buffers
11079 .into_iter()
11080 .flat_map(|buffer| {
11081 buffer.update(cx, |buffer, cx| {
11082 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11083 })
11084 })
11085 .collect::<HashSet<_>>();
11086 for server_id in servers {
11087 self.cancel_language_server_work(server_id, None, cx);
11088 }
11089 }
11090 }
11091
11092 pub(crate) fn cancel_language_server_work(
11093 &mut self,
11094 server_id: LanguageServerId,
11095 token_to_cancel: Option<String>,
11096 cx: &mut Context<Self>,
11097 ) {
11098 if let Some(local) = self.as_local() {
11099 let status = self.language_server_statuses.get(&server_id);
11100 let server = local.language_servers.get(&server_id);
11101 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11102 {
11103 for (token, progress) in &status.pending_work {
11104 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11105 && token != token_to_cancel
11106 {
11107 continue;
11108 }
11109 if progress.is_cancellable {
11110 server
11111 .notify::<lsp::notification::WorkDoneProgressCancel>(
11112 &WorkDoneProgressCancelParams {
11113 token: lsp::NumberOrString::String(token.clone()),
11114 },
11115 )
11116 .ok();
11117 }
11118 }
11119 }
11120 } else if let Some((client, project_id)) = self.upstream_client() {
11121 let request = client.request(proto::CancelLanguageServerWork {
11122 project_id,
11123 work: Some(
11124 proto::cancel_language_server_work::Work::LanguageServerWork(
11125 proto::cancel_language_server_work::LanguageServerWork {
11126 language_server_id: server_id.to_proto(),
11127 token: token_to_cancel,
11128 },
11129 ),
11130 ),
11131 });
11132 cx.background_spawn(request).detach_and_log_err(cx);
11133 }
11134 }
11135
11136 fn register_supplementary_language_server(
11137 &mut self,
11138 id: LanguageServerId,
11139 name: LanguageServerName,
11140 server: Arc<LanguageServer>,
11141 cx: &mut Context<Self>,
11142 ) {
11143 if let Some(local) = self.as_local_mut() {
11144 local
11145 .supplementary_language_servers
11146 .insert(id, (name.clone(), server));
11147 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11148 }
11149 }
11150
11151 fn unregister_supplementary_language_server(
11152 &mut self,
11153 id: LanguageServerId,
11154 cx: &mut Context<Self>,
11155 ) {
11156 if let Some(local) = self.as_local_mut() {
11157 local.supplementary_language_servers.remove(&id);
11158 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11159 }
11160 }
11161
11162 pub(crate) fn supplementary_language_servers(
11163 &self,
11164 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11165 self.as_local().into_iter().flat_map(|local| {
11166 local
11167 .supplementary_language_servers
11168 .iter()
11169 .map(|(id, (name, _))| (*id, name.clone()))
11170 })
11171 }
11172
11173 pub fn language_server_adapter_for_id(
11174 &self,
11175 id: LanguageServerId,
11176 ) -> Option<Arc<CachedLspAdapter>> {
11177 self.as_local()
11178 .and_then(|local| local.language_servers.get(&id))
11179 .and_then(|language_server_state| match language_server_state {
11180 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11181 _ => None,
11182 })
11183 }
11184
11185 pub(super) fn update_local_worktree_language_servers(
11186 &mut self,
11187 worktree_handle: &Entity<Worktree>,
11188 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
11189 cx: &mut Context<Self>,
11190 ) {
11191 if changes.is_empty() {
11192 return;
11193 }
11194
11195 let Some(local) = self.as_local() else { return };
11196
11197 local.prettier_store.update(cx, |prettier_store, cx| {
11198 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11199 });
11200
11201 let worktree_id = worktree_handle.read(cx).id();
11202 let mut language_server_ids = local
11203 .language_server_ids
11204 .iter()
11205 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11206 .collect::<Vec<_>>();
11207 language_server_ids.sort();
11208 language_server_ids.dedup();
11209
11210 let abs_path = worktree_handle.read(cx).abs_path();
11211 for server_id in &language_server_ids {
11212 if let Some(LanguageServerState::Running { server, .. }) =
11213 local.language_servers.get(server_id)
11214 && let Some(watched_paths) = local
11215 .language_server_watched_paths
11216 .get(server_id)
11217 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11218 {
11219 let params = lsp::DidChangeWatchedFilesParams {
11220 changes: changes
11221 .iter()
11222 .filter_map(|(path, _, change)| {
11223 if !watched_paths.is_match(path) {
11224 return None;
11225 }
11226 let typ = match change {
11227 PathChange::Loaded => return None,
11228 PathChange::Added => lsp::FileChangeType::CREATED,
11229 PathChange::Removed => lsp::FileChangeType::DELETED,
11230 PathChange::Updated => lsp::FileChangeType::CHANGED,
11231 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11232 };
11233 Some(lsp::FileEvent {
11234 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
11235 typ,
11236 })
11237 })
11238 .collect(),
11239 };
11240 if !params.changes.is_empty() {
11241 server
11242 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
11243 .ok();
11244 }
11245 }
11246 }
11247 for (path, _, _) in changes {
11248 if let Some(file_name) = path.file_name().and_then(|file_name| file_name.to_str())
11249 && local.watched_manifest_filenames.contains(file_name)
11250 {
11251 self.request_workspace_config_refresh();
11252 break;
11253 }
11254 }
11255 }
11256
11257 pub fn wait_for_remote_buffer(
11258 &mut self,
11259 id: BufferId,
11260 cx: &mut Context<Self>,
11261 ) -> Task<Result<Entity<Buffer>>> {
11262 self.buffer_store.update(cx, |buffer_store, cx| {
11263 buffer_store.wait_for_remote_buffer(id, cx)
11264 })
11265 }
11266
11267 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11268 proto::Symbol {
11269 language_server_name: symbol.language_server_name.0.to_string(),
11270 source_worktree_id: symbol.source_worktree_id.to_proto(),
11271 language_server_id: symbol.source_language_server_id.to_proto(),
11272 worktree_id: symbol.path.worktree_id.to_proto(),
11273 path: symbol.path.path.as_ref().to_proto(),
11274 name: symbol.name.clone(),
11275 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11276 start: Some(proto::PointUtf16 {
11277 row: symbol.range.start.0.row,
11278 column: symbol.range.start.0.column,
11279 }),
11280 end: Some(proto::PointUtf16 {
11281 row: symbol.range.end.0.row,
11282 column: symbol.range.end.0.column,
11283 }),
11284 signature: symbol.signature.to_vec(),
11285 }
11286 }
11287
11288 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11289 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11290 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11291 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11292 let path = ProjectPath {
11293 worktree_id,
11294 path: Arc::<Path>::from_proto(serialized_symbol.path),
11295 };
11296
11297 let start = serialized_symbol.start.context("invalid start")?;
11298 let end = serialized_symbol.end.context("invalid end")?;
11299 Ok(CoreSymbol {
11300 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11301 source_worktree_id,
11302 source_language_server_id: LanguageServerId::from_proto(
11303 serialized_symbol.language_server_id,
11304 ),
11305 path,
11306 name: serialized_symbol.name,
11307 range: Unclipped(PointUtf16::new(start.row, start.column))
11308 ..Unclipped(PointUtf16::new(end.row, end.column)),
11309 kind,
11310 signature: serialized_symbol
11311 .signature
11312 .try_into()
11313 .map_err(|_| anyhow!("invalid signature"))?,
11314 })
11315 }
11316
11317 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11318 let mut serialized_completion = proto::Completion {
11319 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11320 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11321 new_text: completion.new_text.clone(),
11322 ..proto::Completion::default()
11323 };
11324 match &completion.source {
11325 CompletionSource::Lsp {
11326 insert_range,
11327 server_id,
11328 lsp_completion,
11329 lsp_defaults,
11330 resolved,
11331 } => {
11332 let (old_insert_start, old_insert_end) = insert_range
11333 .as_ref()
11334 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11335 .unzip();
11336
11337 serialized_completion.old_insert_start = old_insert_start;
11338 serialized_completion.old_insert_end = old_insert_end;
11339 serialized_completion.source = proto::completion::Source::Lsp as i32;
11340 serialized_completion.server_id = server_id.0 as u64;
11341 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11342 serialized_completion.lsp_defaults = lsp_defaults
11343 .as_deref()
11344 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11345 serialized_completion.resolved = *resolved;
11346 }
11347 CompletionSource::BufferWord {
11348 word_range,
11349 resolved,
11350 } => {
11351 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11352 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11353 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11354 serialized_completion.resolved = *resolved;
11355 }
11356 CompletionSource::Custom => {
11357 serialized_completion.source = proto::completion::Source::Custom as i32;
11358 serialized_completion.resolved = true;
11359 }
11360 CompletionSource::Dap { sort_text } => {
11361 serialized_completion.source = proto::completion::Source::Dap as i32;
11362 serialized_completion.sort_text = Some(sort_text.clone());
11363 }
11364 }
11365
11366 serialized_completion
11367 }
11368
11369 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11370 let old_replace_start = completion
11371 .old_replace_start
11372 .and_then(deserialize_anchor)
11373 .context("invalid old start")?;
11374 let old_replace_end = completion
11375 .old_replace_end
11376 .and_then(deserialize_anchor)
11377 .context("invalid old end")?;
11378 let insert_range = {
11379 match completion.old_insert_start.zip(completion.old_insert_end) {
11380 Some((start, end)) => {
11381 let start = deserialize_anchor(start).context("invalid insert old start")?;
11382 let end = deserialize_anchor(end).context("invalid insert old end")?;
11383 Some(start..end)
11384 }
11385 None => None,
11386 }
11387 };
11388 Ok(CoreCompletion {
11389 replace_range: old_replace_start..old_replace_end,
11390 new_text: completion.new_text,
11391 source: match proto::completion::Source::from_i32(completion.source) {
11392 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11393 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11394 insert_range,
11395 server_id: LanguageServerId::from_proto(completion.server_id),
11396 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11397 lsp_defaults: completion
11398 .lsp_defaults
11399 .as_deref()
11400 .map(serde_json::from_slice)
11401 .transpose()?,
11402 resolved: completion.resolved,
11403 },
11404 Some(proto::completion::Source::BufferWord) => {
11405 let word_range = completion
11406 .buffer_word_start
11407 .and_then(deserialize_anchor)
11408 .context("invalid buffer word start")?
11409 ..completion
11410 .buffer_word_end
11411 .and_then(deserialize_anchor)
11412 .context("invalid buffer word end")?;
11413 CompletionSource::BufferWord {
11414 word_range,
11415 resolved: completion.resolved,
11416 }
11417 }
11418 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11419 sort_text: completion
11420 .sort_text
11421 .context("expected sort text to exist")?,
11422 },
11423 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11424 },
11425 })
11426 }
11427
11428 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11429 let (kind, lsp_action) = match &action.lsp_action {
11430 LspAction::Action(code_action) => (
11431 proto::code_action::Kind::Action as i32,
11432 serde_json::to_vec(code_action).unwrap(),
11433 ),
11434 LspAction::Command(command) => (
11435 proto::code_action::Kind::Command as i32,
11436 serde_json::to_vec(command).unwrap(),
11437 ),
11438 LspAction::CodeLens(code_lens) => (
11439 proto::code_action::Kind::CodeLens as i32,
11440 serde_json::to_vec(code_lens).unwrap(),
11441 ),
11442 };
11443
11444 proto::CodeAction {
11445 server_id: action.server_id.0 as u64,
11446 start: Some(serialize_anchor(&action.range.start)),
11447 end: Some(serialize_anchor(&action.range.end)),
11448 lsp_action,
11449 kind,
11450 resolved: action.resolved,
11451 }
11452 }
11453
11454 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11455 let start = action
11456 .start
11457 .and_then(deserialize_anchor)
11458 .context("invalid start")?;
11459 let end = action
11460 .end
11461 .and_then(deserialize_anchor)
11462 .context("invalid end")?;
11463 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11464 Some(proto::code_action::Kind::Action) => {
11465 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11466 }
11467 Some(proto::code_action::Kind::Command) => {
11468 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11469 }
11470 Some(proto::code_action::Kind::CodeLens) => {
11471 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11472 }
11473 None => anyhow::bail!("Unknown action kind {}", action.kind),
11474 };
11475 Ok(CodeAction {
11476 server_id: LanguageServerId(action.server_id as usize),
11477 range: start..end,
11478 resolved: action.resolved,
11479 lsp_action,
11480 })
11481 }
11482
11483 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11484 match &formatting_result {
11485 Ok(_) => self.last_formatting_failure = None,
11486 Err(error) => {
11487 let error_string = format!("{error:#}");
11488 log::error!("Formatting failed: {error_string}");
11489 self.last_formatting_failure
11490 .replace(error_string.lines().join(" "));
11491 }
11492 }
11493 }
11494
11495 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11496 self.lsp_server_capabilities.remove(&for_server);
11497 for buffer_colors in self.lsp_document_colors.values_mut() {
11498 buffer_colors.colors.remove(&for_server);
11499 buffer_colors.cache_version += 1;
11500 }
11501 for buffer_lens in self.lsp_code_lens.values_mut() {
11502 buffer_lens.lens.remove(&for_server);
11503 }
11504 if let Some(local) = self.as_local_mut() {
11505 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11506 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11507 buffer_servers.remove(&for_server);
11508 }
11509 }
11510 }
11511
11512 pub fn result_id(
11513 &self,
11514 server_id: LanguageServerId,
11515 buffer_id: BufferId,
11516 cx: &App,
11517 ) -> Option<String> {
11518 let abs_path = self
11519 .buffer_store
11520 .read(cx)
11521 .get(buffer_id)
11522 .and_then(|b| File::from_dyn(b.read(cx).file()))
11523 .map(|f| f.abs_path(cx))?;
11524 self.as_local()?
11525 .buffer_pull_diagnostics_result_ids
11526 .get(&server_id)?
11527 .get(&abs_path)?
11528 .clone()
11529 }
11530
11531 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11532 let Some(local) = self.as_local() else {
11533 return HashMap::default();
11534 };
11535 local
11536 .buffer_pull_diagnostics_result_ids
11537 .get(&server_id)
11538 .into_iter()
11539 .flatten()
11540 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11541 .collect()
11542 }
11543
11544 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11545 if let Some(LanguageServerState::Running {
11546 workspace_refresh_task: Some(workspace_refresh_task),
11547 ..
11548 }) = self
11549 .as_local_mut()
11550 .and_then(|local| local.language_servers.get_mut(&server_id))
11551 {
11552 workspace_refresh_task.refresh_tx.try_send(()).ok();
11553 }
11554 }
11555
11556 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11557 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11558 return;
11559 };
11560 let Some(local) = self.as_local_mut() else {
11561 return;
11562 };
11563
11564 for server_id in buffer.update(cx, |buffer, cx| {
11565 local.language_server_ids_for_buffer(buffer, cx)
11566 }) {
11567 if let Some(LanguageServerState::Running {
11568 workspace_refresh_task: Some(workspace_refresh_task),
11569 ..
11570 }) = local.language_servers.get_mut(&server_id)
11571 {
11572 workspace_refresh_task.refresh_tx.try_send(()).ok();
11573 }
11574 }
11575 }
11576
11577 fn apply_workspace_diagnostic_report(
11578 &mut self,
11579 server_id: LanguageServerId,
11580 report: lsp::WorkspaceDiagnosticReportResult,
11581 cx: &mut Context<Self>,
11582 ) {
11583 let workspace_diagnostics =
11584 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11585 let mut unchanged_buffers = HashSet::default();
11586 let mut changed_buffers = HashSet::default();
11587 let workspace_diagnostics_updates = workspace_diagnostics
11588 .into_iter()
11589 .filter_map(
11590 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11591 LspPullDiagnostics::Response {
11592 server_id,
11593 uri,
11594 diagnostics,
11595 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11596 LspPullDiagnostics::Default => None,
11597 },
11598 )
11599 .fold(
11600 HashMap::default(),
11601 |mut acc, (server_id, uri, diagnostics, version)| {
11602 let (result_id, diagnostics) = match diagnostics {
11603 PulledDiagnostics::Unchanged { result_id } => {
11604 unchanged_buffers.insert(uri.clone());
11605 (Some(result_id), Vec::new())
11606 }
11607 PulledDiagnostics::Changed {
11608 result_id,
11609 diagnostics,
11610 } => {
11611 changed_buffers.insert(uri.clone());
11612 (result_id, diagnostics)
11613 }
11614 };
11615 let disk_based_sources = Cow::Owned(
11616 self.language_server_adapter_for_id(server_id)
11617 .as_ref()
11618 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11619 .unwrap_or(&[])
11620 .to_vec(),
11621 );
11622 acc.entry(server_id)
11623 .or_insert_with(Vec::new)
11624 .push(DocumentDiagnosticsUpdate {
11625 server_id,
11626 diagnostics: lsp::PublishDiagnosticsParams {
11627 uri,
11628 diagnostics,
11629 version,
11630 },
11631 result_id,
11632 disk_based_sources,
11633 });
11634 acc
11635 },
11636 );
11637
11638 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11639 self.merge_lsp_diagnostics(
11640 DiagnosticSourceKind::Pulled,
11641 diagnostic_updates,
11642 |buffer, old_diagnostic, cx| {
11643 File::from_dyn(buffer.file())
11644 .and_then(|file| {
11645 let abs_path = file.as_local()?.abs_path(cx);
11646 lsp::Url::from_file_path(abs_path).ok()
11647 })
11648 .is_none_or(|buffer_uri| {
11649 unchanged_buffers.contains(&buffer_uri)
11650 || match old_diagnostic.source_kind {
11651 DiagnosticSourceKind::Pulled => {
11652 !changed_buffers.contains(&buffer_uri)
11653 }
11654 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11655 true
11656 }
11657 }
11658 })
11659 },
11660 cx,
11661 )
11662 .log_err();
11663 }
11664 }
11665
11666 fn register_server_capabilities(
11667 &mut self,
11668 server_id: LanguageServerId,
11669 params: lsp::RegistrationParams,
11670 cx: &mut Context<Self>,
11671 ) -> anyhow::Result<()> {
11672 let server = self
11673 .language_server_for_id(server_id)
11674 .with_context(|| format!("no server {server_id} found"))?;
11675 for reg in params.registrations {
11676 match reg.method.as_str() {
11677 "workspace/didChangeWatchedFiles" => {
11678 if let Some(options) = reg.register_options {
11679 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11680 let caps = serde_json::from_value(options)?;
11681 local_lsp_store
11682 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11683 true
11684 } else {
11685 false
11686 };
11687 if notify {
11688 notify_server_capabilities_updated(&server, cx);
11689 }
11690 }
11691 }
11692 "workspace/didChangeConfiguration" => {
11693 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11694 }
11695 "workspace/symbol" => {
11696 if let Some(options) = parse_register_capabilities(reg)? {
11697 server.update_capabilities(|capabilities| {
11698 capabilities.workspace_symbol_provider = Some(options);
11699 });
11700 notify_server_capabilities_updated(&server, cx);
11701 }
11702 }
11703 "workspace/fileOperations" => {
11704 if let Some(options) = reg.register_options {
11705 let caps = serde_json::from_value(options)?;
11706 server.update_capabilities(|capabilities| {
11707 capabilities
11708 .workspace
11709 .get_or_insert_default()
11710 .file_operations = Some(caps);
11711 });
11712 notify_server_capabilities_updated(&server, cx);
11713 }
11714 }
11715 "workspace/executeCommand" => {
11716 if let Some(options) = reg.register_options {
11717 let options = serde_json::from_value(options)?;
11718 server.update_capabilities(|capabilities| {
11719 capabilities.execute_command_provider = Some(options);
11720 });
11721 notify_server_capabilities_updated(&server, cx);
11722 }
11723 }
11724 "textDocument/rangeFormatting" => {
11725 if let Some(options) = parse_register_capabilities(reg)? {
11726 server.update_capabilities(|capabilities| {
11727 capabilities.document_range_formatting_provider = Some(options);
11728 });
11729 notify_server_capabilities_updated(&server, cx);
11730 }
11731 }
11732 "textDocument/onTypeFormatting" => {
11733 if let Some(options) = reg
11734 .register_options
11735 .map(serde_json::from_value)
11736 .transpose()?
11737 {
11738 server.update_capabilities(|capabilities| {
11739 capabilities.document_on_type_formatting_provider = Some(options);
11740 });
11741 notify_server_capabilities_updated(&server, cx);
11742 }
11743 }
11744 "textDocument/formatting" => {
11745 if let Some(options) = parse_register_capabilities(reg)? {
11746 server.update_capabilities(|capabilities| {
11747 capabilities.document_formatting_provider = Some(options);
11748 });
11749 notify_server_capabilities_updated(&server, cx);
11750 }
11751 }
11752 "textDocument/rename" => {
11753 if let Some(options) = parse_register_capabilities(reg)? {
11754 server.update_capabilities(|capabilities| {
11755 capabilities.rename_provider = Some(options);
11756 });
11757 notify_server_capabilities_updated(&server, cx);
11758 }
11759 }
11760 "textDocument/inlayHint" => {
11761 if let Some(options) = parse_register_capabilities(reg)? {
11762 server.update_capabilities(|capabilities| {
11763 capabilities.inlay_hint_provider = Some(options);
11764 });
11765 notify_server_capabilities_updated(&server, cx);
11766 }
11767 }
11768 "textDocument/documentSymbol" => {
11769 if let Some(options) = parse_register_capabilities(reg)? {
11770 server.update_capabilities(|capabilities| {
11771 capabilities.document_symbol_provider = Some(options);
11772 });
11773 notify_server_capabilities_updated(&server, cx);
11774 }
11775 }
11776 "textDocument/codeAction" => {
11777 if let Some(options) = reg
11778 .register_options
11779 .map(serde_json::from_value)
11780 .transpose()?
11781 {
11782 server.update_capabilities(|capabilities| {
11783 capabilities.code_action_provider =
11784 Some(lsp::CodeActionProviderCapability::Options(options));
11785 });
11786 notify_server_capabilities_updated(&server, cx);
11787 }
11788 }
11789 "textDocument/definition" => {
11790 if let Some(options) = parse_register_capabilities(reg)? {
11791 server.update_capabilities(|capabilities| {
11792 capabilities.definition_provider = Some(options);
11793 });
11794 notify_server_capabilities_updated(&server, cx);
11795 }
11796 }
11797 "textDocument/completion" => {
11798 if let Some(caps) = reg
11799 .register_options
11800 .map(serde_json::from_value)
11801 .transpose()?
11802 {
11803 server.update_capabilities(|capabilities| {
11804 capabilities.completion_provider = Some(caps);
11805 });
11806 notify_server_capabilities_updated(&server, cx);
11807 }
11808 }
11809 "textDocument/hover" => {
11810 if let Some(caps) = reg
11811 .register_options
11812 .map(serde_json::from_value)
11813 .transpose()?
11814 {
11815 server.update_capabilities(|capabilities| {
11816 capabilities.hover_provider = Some(caps);
11817 });
11818 notify_server_capabilities_updated(&server, cx);
11819 }
11820 }
11821 "textDocument/signatureHelp" => {
11822 if let Some(caps) = reg
11823 .register_options
11824 .map(serde_json::from_value)
11825 .transpose()?
11826 {
11827 server.update_capabilities(|capabilities| {
11828 capabilities.signature_help_provider = Some(caps);
11829 });
11830 notify_server_capabilities_updated(&server, cx);
11831 }
11832 }
11833 "textDocument/didChange" => {
11834 if let Some(sync_kind) = reg
11835 .register_options
11836 .and_then(|opts| opts.get("syncKind").cloned())
11837 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11838 .transpose()?
11839 {
11840 server.update_capabilities(|capabilities| {
11841 let mut sync_options =
11842 Self::take_text_document_sync_options(capabilities);
11843 sync_options.change = Some(sync_kind);
11844 capabilities.text_document_sync =
11845 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11846 });
11847 notify_server_capabilities_updated(&server, cx);
11848 }
11849 }
11850 "textDocument/didSave" => {
11851 if let Some(include_text) = reg
11852 .register_options
11853 .map(|opts| {
11854 let transpose = opts
11855 .get("includeText")
11856 .cloned()
11857 .map(serde_json::from_value::<Option<bool>>)
11858 .transpose();
11859 match transpose {
11860 Ok(value) => Ok(value.flatten()),
11861 Err(e) => Err(e),
11862 }
11863 })
11864 .transpose()?
11865 {
11866 server.update_capabilities(|capabilities| {
11867 let mut sync_options =
11868 Self::take_text_document_sync_options(capabilities);
11869 sync_options.save =
11870 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11871 include_text,
11872 }));
11873 capabilities.text_document_sync =
11874 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11875 });
11876 notify_server_capabilities_updated(&server, cx);
11877 }
11878 }
11879 "textDocument/codeLens" => {
11880 if let Some(caps) = reg
11881 .register_options
11882 .map(serde_json::from_value)
11883 .transpose()?
11884 {
11885 server.update_capabilities(|capabilities| {
11886 capabilities.code_lens_provider = Some(caps);
11887 });
11888 notify_server_capabilities_updated(&server, cx);
11889 }
11890 }
11891 "textDocument/diagnostic" => {
11892 if let Some(caps) = reg
11893 .register_options
11894 .map(serde_json::from_value)
11895 .transpose()?
11896 {
11897 server.update_capabilities(|capabilities| {
11898 capabilities.diagnostic_provider = Some(caps);
11899 });
11900 notify_server_capabilities_updated(&server, cx);
11901 }
11902 }
11903 "textDocument/colorProvider" => {
11904 if let Some(caps) = reg
11905 .register_options
11906 .map(serde_json::from_value)
11907 .transpose()?
11908 {
11909 server.update_capabilities(|capabilities| {
11910 capabilities.color_provider = Some(caps);
11911 });
11912 notify_server_capabilities_updated(&server, cx);
11913 }
11914 }
11915 _ => log::warn!("unhandled capability registration: {reg:?}"),
11916 }
11917 }
11918
11919 Ok(())
11920 }
11921
11922 fn unregister_server_capabilities(
11923 &mut self,
11924 server_id: LanguageServerId,
11925 params: lsp::UnregistrationParams,
11926 cx: &mut Context<Self>,
11927 ) -> anyhow::Result<()> {
11928 let server = self
11929 .language_server_for_id(server_id)
11930 .with_context(|| format!("no server {server_id} found"))?;
11931 for unreg in params.unregisterations.iter() {
11932 match unreg.method.as_str() {
11933 "workspace/didChangeWatchedFiles" => {
11934 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11935 local_lsp_store
11936 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
11937 true
11938 } else {
11939 false
11940 };
11941 if notify {
11942 notify_server_capabilities_updated(&server, cx);
11943 }
11944 }
11945 "workspace/didChangeConfiguration" => {
11946 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11947 }
11948 "workspace/symbol" => {
11949 server.update_capabilities(|capabilities| {
11950 capabilities.workspace_symbol_provider = None
11951 });
11952 notify_server_capabilities_updated(&server, cx);
11953 }
11954 "workspace/fileOperations" => {
11955 server.update_capabilities(|capabilities| {
11956 capabilities
11957 .workspace
11958 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
11959 workspace_folders: None,
11960 file_operations: None,
11961 })
11962 .file_operations = None;
11963 });
11964 notify_server_capabilities_updated(&server, cx);
11965 }
11966 "workspace/executeCommand" => {
11967 server.update_capabilities(|capabilities| {
11968 capabilities.execute_command_provider = None;
11969 });
11970 notify_server_capabilities_updated(&server, cx);
11971 }
11972 "textDocument/rangeFormatting" => {
11973 server.update_capabilities(|capabilities| {
11974 capabilities.document_range_formatting_provider = None
11975 });
11976 notify_server_capabilities_updated(&server, cx);
11977 }
11978 "textDocument/onTypeFormatting" => {
11979 server.update_capabilities(|capabilities| {
11980 capabilities.document_on_type_formatting_provider = None;
11981 });
11982 notify_server_capabilities_updated(&server, cx);
11983 }
11984 "textDocument/formatting" => {
11985 server.update_capabilities(|capabilities| {
11986 capabilities.document_formatting_provider = None;
11987 });
11988 notify_server_capabilities_updated(&server, cx);
11989 }
11990 "textDocument/rename" => {
11991 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
11992 notify_server_capabilities_updated(&server, cx);
11993 }
11994 "textDocument/codeAction" => {
11995 server.update_capabilities(|capabilities| {
11996 capabilities.code_action_provider = None;
11997 });
11998 notify_server_capabilities_updated(&server, cx);
11999 }
12000 "textDocument/definition" => {
12001 server.update_capabilities(|capabilities| {
12002 capabilities.definition_provider = None;
12003 });
12004 notify_server_capabilities_updated(&server, cx);
12005 }
12006 "textDocument/completion" => {
12007 server.update_capabilities(|capabilities| {
12008 capabilities.completion_provider = None;
12009 });
12010 notify_server_capabilities_updated(&server, cx);
12011 }
12012 "textDocument/hover" => {
12013 server.update_capabilities(|capabilities| {
12014 capabilities.hover_provider = None;
12015 });
12016 notify_server_capabilities_updated(&server, cx);
12017 }
12018 "textDocument/signatureHelp" => {
12019 server.update_capabilities(|capabilities| {
12020 capabilities.signature_help_provider = None;
12021 });
12022 notify_server_capabilities_updated(&server, cx);
12023 }
12024 "textDocument/didChange" => {
12025 server.update_capabilities(|capabilities| {
12026 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12027 sync_options.change = None;
12028 capabilities.text_document_sync =
12029 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12030 });
12031 notify_server_capabilities_updated(&server, cx);
12032 }
12033 "textDocument/didSave" => {
12034 server.update_capabilities(|capabilities| {
12035 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12036 sync_options.save = None;
12037 capabilities.text_document_sync =
12038 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12039 });
12040 notify_server_capabilities_updated(&server, cx);
12041 }
12042 "textDocument/codeLens" => {
12043 server.update_capabilities(|capabilities| {
12044 capabilities.code_lens_provider = None;
12045 });
12046 notify_server_capabilities_updated(&server, cx);
12047 }
12048 "textDocument/diagnostic" => {
12049 server.update_capabilities(|capabilities| {
12050 capabilities.diagnostic_provider = None;
12051 });
12052 notify_server_capabilities_updated(&server, cx);
12053 }
12054 "textDocument/colorProvider" => {
12055 server.update_capabilities(|capabilities| {
12056 capabilities.color_provider = None;
12057 });
12058 notify_server_capabilities_updated(&server, cx);
12059 }
12060 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12061 }
12062 }
12063
12064 Ok(())
12065 }
12066
12067 async fn query_lsp_locally<T>(
12068 lsp_store: Entity<Self>,
12069 sender_id: proto::PeerId,
12070 lsp_request_id: LspRequestId,
12071 proto_request: T::ProtoRequest,
12072 position: Option<Anchor>,
12073 mut cx: AsyncApp,
12074 ) -> Result<()>
12075 where
12076 T: LspCommand + Clone,
12077 T::ProtoRequest: proto::LspRequestMessage,
12078 <T::ProtoRequest as proto::RequestMessage>::Response:
12079 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12080 {
12081 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12082 let version = deserialize_version(proto_request.buffer_version());
12083 let buffer = lsp_store.update(&mut cx, |this, cx| {
12084 this.buffer_store.read(cx).get_existing(buffer_id)
12085 })??;
12086 buffer
12087 .update(&mut cx, |buffer, _| {
12088 buffer.wait_for_version(version.clone())
12089 })?
12090 .await?;
12091 let buffer_version = buffer.read_with(&cx, |buffer, _| buffer.version())?;
12092 let request =
12093 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12094 lsp_store.update(&mut cx, |lsp_store, cx| {
12095 let request_task =
12096 lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx);
12097 let existing_queries = lsp_store
12098 .running_lsp_requests
12099 .entry(TypeId::of::<T>())
12100 .or_default();
12101 if T::ProtoRequest::stop_previous_requests()
12102 || buffer_version.changed_since(&existing_queries.0)
12103 {
12104 existing_queries.1.clear();
12105 }
12106 existing_queries.1.insert(
12107 lsp_request_id,
12108 cx.spawn(async move |lsp_store, cx| {
12109 let response = request_task.await;
12110 lsp_store
12111 .update(cx, |lsp_store, cx| {
12112 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12113 {
12114 let response = response
12115 .into_iter()
12116 .map(|(server_id, response)| {
12117 (
12118 server_id.to_proto(),
12119 T::response_to_proto(
12120 response,
12121 lsp_store,
12122 sender_id,
12123 &buffer_version,
12124 cx,
12125 )
12126 .into(),
12127 )
12128 })
12129 .collect::<HashMap<_, _>>();
12130 match client.send_lsp_response::<T::ProtoRequest>(
12131 project_id,
12132 lsp_request_id,
12133 response,
12134 ) {
12135 Ok(()) => {}
12136 Err(e) => {
12137 log::error!("Failed to send LSP response: {e:#}",)
12138 }
12139 }
12140 }
12141 })
12142 .ok();
12143 }),
12144 );
12145 })?;
12146 Ok(())
12147 }
12148
12149 fn take_text_document_sync_options(
12150 capabilities: &mut lsp::ServerCapabilities,
12151 ) -> lsp::TextDocumentSyncOptions {
12152 match capabilities.text_document_sync.take() {
12153 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12154 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12155 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12156 sync_options.change = Some(sync_kind);
12157 sync_options
12158 }
12159 None => lsp::TextDocumentSyncOptions::default(),
12160 }
12161 }
12162
12163 #[cfg(any(test, feature = "test-support"))]
12164 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12165 let data = self.lsp_code_lens.get_mut(&buffer_id)?;
12166 Some(data.update.take()?.1)
12167 }
12168}
12169
12170// Registration with registerOptions as null, should fallback to true.
12171// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12172fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12173 reg: lsp::Registration,
12174) -> anyhow::Result<Option<OneOf<bool, T>>> {
12175 Ok(match reg.register_options {
12176 Some(options) => Some(OneOf::Right(serde_json::from_value::<T>(options)?)),
12177 None => Some(OneOf::Left(true)),
12178 })
12179}
12180
12181fn subscribe_to_binary_statuses(
12182 languages: &Arc<LanguageRegistry>,
12183 cx: &mut Context<'_, LspStore>,
12184) -> Task<()> {
12185 let mut server_statuses = languages.language_server_binary_statuses();
12186 cx.spawn(async move |lsp_store, cx| {
12187 while let Some((server_name, binary_status)) = server_statuses.next().await {
12188 if lsp_store
12189 .update(cx, |_, cx| {
12190 let mut message = None;
12191 let binary_status = match binary_status {
12192 BinaryStatus::None => proto::ServerBinaryStatus::None,
12193 BinaryStatus::CheckingForUpdate => {
12194 proto::ServerBinaryStatus::CheckingForUpdate
12195 }
12196 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12197 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12198 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12199 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12200 BinaryStatus::Failed { error } => {
12201 message = Some(error);
12202 proto::ServerBinaryStatus::Failed
12203 }
12204 };
12205 cx.emit(LspStoreEvent::LanguageServerUpdate {
12206 // Binary updates are about the binary that might not have any language server id at that point.
12207 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12208 language_server_id: LanguageServerId(0),
12209 name: Some(server_name),
12210 message: proto::update_language_server::Variant::StatusUpdate(
12211 proto::StatusUpdate {
12212 message,
12213 status: Some(proto::status_update::Status::Binary(
12214 binary_status as i32,
12215 )),
12216 },
12217 ),
12218 });
12219 })
12220 .is_err()
12221 {
12222 break;
12223 }
12224 }
12225 })
12226}
12227
12228fn lsp_workspace_diagnostics_refresh(
12229 server: Arc<LanguageServer>,
12230 cx: &mut Context<'_, LspStore>,
12231) -> Option<WorkspaceRefreshTask> {
12232 let identifier = match server.capabilities().diagnostic_provider? {
12233 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12234 if !diagnostic_options.workspace_diagnostics {
12235 return None;
12236 }
12237 diagnostic_options.identifier
12238 }
12239 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12240 let diagnostic_options = registration_options.diagnostic_options;
12241 if !diagnostic_options.workspace_diagnostics {
12242 return None;
12243 }
12244 diagnostic_options.identifier
12245 }
12246 };
12247
12248 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12249 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12250 refresh_tx.try_send(()).ok();
12251
12252 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12253 let mut attempts = 0;
12254 let max_attempts = 50;
12255 let mut requests = 0;
12256
12257 loop {
12258 let Some(()) = refresh_rx.recv().await else {
12259 return;
12260 };
12261
12262 'request: loop {
12263 requests += 1;
12264 if attempts > max_attempts {
12265 log::error!(
12266 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12267 );
12268 return;
12269 }
12270 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12271 cx.background_executor()
12272 .timer(Duration::from_millis(backoff_millis))
12273 .await;
12274 attempts += 1;
12275
12276 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12277 lsp_store
12278 .all_result_ids(server.server_id())
12279 .into_iter()
12280 .filter_map(|(abs_path, result_id)| {
12281 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12282 Some(lsp::PreviousResultId {
12283 uri,
12284 value: result_id,
12285 })
12286 })
12287 .collect()
12288 }) else {
12289 return;
12290 };
12291
12292 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
12293
12294 progress_rx.try_recv().ok();
12295 let timer =
12296 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12297 let progress = pin!(progress_rx.recv().fuse());
12298 let response_result = server
12299 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12300 lsp::WorkspaceDiagnosticParams {
12301 previous_result_ids,
12302 identifier: identifier.clone(),
12303 work_done_progress_params: Default::default(),
12304 partial_result_params: lsp::PartialResultParams {
12305 partial_result_token: Some(lsp::ProgressToken::String(token)),
12306 },
12307 },
12308 select(timer, progress).then(|either| match either {
12309 Either::Left((message, ..)) => ready(message).left_future(),
12310 Either::Right(..) => pending::<String>().right_future(),
12311 }),
12312 )
12313 .await;
12314
12315 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12316 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12317 match response_result {
12318 ConnectionResult::Timeout => {
12319 log::error!("Timeout during workspace diagnostics pull");
12320 continue 'request;
12321 }
12322 ConnectionResult::ConnectionReset => {
12323 log::error!("Server closed a workspace diagnostics pull request");
12324 continue 'request;
12325 }
12326 ConnectionResult::Result(Err(e)) => {
12327 log::error!("Error during workspace diagnostics pull: {e:#}");
12328 break 'request;
12329 }
12330 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12331 attempts = 0;
12332 if lsp_store
12333 .update(cx, |lsp_store, cx| {
12334 lsp_store.apply_workspace_diagnostic_report(
12335 server.server_id(),
12336 pulled_diagnostics,
12337 cx,
12338 )
12339 })
12340 .is_err()
12341 {
12342 return;
12343 }
12344 break 'request;
12345 }
12346 }
12347 }
12348 }
12349 });
12350
12351 Some(WorkspaceRefreshTask {
12352 refresh_tx,
12353 progress_tx,
12354 task: workspace_query_language_server,
12355 })
12356}
12357
12358fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12359 let CompletionSource::BufferWord {
12360 word_range,
12361 resolved,
12362 } = &mut completion.source
12363 else {
12364 return;
12365 };
12366 if *resolved {
12367 return;
12368 }
12369
12370 if completion.new_text
12371 != snapshot
12372 .text_for_range(word_range.clone())
12373 .collect::<String>()
12374 {
12375 return;
12376 }
12377
12378 let mut offset = 0;
12379 for chunk in snapshot.chunks(word_range.clone(), true) {
12380 let end_offset = offset + chunk.text.len();
12381 if let Some(highlight_id) = chunk.syntax_highlight_id {
12382 completion
12383 .label
12384 .runs
12385 .push((offset..end_offset, highlight_id));
12386 }
12387 offset = end_offset;
12388 }
12389 *resolved = true;
12390}
12391
12392impl EventEmitter<LspStoreEvent> for LspStore {}
12393
12394fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12395 hover
12396 .contents
12397 .retain(|hover_block| !hover_block.text.trim().is_empty());
12398 if hover.contents.is_empty() {
12399 None
12400 } else {
12401 Some(hover)
12402 }
12403}
12404
12405async fn populate_labels_for_completions(
12406 new_completions: Vec<CoreCompletion>,
12407 language: Option<Arc<Language>>,
12408 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12409) -> Vec<Completion> {
12410 let lsp_completions = new_completions
12411 .iter()
12412 .filter_map(|new_completion| {
12413 new_completion
12414 .source
12415 .lsp_completion(true)
12416 .map(|lsp_completion| lsp_completion.into_owned())
12417 })
12418 .collect::<Vec<_>>();
12419
12420 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12421 lsp_adapter
12422 .labels_for_completions(&lsp_completions, language)
12423 .await
12424 .log_err()
12425 .unwrap_or_default()
12426 } else {
12427 Vec::new()
12428 }
12429 .into_iter()
12430 .fuse();
12431
12432 let mut completions = Vec::new();
12433 for completion in new_completions {
12434 match completion.source.lsp_completion(true) {
12435 Some(lsp_completion) => {
12436 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12437
12438 let mut label = labels.next().flatten().unwrap_or_else(|| {
12439 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12440 });
12441 ensure_uniform_list_compatible_label(&mut label);
12442 completions.push(Completion {
12443 label,
12444 documentation,
12445 replace_range: completion.replace_range,
12446 new_text: completion.new_text,
12447 insert_text_mode: lsp_completion.insert_text_mode,
12448 source: completion.source,
12449 icon_path: None,
12450 confirm: None,
12451 });
12452 }
12453 None => {
12454 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12455 ensure_uniform_list_compatible_label(&mut label);
12456 completions.push(Completion {
12457 label,
12458 documentation: None,
12459 replace_range: completion.replace_range,
12460 new_text: completion.new_text,
12461 source: completion.source,
12462 insert_text_mode: None,
12463 icon_path: None,
12464 confirm: None,
12465 });
12466 }
12467 }
12468 }
12469 completions
12470}
12471
12472#[derive(Debug)]
12473pub enum LanguageServerToQuery {
12474 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12475 FirstCapable,
12476 /// Query a specific language server.
12477 Other(LanguageServerId),
12478}
12479
12480#[derive(Default)]
12481struct RenamePathsWatchedForServer {
12482 did_rename: Vec<RenameActionPredicate>,
12483 will_rename: Vec<RenameActionPredicate>,
12484}
12485
12486impl RenamePathsWatchedForServer {
12487 fn with_did_rename_patterns(
12488 mut self,
12489 did_rename: Option<&FileOperationRegistrationOptions>,
12490 ) -> Self {
12491 if let Some(did_rename) = did_rename {
12492 self.did_rename = did_rename
12493 .filters
12494 .iter()
12495 .filter_map(|filter| filter.try_into().log_err())
12496 .collect();
12497 }
12498 self
12499 }
12500 fn with_will_rename_patterns(
12501 mut self,
12502 will_rename: Option<&FileOperationRegistrationOptions>,
12503 ) -> Self {
12504 if let Some(will_rename) = will_rename {
12505 self.will_rename = will_rename
12506 .filters
12507 .iter()
12508 .filter_map(|filter| filter.try_into().log_err())
12509 .collect();
12510 }
12511 self
12512 }
12513
12514 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12515 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12516 }
12517 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12518 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12519 }
12520}
12521
12522impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12523 type Error = globset::Error;
12524 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12525 Ok(Self {
12526 kind: ops.pattern.matches.clone(),
12527 glob: GlobBuilder::new(&ops.pattern.glob)
12528 .case_insensitive(
12529 ops.pattern
12530 .options
12531 .as_ref()
12532 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12533 )
12534 .build()?
12535 .compile_matcher(),
12536 })
12537 }
12538}
12539struct RenameActionPredicate {
12540 glob: GlobMatcher,
12541 kind: Option<FileOperationPatternKind>,
12542}
12543
12544impl RenameActionPredicate {
12545 // Returns true if language server should be notified
12546 fn eval(&self, path: &str, is_dir: bool) -> bool {
12547 self.kind.as_ref().is_none_or(|kind| {
12548 let expected_kind = if is_dir {
12549 FileOperationPatternKind::Folder
12550 } else {
12551 FileOperationPatternKind::File
12552 };
12553 kind == &expected_kind
12554 }) && self.glob.is_match(path)
12555 }
12556}
12557
12558#[derive(Default)]
12559struct LanguageServerWatchedPaths {
12560 worktree_paths: HashMap<WorktreeId, GlobSet>,
12561 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12562}
12563
12564#[derive(Default)]
12565struct LanguageServerWatchedPathsBuilder {
12566 worktree_paths: HashMap<WorktreeId, GlobSet>,
12567 abs_paths: HashMap<Arc<Path>, GlobSet>,
12568}
12569
12570impl LanguageServerWatchedPathsBuilder {
12571 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12572 self.worktree_paths.insert(worktree_id, glob_set);
12573 }
12574 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12575 self.abs_paths.insert(path, glob_set);
12576 }
12577 fn build(
12578 self,
12579 fs: Arc<dyn Fs>,
12580 language_server_id: LanguageServerId,
12581 cx: &mut Context<LspStore>,
12582 ) -> LanguageServerWatchedPaths {
12583 let project = cx.weak_entity();
12584
12585 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12586 let abs_paths = self
12587 .abs_paths
12588 .into_iter()
12589 .map(|(abs_path, globset)| {
12590 let task = cx.spawn({
12591 let abs_path = abs_path.clone();
12592 let fs = fs.clone();
12593
12594 let lsp_store = project.clone();
12595 async move |_, cx| {
12596 maybe!(async move {
12597 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12598 while let Some(update) = push_updates.0.next().await {
12599 let action = lsp_store
12600 .update(cx, |this, _| {
12601 let Some(local) = this.as_local() else {
12602 return ControlFlow::Break(());
12603 };
12604 let Some(watcher) = local
12605 .language_server_watched_paths
12606 .get(&language_server_id)
12607 else {
12608 return ControlFlow::Break(());
12609 };
12610 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12611 "Watched abs path is not registered with a watcher",
12612 );
12613 let matching_entries = update
12614 .into_iter()
12615 .filter(|event| globs.is_match(&event.path))
12616 .collect::<Vec<_>>();
12617 this.lsp_notify_abs_paths_changed(
12618 language_server_id,
12619 matching_entries,
12620 );
12621 ControlFlow::Continue(())
12622 })
12623 .ok()?;
12624
12625 if action.is_break() {
12626 break;
12627 }
12628 }
12629 Some(())
12630 })
12631 .await;
12632 }
12633 });
12634 (abs_path, (globset, task))
12635 })
12636 .collect();
12637 LanguageServerWatchedPaths {
12638 worktree_paths: self.worktree_paths,
12639 abs_paths,
12640 }
12641 }
12642}
12643
12644struct LspBufferSnapshot {
12645 version: i32,
12646 snapshot: TextBufferSnapshot,
12647}
12648
12649/// A prompt requested by LSP server.
12650#[derive(Clone, Debug)]
12651pub struct LanguageServerPromptRequest {
12652 pub level: PromptLevel,
12653 pub message: String,
12654 pub actions: Vec<MessageActionItem>,
12655 pub lsp_name: String,
12656 pub(crate) response_channel: Sender<MessageActionItem>,
12657}
12658
12659impl LanguageServerPromptRequest {
12660 pub async fn respond(self, index: usize) -> Option<()> {
12661 if let Some(response) = self.actions.into_iter().nth(index) {
12662 self.response_channel.send(response).await.ok()
12663 } else {
12664 None
12665 }
12666 }
12667}
12668impl PartialEq for LanguageServerPromptRequest {
12669 fn eq(&self, other: &Self) -> bool {
12670 self.message == other.message && self.actions == other.actions
12671 }
12672}
12673
12674#[derive(Clone, Debug, PartialEq)]
12675pub enum LanguageServerLogType {
12676 Log(MessageType),
12677 Trace(Option<String>),
12678}
12679
12680impl LanguageServerLogType {
12681 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12682 match self {
12683 Self::Log(log_type) => {
12684 let message_type = match *log_type {
12685 MessageType::ERROR => 1,
12686 MessageType::WARNING => 2,
12687 MessageType::INFO => 3,
12688 MessageType::LOG => 4,
12689 other => {
12690 log::warn!("Unknown lsp log message type: {:?}", other);
12691 4
12692 }
12693 };
12694 proto::language_server_log::LogType::LogMessageType(message_type)
12695 }
12696 Self::Trace(message) => {
12697 proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
12698 message: message.clone(),
12699 })
12700 }
12701 }
12702 }
12703
12704 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12705 match log_type {
12706 proto::language_server_log::LogType::LogMessageType(message_type) => {
12707 Self::Log(match message_type {
12708 1 => MessageType::ERROR,
12709 2 => MessageType::WARNING,
12710 3 => MessageType::INFO,
12711 4 => MessageType::LOG,
12712 _ => MessageType::LOG,
12713 })
12714 }
12715 proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
12716 }
12717 }
12718}
12719
12720pub struct WorkspaceRefreshTask {
12721 refresh_tx: mpsc::Sender<()>,
12722 progress_tx: mpsc::Sender<()>,
12723 #[allow(dead_code)]
12724 task: Task<()>,
12725}
12726
12727pub enum LanguageServerState {
12728 Starting {
12729 startup: Task<Option<Arc<LanguageServer>>>,
12730 /// List of language servers that will be added to the workspace once it's initialization completes.
12731 pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
12732 },
12733
12734 Running {
12735 adapter: Arc<CachedLspAdapter>,
12736 server: Arc<LanguageServer>,
12737 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12738 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12739 },
12740}
12741
12742impl LanguageServerState {
12743 fn add_workspace_folder(&self, uri: Url) {
12744 match self {
12745 LanguageServerState::Starting {
12746 pending_workspace_folders,
12747 ..
12748 } => {
12749 pending_workspace_folders.lock().insert(uri);
12750 }
12751 LanguageServerState::Running { server, .. } => {
12752 server.add_workspace_folder(uri);
12753 }
12754 }
12755 }
12756 fn _remove_workspace_folder(&self, uri: Url) {
12757 match self {
12758 LanguageServerState::Starting {
12759 pending_workspace_folders,
12760 ..
12761 } => {
12762 pending_workspace_folders.lock().remove(&uri);
12763 }
12764 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12765 }
12766 }
12767}
12768
12769impl std::fmt::Debug for LanguageServerState {
12770 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12771 match self {
12772 LanguageServerState::Starting { .. } => {
12773 f.debug_struct("LanguageServerState::Starting").finish()
12774 }
12775 LanguageServerState::Running { .. } => {
12776 f.debug_struct("LanguageServerState::Running").finish()
12777 }
12778 }
12779 }
12780}
12781
12782#[derive(Clone, Debug, Serialize)]
12783pub struct LanguageServerProgress {
12784 pub is_disk_based_diagnostics_progress: bool,
12785 pub is_cancellable: bool,
12786 pub title: Option<String>,
12787 pub message: Option<String>,
12788 pub percentage: Option<usize>,
12789 #[serde(skip_serializing)]
12790 pub last_update_at: Instant,
12791}
12792
12793#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12794pub struct DiagnosticSummary {
12795 pub error_count: usize,
12796 pub warning_count: usize,
12797}
12798
12799impl DiagnosticSummary {
12800 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12801 let mut this = Self {
12802 error_count: 0,
12803 warning_count: 0,
12804 };
12805
12806 for entry in diagnostics {
12807 if entry.diagnostic.is_primary {
12808 match entry.diagnostic.severity {
12809 DiagnosticSeverity::ERROR => this.error_count += 1,
12810 DiagnosticSeverity::WARNING => this.warning_count += 1,
12811 _ => {}
12812 }
12813 }
12814 }
12815
12816 this
12817 }
12818
12819 pub fn is_empty(&self) -> bool {
12820 self.error_count == 0 && self.warning_count == 0
12821 }
12822
12823 pub fn to_proto(
12824 self,
12825 language_server_id: LanguageServerId,
12826 path: &Path,
12827 ) -> proto::DiagnosticSummary {
12828 proto::DiagnosticSummary {
12829 path: path.to_proto(),
12830 language_server_id: language_server_id.0 as u64,
12831 error_count: self.error_count as u32,
12832 warning_count: self.warning_count as u32,
12833 }
12834 }
12835}
12836
12837#[derive(Clone, Debug)]
12838pub enum CompletionDocumentation {
12839 /// There is no documentation for this completion.
12840 Undocumented,
12841 /// A single line of documentation.
12842 SingleLine(SharedString),
12843 /// Multiple lines of plain text documentation.
12844 MultiLinePlainText(SharedString),
12845 /// Markdown documentation.
12846 MultiLineMarkdown(SharedString),
12847 /// Both single line and multiple lines of plain text documentation.
12848 SingleLineAndMultiLinePlainText {
12849 single_line: SharedString,
12850 plain_text: Option<SharedString>,
12851 },
12852}
12853
12854impl From<lsp::Documentation> for CompletionDocumentation {
12855 fn from(docs: lsp::Documentation) -> Self {
12856 match docs {
12857 lsp::Documentation::String(text) => {
12858 if text.lines().count() <= 1 {
12859 CompletionDocumentation::SingleLine(text.into())
12860 } else {
12861 CompletionDocumentation::MultiLinePlainText(text.into())
12862 }
12863 }
12864
12865 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12866 lsp::MarkupKind::PlainText => {
12867 if value.lines().count() <= 1 {
12868 CompletionDocumentation::SingleLine(value.into())
12869 } else {
12870 CompletionDocumentation::MultiLinePlainText(value.into())
12871 }
12872 }
12873
12874 lsp::MarkupKind::Markdown => {
12875 CompletionDocumentation::MultiLineMarkdown(value.into())
12876 }
12877 },
12878 }
12879 }
12880}
12881
12882fn glob_literal_prefix(glob: &Path) -> PathBuf {
12883 glob.components()
12884 .take_while(|component| match component {
12885 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12886 _ => true,
12887 })
12888 .collect()
12889}
12890
12891pub struct SshLspAdapter {
12892 name: LanguageServerName,
12893 binary: LanguageServerBinary,
12894 initialization_options: Option<String>,
12895 code_action_kinds: Option<Vec<CodeActionKind>>,
12896}
12897
12898impl SshLspAdapter {
12899 pub fn new(
12900 name: LanguageServerName,
12901 binary: LanguageServerBinary,
12902 initialization_options: Option<String>,
12903 code_action_kinds: Option<String>,
12904 ) -> Self {
12905 Self {
12906 name,
12907 binary,
12908 initialization_options,
12909 code_action_kinds: code_action_kinds
12910 .as_ref()
12911 .and_then(|c| serde_json::from_str(c).ok()),
12912 }
12913 }
12914}
12915
12916#[async_trait(?Send)]
12917impl LspAdapter for SshLspAdapter {
12918 fn name(&self) -> LanguageServerName {
12919 self.name.clone()
12920 }
12921
12922 async fn initialization_options(
12923 self: Arc<Self>,
12924 _: &dyn Fs,
12925 _: &Arc<dyn LspAdapterDelegate>,
12926 ) -> Result<Option<serde_json::Value>> {
12927 let Some(options) = &self.initialization_options else {
12928 return Ok(None);
12929 };
12930 let result = serde_json::from_str(options)?;
12931 Ok(result)
12932 }
12933
12934 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12935 self.code_action_kinds.clone()
12936 }
12937
12938 async fn check_if_user_installed(
12939 &self,
12940 _: &dyn LspAdapterDelegate,
12941 _: Option<Toolchain>,
12942 _: &AsyncApp,
12943 ) -> Option<LanguageServerBinary> {
12944 Some(self.binary.clone())
12945 }
12946
12947 async fn cached_server_binary(
12948 &self,
12949 _: PathBuf,
12950 _: &dyn LspAdapterDelegate,
12951 ) -> Option<LanguageServerBinary> {
12952 None
12953 }
12954
12955 async fn fetch_latest_server_version(
12956 &self,
12957 _: &dyn LspAdapterDelegate,
12958 ) -> Result<Box<dyn 'static + Send + Any>> {
12959 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12960 }
12961
12962 async fn fetch_server_binary(
12963 &self,
12964 _: Box<dyn 'static + Send + Any>,
12965 _: PathBuf,
12966 _: &dyn LspAdapterDelegate,
12967 ) -> Result<LanguageServerBinary> {
12968 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12969 }
12970}
12971
12972pub fn language_server_settings<'a>(
12973 delegate: &'a dyn LspAdapterDelegate,
12974 language: &LanguageServerName,
12975 cx: &'a App,
12976) -> Option<&'a LspSettings> {
12977 language_server_settings_for(
12978 SettingsLocation {
12979 worktree_id: delegate.worktree_id(),
12980 path: delegate.worktree_root_path(),
12981 },
12982 language,
12983 cx,
12984 )
12985}
12986
12987pub(crate) fn language_server_settings_for<'a>(
12988 location: SettingsLocation<'a>,
12989 language: &LanguageServerName,
12990 cx: &'a App,
12991) -> Option<&'a LspSettings> {
12992 ProjectSettings::get(Some(location), cx).lsp.get(language)
12993}
12994
12995pub struct LocalLspAdapterDelegate {
12996 lsp_store: WeakEntity<LspStore>,
12997 worktree: worktree::Snapshot,
12998 fs: Arc<dyn Fs>,
12999 http_client: Arc<dyn HttpClient>,
13000 language_registry: Arc<LanguageRegistry>,
13001 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13002}
13003
13004impl LocalLspAdapterDelegate {
13005 pub fn new(
13006 language_registry: Arc<LanguageRegistry>,
13007 environment: &Entity<ProjectEnvironment>,
13008 lsp_store: WeakEntity<LspStore>,
13009 worktree: &Entity<Worktree>,
13010 http_client: Arc<dyn HttpClient>,
13011 fs: Arc<dyn Fs>,
13012 cx: &mut App,
13013 ) -> Arc<Self> {
13014 let load_shell_env_task = environment.update(cx, |env, cx| {
13015 env.get_worktree_environment(worktree.clone(), cx)
13016 });
13017
13018 Arc::new(Self {
13019 lsp_store,
13020 worktree: worktree.read(cx).snapshot(),
13021 fs,
13022 http_client,
13023 language_registry,
13024 load_shell_env_task,
13025 })
13026 }
13027
13028 fn from_local_lsp(
13029 local: &LocalLspStore,
13030 worktree: &Entity<Worktree>,
13031 cx: &mut App,
13032 ) -> Arc<Self> {
13033 Self::new(
13034 local.languages.clone(),
13035 &local.environment,
13036 local.weak.clone(),
13037 worktree,
13038 local.http_client.clone(),
13039 local.fs.clone(),
13040 cx,
13041 )
13042 }
13043}
13044
13045#[async_trait]
13046impl LspAdapterDelegate for LocalLspAdapterDelegate {
13047 fn show_notification(&self, message: &str, cx: &mut App) {
13048 self.lsp_store
13049 .update(cx, |_, cx| {
13050 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13051 })
13052 .ok();
13053 }
13054
13055 fn http_client(&self) -> Arc<dyn HttpClient> {
13056 self.http_client.clone()
13057 }
13058
13059 fn worktree_id(&self) -> WorktreeId {
13060 self.worktree.id()
13061 }
13062
13063 fn worktree_root_path(&self) -> &Path {
13064 self.worktree.abs_path().as_ref()
13065 }
13066
13067 async fn shell_env(&self) -> HashMap<String, String> {
13068 let task = self.load_shell_env_task.clone();
13069 task.await.unwrap_or_default()
13070 }
13071
13072 async fn npm_package_installed_version(
13073 &self,
13074 package_name: &str,
13075 ) -> Result<Option<(PathBuf, String)>> {
13076 let local_package_directory = self.worktree_root_path();
13077 let node_modules_directory = local_package_directory.join("node_modules");
13078
13079 if let Some(version) =
13080 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13081 {
13082 return Ok(Some((node_modules_directory, version)));
13083 }
13084 let Some(npm) = self.which("npm".as_ref()).await else {
13085 log::warn!(
13086 "Failed to find npm executable for {:?}",
13087 local_package_directory
13088 );
13089 return Ok(None);
13090 };
13091
13092 let env = self.shell_env().await;
13093 let output = util::command::new_smol_command(&npm)
13094 .args(["root", "-g"])
13095 .envs(env)
13096 .current_dir(local_package_directory)
13097 .output()
13098 .await?;
13099 let global_node_modules =
13100 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13101
13102 if let Some(version) =
13103 read_package_installed_version(global_node_modules.clone(), package_name).await?
13104 {
13105 return Ok(Some((global_node_modules, version)));
13106 }
13107 return Ok(None);
13108 }
13109
13110 #[cfg(not(target_os = "windows"))]
13111 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13112 let worktree_abs_path = self.worktree.abs_path();
13113 let shell_path = self.shell_env().await.get("PATH").cloned();
13114 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13115 }
13116
13117 #[cfg(target_os = "windows")]
13118 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13119 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
13120 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
13121 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
13122 which::which(command).ok()
13123 }
13124
13125 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13126 let working_dir = self.worktree_root_path();
13127 let output = util::command::new_smol_command(&command.path)
13128 .args(command.arguments)
13129 .envs(command.env.clone().unwrap_or_default())
13130 .current_dir(working_dir)
13131 .output()
13132 .await?;
13133
13134 anyhow::ensure!(
13135 output.status.success(),
13136 "{}, stdout: {:?}, stderr: {:?}",
13137 output.status,
13138 String::from_utf8_lossy(&output.stdout),
13139 String::from_utf8_lossy(&output.stderr)
13140 );
13141 Ok(())
13142 }
13143
13144 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13145 self.language_registry
13146 .update_lsp_binary_status(server_name, status);
13147 }
13148
13149 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13150 self.language_registry
13151 .all_lsp_adapters()
13152 .into_iter()
13153 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13154 .collect()
13155 }
13156
13157 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13158 let dir = self.language_registry.language_server_download_dir(name)?;
13159
13160 if !dir.exists() {
13161 smol::fs::create_dir_all(&dir)
13162 .await
13163 .context("failed to create container directory")
13164 .log_err()?;
13165 }
13166
13167 Some(dir)
13168 }
13169
13170 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
13171 let entry = self
13172 .worktree
13173 .entry_for_path(&path)
13174 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13175 let abs_path = self
13176 .worktree
13177 .absolutize(&entry.path)
13178 .with_context(|| format!("cannot absolutize path {path:?}"))?;
13179
13180 self.fs.load(&abs_path).await
13181 }
13182}
13183
13184async fn populate_labels_for_symbols(
13185 symbols: Vec<CoreSymbol>,
13186 language_registry: &Arc<LanguageRegistry>,
13187 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13188 output: &mut Vec<Symbol>,
13189) {
13190 #[allow(clippy::mutable_key_type)]
13191 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13192
13193 let mut unknown_paths = BTreeSet::new();
13194 for symbol in symbols {
13195 let language = language_registry
13196 .language_for_file_path(&symbol.path.path)
13197 .await
13198 .ok()
13199 .or_else(|| {
13200 unknown_paths.insert(symbol.path.path.clone());
13201 None
13202 });
13203 symbols_by_language
13204 .entry(language)
13205 .or_default()
13206 .push(symbol);
13207 }
13208
13209 for unknown_path in unknown_paths {
13210 log::info!(
13211 "no language found for symbol path {}",
13212 unknown_path.display()
13213 );
13214 }
13215
13216 let mut label_params = Vec::new();
13217 for (language, mut symbols) in symbols_by_language {
13218 label_params.clear();
13219 label_params.extend(
13220 symbols
13221 .iter_mut()
13222 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13223 );
13224
13225 let mut labels = Vec::new();
13226 if let Some(language) = language {
13227 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13228 language_registry
13229 .lsp_adapters(&language.name())
13230 .first()
13231 .cloned()
13232 });
13233 if let Some(lsp_adapter) = lsp_adapter {
13234 labels = lsp_adapter
13235 .labels_for_symbols(&label_params, &language)
13236 .await
13237 .log_err()
13238 .unwrap_or_default();
13239 }
13240 }
13241
13242 for ((symbol, (name, _)), label) in symbols
13243 .into_iter()
13244 .zip(label_params.drain(..))
13245 .zip(labels.into_iter().chain(iter::repeat(None)))
13246 {
13247 output.push(Symbol {
13248 language_server_name: symbol.language_server_name,
13249 source_worktree_id: symbol.source_worktree_id,
13250 source_language_server_id: symbol.source_language_server_id,
13251 path: symbol.path,
13252 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13253 name,
13254 kind: symbol.kind,
13255 range: symbol.range,
13256 signature: symbol.signature,
13257 });
13258 }
13259 }
13260}
13261
13262fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13263 match server.capabilities().text_document_sync.as_ref()? {
13264 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13265 // Server wants didSave but didn't specify includeText.
13266 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13267 // Server doesn't want didSave at all.
13268 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13269 // Server provided SaveOptions.
13270 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13271 Some(save_options.include_text.unwrap_or(false))
13272 }
13273 },
13274 // We do not have any save info. Kind affects didChange only.
13275 lsp::TextDocumentSyncCapability::Kind(_) => None,
13276 }
13277}
13278
13279/// Completion items are displayed in a `UniformList`.
13280/// Usually, those items are single-line strings, but in LSP responses,
13281/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13282/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13283/// 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,
13284/// breaking the completions menu presentation.
13285///
13286/// 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.
13287fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13288 let mut new_text = String::with_capacity(label.text.len());
13289 let mut offset_map = vec![0; label.text.len() + 1];
13290 let mut last_char_was_space = false;
13291 let mut new_idx = 0;
13292 let chars = label.text.char_indices().fuse();
13293 let mut newlines_removed = false;
13294
13295 for (idx, c) in chars {
13296 offset_map[idx] = new_idx;
13297
13298 match c {
13299 '\n' if last_char_was_space => {
13300 newlines_removed = true;
13301 }
13302 '\t' | ' ' if last_char_was_space => {}
13303 '\n' if !last_char_was_space => {
13304 new_text.push(' ');
13305 new_idx += 1;
13306 last_char_was_space = true;
13307 newlines_removed = true;
13308 }
13309 ' ' | '\t' => {
13310 new_text.push(' ');
13311 new_idx += 1;
13312 last_char_was_space = true;
13313 }
13314 _ => {
13315 new_text.push(c);
13316 new_idx += c.len_utf8();
13317 last_char_was_space = false;
13318 }
13319 }
13320 }
13321 offset_map[label.text.len()] = new_idx;
13322
13323 // Only modify the label if newlines were removed.
13324 if !newlines_removed {
13325 return;
13326 }
13327
13328 let last_index = new_idx;
13329 let mut run_ranges_errors = Vec::new();
13330 label.runs.retain_mut(|(range, _)| {
13331 match offset_map.get(range.start) {
13332 Some(&start) => range.start = start,
13333 None => {
13334 run_ranges_errors.push(range.clone());
13335 return false;
13336 }
13337 }
13338
13339 match offset_map.get(range.end) {
13340 Some(&end) => range.end = end,
13341 None => {
13342 run_ranges_errors.push(range.clone());
13343 range.end = last_index;
13344 }
13345 }
13346 true
13347 });
13348 if !run_ranges_errors.is_empty() {
13349 log::error!(
13350 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13351 label.text
13352 );
13353 }
13354
13355 let mut wrong_filter_range = None;
13356 if label.filter_range == (0..label.text.len()) {
13357 label.filter_range = 0..new_text.len();
13358 } else {
13359 let mut original_filter_range = Some(label.filter_range.clone());
13360 match offset_map.get(label.filter_range.start) {
13361 Some(&start) => label.filter_range.start = start,
13362 None => {
13363 wrong_filter_range = original_filter_range.take();
13364 label.filter_range.start = last_index;
13365 }
13366 }
13367
13368 match offset_map.get(label.filter_range.end) {
13369 Some(&end) => label.filter_range.end = end,
13370 None => {
13371 wrong_filter_range = original_filter_range.take();
13372 label.filter_range.end = last_index;
13373 }
13374 }
13375 }
13376 if let Some(wrong_filter_range) = wrong_filter_range {
13377 log::error!(
13378 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13379 label.text
13380 );
13381 }
13382
13383 label.text = new_text;
13384}
13385
13386#[cfg(test)]
13387mod tests {
13388 use language::HighlightId;
13389
13390 use super::*;
13391
13392 #[test]
13393 fn test_glob_literal_prefix() {
13394 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13395 assert_eq!(
13396 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13397 Path::new("node_modules")
13398 );
13399 assert_eq!(
13400 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13401 Path::new("foo")
13402 );
13403 assert_eq!(
13404 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13405 Path::new("foo/bar/baz.js")
13406 );
13407
13408 #[cfg(target_os = "windows")]
13409 {
13410 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13411 assert_eq!(
13412 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13413 Path::new("node_modules")
13414 );
13415 assert_eq!(
13416 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13417 Path::new("foo")
13418 );
13419 assert_eq!(
13420 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13421 Path::new("foo/bar/baz.js")
13422 );
13423 }
13424 }
13425
13426 #[test]
13427 fn test_multi_len_chars_normalization() {
13428 let mut label = CodeLabel {
13429 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13430 runs: vec![(0..6, HighlightId(1))],
13431 filter_range: 0..6,
13432 };
13433 ensure_uniform_list_compatible_label(&mut label);
13434 assert_eq!(
13435 label,
13436 CodeLabel {
13437 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13438 runs: vec![(0..6, HighlightId(1))],
13439 filter_range: 0..6,
13440 }
13441 );
13442 }
13443}