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