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