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