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