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