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