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