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;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 inlay_hint_cache::BufferChunk,
33 log_store::{GlobalLogStore, LanguageServerKind},
34 },
35 manifest_tree::{
36 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
37 ManifestTree,
38 },
39 prettier_store::{self, PrettierStore, PrettierStoreEvent},
40 project_settings::{LspSettings, ProjectSettings},
41 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
59 WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76};
77use lsp::{
78 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticServerCapabilities,
79 DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit,
80 FileOperationFilter, FileOperationPatternKind, FileOperationRegistrationOptions, FileRename,
81 FileSystemWatcher, LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary,
82 LanguageServerBinaryOptions, LanguageServerId, LanguageServerName, LanguageServerSelector,
83 LspRequestFuture, MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
84 TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, WorkDoneProgressCancelParams,
85 WorkspaceFolder, notification::DidRenameFiles,
86};
87use node_runtime::read_package_installed_version;
88use parking_lot::Mutex;
89use postage::{mpsc, sink::Sink, stream::Stream, watch};
90use rand::prelude::*;
91use rpc::{
92 AnyProtoClient, ErrorCode, ErrorExt as _,
93 proto::{LspRequestId, LspRequestMessage as _},
94};
95use serde::Serialize;
96use settings::{Settings, SettingsLocation, SettingsStore};
97use sha2::{Digest, Sha256};
98use smol::channel::Sender;
99use snippet::Snippet;
100use std::{
101 any::TypeId,
102 borrow::Cow,
103 cell::RefCell,
104 cmp::{Ordering, Reverse},
105 convert::TryInto,
106 ffi::OsStr,
107 future::ready,
108 iter, mem,
109 ops::{ControlFlow, Range},
110 path::{self, Path, PathBuf},
111 pin::pin,
112 rc::Rc,
113 sync::{
114 Arc,
115 atomic::{self, AtomicUsize},
116 },
117 time::{Duration, Instant},
118};
119use sum_tree::Dimensions;
120use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, Point, ToPoint as _};
121
122use util::{
123 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
124 paths::{PathStyle, SanitizedPath},
125 post_inc,
126 rel_path::RelPath,
127};
128
129pub use fs::*;
130pub use language::Location;
131pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
132#[cfg(any(test, feature = "test-support"))]
133pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
134pub use worktree::{
135 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
136 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
137};
138
139const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
140pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
141const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
144pub enum ProgressToken {
145 Number(i32),
146 String(SharedString),
147}
148
149impl std::fmt::Display for ProgressToken {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::Number(number) => write!(f, "{number}"),
153 Self::String(string) => write!(f, "{string}"),
154 }
155 }
156}
157
158impl ProgressToken {
159 fn from_lsp(value: lsp::NumberOrString) -> Self {
160 match value {
161 lsp::NumberOrString::Number(number) => Self::Number(number),
162 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
163 }
164 }
165
166 fn to_lsp(&self) -> lsp::NumberOrString {
167 match self {
168 Self::Number(number) => lsp::NumberOrString::Number(*number),
169 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
170 }
171 }
172
173 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
174 Some(match value.value? {
175 proto::progress_token::Value::Number(number) => Self::Number(number),
176 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
177 })
178 }
179
180 fn to_proto(&self) -> proto::ProgressToken {
181 proto::ProgressToken {
182 value: Some(match self {
183 Self::Number(number) => proto::progress_token::Value::Number(*number),
184 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
185 }),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum FormatTrigger {
192 Save,
193 Manual,
194}
195
196pub enum LspFormatTarget {
197 Buffers,
198 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
199}
200
201pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
202
203impl FormatTrigger {
204 fn from_proto(value: i32) -> FormatTrigger {
205 match value {
206 0 => FormatTrigger::Save,
207 1 => FormatTrigger::Manual,
208 _ => FormatTrigger::Save,
209 }
210 }
211}
212
213#[derive(Clone)]
214struct UnifiedLanguageServer {
215 id: LanguageServerId,
216 project_roots: HashSet<Arc<RelPath>>,
217}
218
219#[derive(Clone, Hash, PartialEq, Eq)]
220struct LanguageServerSeed {
221 worktree_id: WorktreeId,
222 name: LanguageServerName,
223 toolchain: Option<Toolchain>,
224 settings: Arc<LspSettings>,
225}
226
227#[derive(Debug)]
228pub struct DocumentDiagnosticsUpdate<'a, D> {
229 pub diagnostics: D,
230 pub result_id: Option<String>,
231 pub server_id: LanguageServerId,
232 pub disk_based_sources: Cow<'a, [String]>,
233}
234
235pub struct DocumentDiagnostics {
236 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
237 document_abs_path: PathBuf,
238 version: Option<i32>,
239}
240
241#[derive(Default)]
242struct DynamicRegistrations {
243 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
244 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
245}
246
247pub struct LocalLspStore {
248 weak: WeakEntity<LspStore>,
249 worktree_store: Entity<WorktreeStore>,
250 toolchain_store: Entity<LocalToolchainStore>,
251 http_client: Arc<dyn HttpClient>,
252 environment: Entity<ProjectEnvironment>,
253 fs: Arc<dyn Fs>,
254 languages: Arc<LanguageRegistry>,
255 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
256 yarn: Entity<YarnPathStore>,
257 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
258 buffers_being_formatted: HashSet<BufferId>,
259 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
260 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
261 watched_manifest_filenames: HashSet<ManifestName>,
262 language_server_paths_watched_for_rename:
263 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
264 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
265 supplementary_language_servers:
266 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
267 prettier_store: Entity<PrettierStore>,
268 next_diagnostic_group_id: usize,
269 diagnostics: HashMap<
270 WorktreeId,
271 HashMap<
272 Arc<RelPath>,
273 Vec<(
274 LanguageServerId,
275 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 )>,
277 >,
278 >,
279 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
280 _subscription: gpui::Subscription,
281 lsp_tree: LanguageServerTree,
282 registered_buffers: HashMap<BufferId, usize>,
283 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
284 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
285}
286
287impl LocalLspStore {
288 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
289 pub fn running_language_server_for_id(
290 &self,
291 id: LanguageServerId,
292 ) -> Option<&Arc<LanguageServer>> {
293 let language_server_state = self.language_servers.get(&id)?;
294
295 match language_server_state {
296 LanguageServerState::Running { server, .. } => Some(server),
297 LanguageServerState::Starting { .. } => None,
298 }
299 }
300
301 fn get_or_insert_language_server(
302 &mut self,
303 worktree_handle: &Entity<Worktree>,
304 delegate: Arc<LocalLspAdapterDelegate>,
305 disposition: &Arc<LaunchDisposition>,
306 language_name: &LanguageName,
307 cx: &mut App,
308 ) -> LanguageServerId {
309 let key = LanguageServerSeed {
310 worktree_id: worktree_handle.read(cx).id(),
311 name: disposition.server_name.clone(),
312 settings: disposition.settings.clone(),
313 toolchain: disposition.toolchain.clone(),
314 };
315 if let Some(state) = self.language_server_ids.get_mut(&key) {
316 state.project_roots.insert(disposition.path.path.clone());
317 state.id
318 } else {
319 let adapter = self
320 .languages
321 .lsp_adapters(language_name)
322 .into_iter()
323 .find(|adapter| adapter.name() == disposition.server_name)
324 .expect("To find LSP adapter");
325 let new_language_server_id = self.start_language_server(
326 worktree_handle,
327 delegate,
328 adapter,
329 disposition.settings.clone(),
330 key.clone(),
331 cx,
332 );
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 } else {
336 debug_assert!(
337 false,
338 "Expected `start_language_server` to ensure that `key` exists in a map"
339 );
340 }
341 new_language_server_id
342 }
343 }
344
345 fn start_language_server(
346 &mut self,
347 worktree_handle: &Entity<Worktree>,
348 delegate: Arc<LocalLspAdapterDelegate>,
349 adapter: Arc<CachedLspAdapter>,
350 settings: Arc<LspSettings>,
351 key: LanguageServerSeed,
352 cx: &mut App,
353 ) -> LanguageServerId {
354 let worktree = worktree_handle.read(cx);
355
356 let root_path = worktree.abs_path();
357 let toolchain = key.toolchain.clone();
358 let override_options = settings.initialization_options.clone();
359
360 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
361
362 let server_id = self.languages.next_language_server_id();
363 log::trace!(
364 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
365 adapter.name.0
366 );
367
368 let binary = self.get_language_server_binary(
369 adapter.clone(),
370 settings,
371 toolchain.clone(),
372 delegate.clone(),
373 true,
374 cx,
375 );
376 let pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
377
378 let pending_server = cx.spawn({
379 let adapter = adapter.clone();
380 let server_name = adapter.name.clone();
381 let stderr_capture = stderr_capture.clone();
382 #[cfg(any(test, feature = "test-support"))]
383 let lsp_store = self.weak.clone();
384 let pending_workspace_folders = pending_workspace_folders.clone();
385 async move |cx| {
386 let binary = binary.await?;
387 #[cfg(any(test, feature = "test-support"))]
388 if let Some(server) = lsp_store
389 .update(&mut cx.clone(), |this, cx| {
390 this.languages.create_fake_language_server(
391 server_id,
392 &server_name,
393 binary.clone(),
394 &mut cx.to_async(),
395 )
396 })
397 .ok()
398 .flatten()
399 {
400 return Ok(server);
401 }
402
403 let code_action_kinds = adapter.code_action_kinds();
404 lsp::LanguageServer::new(
405 stderr_capture,
406 server_id,
407 server_name,
408 binary,
409 &root_path,
410 code_action_kinds,
411 Some(pending_workspace_folders),
412 cx,
413 )
414 }
415 });
416
417 let startup = {
418 let server_name = adapter.name.0.clone();
419 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
420 let key = key.clone();
421 let adapter = adapter.clone();
422 let lsp_store = self.weak.clone();
423 let pending_workspace_folders = pending_workspace_folders.clone();
424
425 let pull_diagnostics = ProjectSettings::get_global(cx)
426 .diagnostics
427 .lsp_pull_diagnostics
428 .enabled;
429 cx.spawn(async move |cx| {
430 let result = async {
431 let language_server = pending_server.await?;
432
433 let workspace_config = Self::workspace_configuration_for_adapter(
434 adapter.adapter.clone(),
435 &delegate,
436 toolchain,
437 cx,
438 )
439 .await?;
440
441 let mut initialization_options = Self::initialization_options_for_adapter(
442 adapter.adapter.clone(),
443 &delegate,
444 )
445 .await?;
446
447 match (&mut initialization_options, override_options) {
448 (Some(initialization_options), Some(override_options)) => {
449 merge_json_value_into(override_options, initialization_options);
450 }
451 (None, override_options) => initialization_options = override_options,
452 _ => {}
453 }
454
455 let initialization_params = cx.update(|cx| {
456 let mut params =
457 language_server.default_initialize_params(pull_diagnostics, cx);
458 params.initialization_options = initialization_options;
459 adapter.adapter.prepare_initialize_params(params, cx)
460 })??;
461
462 Self::setup_lsp_messages(
463 lsp_store.clone(),
464 &language_server,
465 delegate.clone(),
466 adapter.clone(),
467 );
468
469 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
470 settings: workspace_config,
471 };
472 let language_server = cx
473 .update(|cx| {
474 language_server.initialize(
475 initialization_params,
476 Arc::new(did_change_configuration_params.clone()),
477 cx,
478 )
479 })?
480 .await
481 .inspect_err(|_| {
482 if let Some(lsp_store) = lsp_store.upgrade() {
483 lsp_store
484 .update(cx, |lsp_store, cx| {
485 lsp_store.cleanup_lsp_data(server_id);
486 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
487 })
488 .ok();
489 }
490 })?;
491
492 language_server.notify::<lsp::notification::DidChangeConfiguration>(
493 did_change_configuration_params,
494 )?;
495
496 anyhow::Ok(language_server)
497 }
498 .await;
499
500 match result {
501 Ok(server) => {
502 lsp_store
503 .update(cx, |lsp_store, cx| {
504 lsp_store.insert_newly_running_language_server(
505 adapter,
506 server.clone(),
507 server_id,
508 key,
509 pending_workspace_folders,
510 cx,
511 );
512 })
513 .ok();
514 stderr_capture.lock().take();
515 Some(server)
516 }
517
518 Err(err) => {
519 let log = stderr_capture.lock().take().unwrap_or_default();
520 delegate.update_status(
521 adapter.name(),
522 BinaryStatus::Failed {
523 error: if log.is_empty() {
524 format!("{err:#}")
525 } else {
526 format!("{err:#}\n-- stderr --\n{log}")
527 },
528 },
529 );
530 log::error!("Failed to start language server {server_name:?}: {err:?}");
531 if !log.is_empty() {
532 log::error!("server stderr: {log}");
533 }
534 None
535 }
536 }
537 })
538 };
539 let state = LanguageServerState::Starting {
540 startup,
541 pending_workspace_folders,
542 };
543
544 self.languages
545 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
546
547 self.language_servers.insert(server_id, state);
548 self.language_server_ids
549 .entry(key)
550 .or_insert(UnifiedLanguageServer {
551 id: server_id,
552 project_roots: Default::default(),
553 });
554 server_id
555 }
556
557 fn get_language_server_binary(
558 &self,
559 adapter: Arc<CachedLspAdapter>,
560 settings: Arc<LspSettings>,
561 toolchain: Option<Toolchain>,
562 delegate: Arc<dyn LspAdapterDelegate>,
563 allow_binary_download: bool,
564 cx: &mut App,
565 ) -> Task<Result<LanguageServerBinary>> {
566 if let Some(settings) = settings.binary.as_ref()
567 && settings.path.is_some()
568 {
569 let settings = settings.clone();
570
571 return cx.background_spawn(async move {
572 let mut env = delegate.shell_env().await;
573 env.extend(settings.env.unwrap_or_default());
574
575 Ok(LanguageServerBinary {
576 path: PathBuf::from(&settings.path.unwrap()),
577 env: Some(env),
578 arguments: settings
579 .arguments
580 .unwrap_or_default()
581 .iter()
582 .map(Into::into)
583 .collect(),
584 })
585 });
586 }
587 let lsp_binary_options = LanguageServerBinaryOptions {
588 allow_path_lookup: !settings
589 .binary
590 .as_ref()
591 .and_then(|b| b.ignore_system_version)
592 .unwrap_or_default(),
593 allow_binary_download,
594 pre_release: settings
595 .fetch
596 .as_ref()
597 .and_then(|f| f.pre_release)
598 .unwrap_or(false),
599 };
600
601 cx.spawn(async move |cx| {
602 let binary_result = adapter
603 .clone()
604 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
605 .await;
606
607 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
608
609 let mut binary = binary_result?;
610 let mut shell_env = delegate.shell_env().await;
611
612 shell_env.extend(binary.env.unwrap_or_default());
613
614 if let Some(settings) = settings.binary.as_ref() {
615 if let Some(arguments) = &settings.arguments {
616 binary.arguments = arguments.iter().map(Into::into).collect();
617 }
618 if let Some(env) = &settings.env {
619 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
620 }
621 }
622
623 binary.env = Some(shell_env);
624 Ok(binary)
625 })
626 }
627
628 fn setup_lsp_messages(
629 lsp_store: WeakEntity<LspStore>,
630 language_server: &LanguageServer,
631 delegate: Arc<dyn LspAdapterDelegate>,
632 adapter: Arc<CachedLspAdapter>,
633 ) {
634 let name = language_server.name();
635 let server_id = language_server.server_id();
636 language_server
637 .on_notification::<lsp::notification::PublishDiagnostics, _>({
638 let adapter = adapter.clone();
639 let this = lsp_store.clone();
640 move |mut params, cx| {
641 let adapter = adapter.clone();
642 if let Some(this) = this.upgrade() {
643 this.update(cx, |this, cx| {
644 {
645 let buffer = params
646 .uri
647 .to_file_path()
648 .map(|file_path| this.get_buffer(&file_path, cx))
649 .ok()
650 .flatten();
651 adapter.process_diagnostics(&mut params, server_id, buffer);
652 }
653
654 this.merge_lsp_diagnostics(
655 DiagnosticSourceKind::Pushed,
656 vec![DocumentDiagnosticsUpdate {
657 server_id,
658 diagnostics: params,
659 result_id: None,
660 disk_based_sources: Cow::Borrowed(
661 &adapter.disk_based_diagnostic_sources,
662 ),
663 }],
664 |_, diagnostic, cx| match diagnostic.source_kind {
665 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
666 adapter.retain_old_diagnostic(diagnostic, cx)
667 }
668 DiagnosticSourceKind::Pulled => true,
669 },
670 cx,
671 )
672 .log_err();
673 })
674 .ok();
675 }
676 }
677 })
678 .detach();
679 language_server
680 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
681 let adapter = adapter.adapter.clone();
682 let delegate = delegate.clone();
683 let this = lsp_store.clone();
684 move |params, cx| {
685 let adapter = adapter.clone();
686 let delegate = delegate.clone();
687 let this = this.clone();
688 let mut cx = cx.clone();
689 async move {
690 let toolchain_for_id = this
691 .update(&mut cx, |this, _| {
692 this.as_local()?.language_server_ids.iter().find_map(
693 |(seed, value)| {
694 (value.id == server_id).then(|| seed.toolchain.clone())
695 },
696 )
697 })?
698 .context("Expected the LSP store to be in a local mode")?;
699 let workspace_config = Self::workspace_configuration_for_adapter(
700 adapter.clone(),
701 &delegate,
702 toolchain_for_id,
703 &mut cx,
704 )
705 .await?;
706
707 Ok(params
708 .items
709 .into_iter()
710 .map(|item| {
711 if let Some(section) = &item.section {
712 workspace_config
713 .get(section)
714 .cloned()
715 .unwrap_or(serde_json::Value::Null)
716 } else {
717 workspace_config.clone()
718 }
719 })
720 .collect())
721 }
722 }
723 })
724 .detach();
725
726 language_server
727 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
728 let this = lsp_store.clone();
729 move |_, cx| {
730 let this = this.clone();
731 let cx = cx.clone();
732 async move {
733 let Some(server) =
734 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
735 else {
736 return Ok(None);
737 };
738 let root = server.workspace_folders();
739 Ok(Some(
740 root.into_iter()
741 .map(|uri| WorkspaceFolder {
742 uri,
743 name: Default::default(),
744 })
745 .collect(),
746 ))
747 }
748 }
749 })
750 .detach();
751 // Even though we don't have handling for these requests, respond to them to
752 // avoid stalling any language server like `gopls` which waits for a response
753 // to these requests when initializing.
754 language_server
755 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
756 let this = lsp_store.clone();
757 move |params, cx| {
758 let this = this.clone();
759 let mut cx = cx.clone();
760 async move {
761 this.update(&mut cx, |this, _| {
762 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
763 {
764 status
765 .progress_tokens
766 .insert(ProgressToken::from_lsp(params.token));
767 }
768 })?;
769
770 Ok(())
771 }
772 }
773 })
774 .detach();
775
776 language_server
777 .on_request::<lsp::request::RegisterCapability, _, _>({
778 let lsp_store = lsp_store.clone();
779 move |params, cx| {
780 let lsp_store = lsp_store.clone();
781 let mut cx = cx.clone();
782 async move {
783 lsp_store
784 .update(&mut cx, |lsp_store, cx| {
785 if lsp_store.as_local().is_some() {
786 match lsp_store
787 .register_server_capabilities(server_id, params, cx)
788 {
789 Ok(()) => {}
790 Err(e) => {
791 log::error!(
792 "Failed to register server capabilities: {e:#}"
793 );
794 }
795 };
796 }
797 })
798 .ok();
799 Ok(())
800 }
801 }
802 })
803 .detach();
804
805 language_server
806 .on_request::<lsp::request::UnregisterCapability, _, _>({
807 let lsp_store = lsp_store.clone();
808 move |params, cx| {
809 let lsp_store = lsp_store.clone();
810 let mut cx = cx.clone();
811 async move {
812 lsp_store
813 .update(&mut cx, |lsp_store, cx| {
814 if lsp_store.as_local().is_some() {
815 match lsp_store
816 .unregister_server_capabilities(server_id, params, cx)
817 {
818 Ok(()) => {}
819 Err(e) => {
820 log::error!(
821 "Failed to unregister server capabilities: {e:#}"
822 );
823 }
824 }
825 }
826 })
827 .ok();
828 Ok(())
829 }
830 }
831 })
832 .detach();
833
834 language_server
835 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
836 let this = lsp_store.clone();
837 move |params, cx| {
838 let mut cx = cx.clone();
839 let this = this.clone();
840 async move {
841 LocalLspStore::on_lsp_workspace_edit(
842 this.clone(),
843 params,
844 server_id,
845 &mut cx,
846 )
847 .await
848 }
849 }
850 })
851 .detach();
852
853 language_server
854 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
855 let lsp_store = lsp_store.clone();
856 move |(), cx| {
857 let this = lsp_store.clone();
858 let mut cx = cx.clone();
859 async move {
860 this.update(&mut cx, |lsp_store, cx| {
861 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
862 lsp_store
863 .downstream_client
864 .as_ref()
865 .map(|(client, project_id)| {
866 client.send(proto::RefreshInlayHints {
867 project_id: *project_id,
868 server_id: server_id.to_proto(),
869 })
870 })
871 })?
872 .transpose()?;
873 Ok(())
874 }
875 }
876 })
877 .detach();
878
879 language_server
880 .on_request::<lsp::request::CodeLensRefresh, _, _>({
881 let this = lsp_store.clone();
882 move |(), cx| {
883 let this = this.clone();
884 let mut cx = cx.clone();
885 async move {
886 this.update(&mut cx, |this, cx| {
887 cx.emit(LspStoreEvent::RefreshCodeLens);
888 this.downstream_client.as_ref().map(|(client, project_id)| {
889 client.send(proto::RefreshCodeLens {
890 project_id: *project_id,
891 })
892 })
893 })?
894 .transpose()?;
895 Ok(())
896 }
897 }
898 })
899 .detach();
900
901 language_server
902 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
903 let this = lsp_store.clone();
904 move |(), cx| {
905 let this = this.clone();
906 let mut cx = cx.clone();
907 async move {
908 this.update(&mut cx, |lsp_store, _| {
909 lsp_store.pull_workspace_diagnostics(server_id);
910 lsp_store
911 .downstream_client
912 .as_ref()
913 .map(|(client, project_id)| {
914 client.send(proto::PullWorkspaceDiagnostics {
915 project_id: *project_id,
916 server_id: server_id.to_proto(),
917 })
918 })
919 })?
920 .transpose()?;
921 Ok(())
922 }
923 }
924 })
925 .detach();
926
927 language_server
928 .on_request::<lsp::request::ShowMessageRequest, _, _>({
929 let this = lsp_store.clone();
930 let name = name.to_string();
931 move |params, cx| {
932 let this = this.clone();
933 let name = name.to_string();
934 let mut cx = cx.clone();
935 async move {
936 let actions = params.actions.unwrap_or_default();
937 let (tx, rx) = smol::channel::bounded(1);
938 let request = LanguageServerPromptRequest {
939 level: match params.typ {
940 lsp::MessageType::ERROR => PromptLevel::Critical,
941 lsp::MessageType::WARNING => PromptLevel::Warning,
942 _ => PromptLevel::Info,
943 },
944 message: params.message,
945 actions,
946 response_channel: tx,
947 lsp_name: name.clone(),
948 };
949
950 let did_update = this
951 .update(&mut cx, |_, cx| {
952 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
953 })
954 .is_ok();
955 if did_update {
956 let response = rx.recv().await.ok();
957 Ok(response)
958 } else {
959 Ok(None)
960 }
961 }
962 }
963 })
964 .detach();
965 language_server
966 .on_notification::<lsp::notification::ShowMessage, _>({
967 let this = lsp_store.clone();
968 let name = name.to_string();
969 move |params, cx| {
970 let this = this.clone();
971 let name = name.to_string();
972 let mut cx = cx.clone();
973
974 let (tx, _) = smol::channel::bounded(1);
975 let request = LanguageServerPromptRequest {
976 level: match params.typ {
977 lsp::MessageType::ERROR => PromptLevel::Critical,
978 lsp::MessageType::WARNING => PromptLevel::Warning,
979 _ => PromptLevel::Info,
980 },
981 message: params.message,
982 actions: vec![],
983 response_channel: tx,
984 lsp_name: name,
985 };
986
987 let _ = this.update(&mut cx, |_, cx| {
988 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
989 });
990 }
991 })
992 .detach();
993
994 let disk_based_diagnostics_progress_token =
995 adapter.disk_based_diagnostics_progress_token.clone();
996
997 language_server
998 .on_notification::<lsp::notification::Progress, _>({
999 let this = lsp_store.clone();
1000 move |params, cx| {
1001 if let Some(this) = this.upgrade() {
1002 this.update(cx, |this, cx| {
1003 this.on_lsp_progress(
1004 params,
1005 server_id,
1006 disk_based_diagnostics_progress_token.clone(),
1007 cx,
1008 );
1009 })
1010 .ok();
1011 }
1012 }
1013 })
1014 .detach();
1015
1016 language_server
1017 .on_notification::<lsp::notification::LogMessage, _>({
1018 let this = lsp_store.clone();
1019 move |params, cx| {
1020 if let Some(this) = this.upgrade() {
1021 this.update(cx, |_, cx| {
1022 cx.emit(LspStoreEvent::LanguageServerLog(
1023 server_id,
1024 LanguageServerLogType::Log(params.typ),
1025 params.message,
1026 ));
1027 })
1028 .ok();
1029 }
1030 }
1031 })
1032 .detach();
1033
1034 language_server
1035 .on_notification::<lsp::notification::LogTrace, _>({
1036 let this = lsp_store.clone();
1037 move |params, cx| {
1038 let mut cx = cx.clone();
1039 if let Some(this) = this.upgrade() {
1040 this.update(&mut cx, |_, cx| {
1041 cx.emit(LspStoreEvent::LanguageServerLog(
1042 server_id,
1043 LanguageServerLogType::Trace {
1044 verbose_info: params.verbose,
1045 },
1046 params.message,
1047 ));
1048 })
1049 .ok();
1050 }
1051 }
1052 })
1053 .detach();
1054
1055 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1056 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1057 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1058 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1059 }
1060
1061 fn shutdown_language_servers_on_quit(
1062 &mut self,
1063 _: &mut Context<LspStore>,
1064 ) -> impl Future<Output = ()> + use<> {
1065 let shutdown_futures = self
1066 .language_servers
1067 .drain()
1068 .map(|(_, server_state)| Self::shutdown_server(server_state))
1069 .collect::<Vec<_>>();
1070
1071 async move {
1072 join_all(shutdown_futures).await;
1073 }
1074 }
1075
1076 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1077 match server_state {
1078 LanguageServerState::Running { server, .. } => {
1079 if let Some(shutdown) = server.shutdown() {
1080 shutdown.await;
1081 }
1082 }
1083 LanguageServerState::Starting { startup, .. } => {
1084 if let Some(server) = startup.await
1085 && let Some(shutdown) = server.shutdown()
1086 {
1087 shutdown.await;
1088 }
1089 }
1090 }
1091 Ok(())
1092 }
1093
1094 fn language_servers_for_worktree(
1095 &self,
1096 worktree_id: WorktreeId,
1097 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1098 self.language_server_ids
1099 .iter()
1100 .filter_map(move |(seed, state)| {
1101 if seed.worktree_id != worktree_id {
1102 return None;
1103 }
1104
1105 if let Some(LanguageServerState::Running { server, .. }) =
1106 self.language_servers.get(&state.id)
1107 {
1108 Some(server)
1109 } else {
1110 None
1111 }
1112 })
1113 }
1114
1115 fn language_server_ids_for_project_path(
1116 &self,
1117 project_path: ProjectPath,
1118 language: &Language,
1119 cx: &mut App,
1120 ) -> Vec<LanguageServerId> {
1121 let Some(worktree) = self
1122 .worktree_store
1123 .read(cx)
1124 .worktree_for_id(project_path.worktree_id, cx)
1125 else {
1126 return Vec::new();
1127 };
1128 let delegate: Arc<dyn ManifestDelegate> =
1129 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1130
1131 self.lsp_tree
1132 .get(
1133 project_path,
1134 language.name(),
1135 language.manifest(),
1136 &delegate,
1137 cx,
1138 )
1139 .collect::<Vec<_>>()
1140 }
1141
1142 fn language_server_ids_for_buffer(
1143 &self,
1144 buffer: &Buffer,
1145 cx: &mut App,
1146 ) -> Vec<LanguageServerId> {
1147 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1148 let worktree_id = file.worktree_id(cx);
1149
1150 let path: Arc<RelPath> = file
1151 .path()
1152 .parent()
1153 .map(Arc::from)
1154 .unwrap_or_else(|| file.path().clone());
1155 let worktree_path = ProjectPath { worktree_id, path };
1156 self.language_server_ids_for_project_path(worktree_path, language, cx)
1157 } else {
1158 Vec::new()
1159 }
1160 }
1161
1162 fn language_servers_for_buffer<'a>(
1163 &'a self,
1164 buffer: &'a Buffer,
1165 cx: &'a mut App,
1166 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1167 self.language_server_ids_for_buffer(buffer, cx)
1168 .into_iter()
1169 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1170 LanguageServerState::Running {
1171 adapter, server, ..
1172 } => Some((adapter, server)),
1173 _ => None,
1174 })
1175 }
1176
1177 async fn execute_code_action_kind_locally(
1178 lsp_store: WeakEntity<LspStore>,
1179 mut buffers: Vec<Entity<Buffer>>,
1180 kind: CodeActionKind,
1181 push_to_history: bool,
1182 cx: &mut AsyncApp,
1183 ) -> anyhow::Result<ProjectTransaction> {
1184 // Do not allow multiple concurrent code actions requests for the
1185 // same buffer.
1186 lsp_store.update(cx, |this, cx| {
1187 let this = this.as_local_mut().unwrap();
1188 buffers.retain(|buffer| {
1189 this.buffers_being_formatted
1190 .insert(buffer.read(cx).remote_id())
1191 });
1192 })?;
1193 let _cleanup = defer({
1194 let this = lsp_store.clone();
1195 let mut cx = cx.clone();
1196 let buffers = &buffers;
1197 move || {
1198 this.update(&mut cx, |this, cx| {
1199 let this = this.as_local_mut().unwrap();
1200 for buffer in buffers {
1201 this.buffers_being_formatted
1202 .remove(&buffer.read(cx).remote_id());
1203 }
1204 })
1205 .ok();
1206 }
1207 });
1208 let mut project_transaction = ProjectTransaction::default();
1209
1210 for buffer in &buffers {
1211 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1212 buffer.update(cx, |buffer, cx| {
1213 lsp_store
1214 .as_local()
1215 .unwrap()
1216 .language_servers_for_buffer(buffer, cx)
1217 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1218 .collect::<Vec<_>>()
1219 })
1220 })?;
1221 for (_, language_server) in adapters_and_servers.iter() {
1222 let actions = Self::get_server_code_actions_from_action_kinds(
1223 &lsp_store,
1224 language_server.server_id(),
1225 vec![kind.clone()],
1226 buffer,
1227 cx,
1228 )
1229 .await?;
1230 Self::execute_code_actions_on_server(
1231 &lsp_store,
1232 language_server,
1233 actions,
1234 push_to_history,
1235 &mut project_transaction,
1236 cx,
1237 )
1238 .await?;
1239 }
1240 }
1241 Ok(project_transaction)
1242 }
1243
1244 async fn format_locally(
1245 lsp_store: WeakEntity<LspStore>,
1246 mut buffers: Vec<FormattableBuffer>,
1247 push_to_history: bool,
1248 trigger: FormatTrigger,
1249 logger: zlog::Logger,
1250 cx: &mut AsyncApp,
1251 ) -> anyhow::Result<ProjectTransaction> {
1252 // Do not allow multiple concurrent formatting requests for the
1253 // same buffer.
1254 lsp_store.update(cx, |this, cx| {
1255 let this = this.as_local_mut().unwrap();
1256 buffers.retain(|buffer| {
1257 this.buffers_being_formatted
1258 .insert(buffer.handle.read(cx).remote_id())
1259 });
1260 })?;
1261
1262 let _cleanup = defer({
1263 let this = lsp_store.clone();
1264 let mut cx = cx.clone();
1265 let buffers = &buffers;
1266 move || {
1267 this.update(&mut cx, |this, cx| {
1268 let this = this.as_local_mut().unwrap();
1269 for buffer in buffers {
1270 this.buffers_being_formatted
1271 .remove(&buffer.handle.read(cx).remote_id());
1272 }
1273 })
1274 .ok();
1275 }
1276 });
1277
1278 let mut project_transaction = ProjectTransaction::default();
1279
1280 for buffer in &buffers {
1281 zlog::debug!(
1282 logger =>
1283 "formatting buffer '{:?}'",
1284 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1285 );
1286 // Create an empty transaction to hold all of the formatting edits.
1287 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1288 // ensure no transactions created while formatting are
1289 // grouped with the previous transaction in the history
1290 // based on the transaction group interval
1291 buffer.finalize_last_transaction();
1292 buffer
1293 .start_transaction()
1294 .context("transaction already open")?;
1295 buffer.end_transaction(cx);
1296 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1297 buffer.finalize_last_transaction();
1298 anyhow::Ok(transaction_id)
1299 })??;
1300
1301 let result = Self::format_buffer_locally(
1302 lsp_store.clone(),
1303 buffer,
1304 formatting_transaction_id,
1305 trigger,
1306 logger,
1307 cx,
1308 )
1309 .await;
1310
1311 buffer.handle.update(cx, |buffer, cx| {
1312 let Some(formatting_transaction) =
1313 buffer.get_transaction(formatting_transaction_id).cloned()
1314 else {
1315 zlog::warn!(logger => "no formatting transaction");
1316 return;
1317 };
1318 if formatting_transaction.edit_ids.is_empty() {
1319 zlog::debug!(logger => "no changes made while formatting");
1320 buffer.forget_transaction(formatting_transaction_id);
1321 return;
1322 }
1323 if !push_to_history {
1324 zlog::trace!(logger => "forgetting format transaction");
1325 buffer.forget_transaction(formatting_transaction.id);
1326 }
1327 project_transaction
1328 .0
1329 .insert(cx.entity(), formatting_transaction);
1330 })?;
1331
1332 result?;
1333 }
1334
1335 Ok(project_transaction)
1336 }
1337
1338 async fn format_buffer_locally(
1339 lsp_store: WeakEntity<LspStore>,
1340 buffer: &FormattableBuffer,
1341 formatting_transaction_id: clock::Lamport,
1342 trigger: FormatTrigger,
1343 logger: zlog::Logger,
1344 cx: &mut AsyncApp,
1345 ) -> Result<()> {
1346 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1347 buffer.handle.update(cx, |buffer, cx| {
1348 let adapters_and_servers = lsp_store
1349 .as_local()
1350 .unwrap()
1351 .language_servers_for_buffer(buffer, cx)
1352 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1353 .collect::<Vec<_>>();
1354 let settings =
1355 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1356 .into_owned();
1357 (adapters_and_servers, settings)
1358 })
1359 })?;
1360
1361 /// Apply edits to the buffer that will become part of the formatting transaction.
1362 /// Fails if the buffer has been edited since the start of that transaction.
1363 fn extend_formatting_transaction(
1364 buffer: &FormattableBuffer,
1365 formatting_transaction_id: text::TransactionId,
1366 cx: &mut AsyncApp,
1367 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1368 ) -> anyhow::Result<()> {
1369 buffer.handle.update(cx, |buffer, cx| {
1370 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1371 if last_transaction_id != Some(formatting_transaction_id) {
1372 anyhow::bail!("Buffer edited while formatting. Aborting")
1373 }
1374 buffer.start_transaction();
1375 operation(buffer, cx);
1376 if let Some(transaction_id) = buffer.end_transaction(cx) {
1377 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1378 }
1379 Ok(())
1380 })?
1381 }
1382
1383 // handle whitespace formatting
1384 if settings.remove_trailing_whitespace_on_save {
1385 zlog::trace!(logger => "removing trailing whitespace");
1386 let diff = buffer
1387 .handle
1388 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1389 .await;
1390 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1391 buffer.apply_diff(diff, cx);
1392 })?;
1393 }
1394
1395 if settings.ensure_final_newline_on_save {
1396 zlog::trace!(logger => "ensuring final newline");
1397 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1398 buffer.ensure_final_newline(cx);
1399 })?;
1400 }
1401
1402 // Formatter for `code_actions_on_format` that runs before
1403 // the rest of the formatters
1404 let mut code_actions_on_format_formatters = None;
1405 let should_run_code_actions_on_format = !matches!(
1406 (trigger, &settings.format_on_save),
1407 (FormatTrigger::Save, &FormatOnSave::Off)
1408 );
1409 if should_run_code_actions_on_format {
1410 let have_code_actions_to_run_on_format = settings
1411 .code_actions_on_format
1412 .values()
1413 .any(|enabled| *enabled);
1414 if have_code_actions_to_run_on_format {
1415 zlog::trace!(logger => "going to run code actions on format");
1416 code_actions_on_format_formatters = Some(
1417 settings
1418 .code_actions_on_format
1419 .iter()
1420 .filter_map(|(action, enabled)| enabled.then_some(action))
1421 .cloned()
1422 .map(Formatter::CodeAction)
1423 .collect::<Vec<_>>(),
1424 );
1425 }
1426 }
1427
1428 let formatters = match (trigger, &settings.format_on_save) {
1429 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1430 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1431 settings.formatter.as_ref()
1432 }
1433 };
1434
1435 let formatters = code_actions_on_format_formatters
1436 .iter()
1437 .flatten()
1438 .chain(formatters);
1439
1440 for formatter in formatters {
1441 let formatter = if formatter == &Formatter::Auto {
1442 if settings.prettier.allowed {
1443 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1444 &Formatter::Prettier
1445 } else {
1446 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1447 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1448 }
1449 } else {
1450 formatter
1451 };
1452 match formatter {
1453 Formatter::Auto => unreachable!("Auto resolved above"),
1454 Formatter::Prettier => {
1455 let logger = zlog::scoped!(logger => "prettier");
1456 zlog::trace!(logger => "formatting");
1457 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1458
1459 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1460 lsp_store.prettier_store().unwrap().downgrade()
1461 })?;
1462 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1463 .await
1464 .transpose()?;
1465 let Some(diff) = diff else {
1466 zlog::trace!(logger => "No changes");
1467 continue;
1468 };
1469
1470 extend_formatting_transaction(
1471 buffer,
1472 formatting_transaction_id,
1473 cx,
1474 |buffer, cx| {
1475 buffer.apply_diff(diff, cx);
1476 },
1477 )?;
1478 }
1479 Formatter::External { command, arguments } => {
1480 let logger = zlog::scoped!(logger => "command");
1481 zlog::trace!(logger => "formatting");
1482 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1483
1484 let diff = Self::format_via_external_command(
1485 buffer,
1486 command.as_ref(),
1487 arguments.as_deref(),
1488 cx,
1489 )
1490 .await
1491 .with_context(|| {
1492 format!("Failed to format buffer via external command: {}", command)
1493 })?;
1494 let Some(diff) = diff else {
1495 zlog::trace!(logger => "No changes");
1496 continue;
1497 };
1498
1499 extend_formatting_transaction(
1500 buffer,
1501 formatting_transaction_id,
1502 cx,
1503 |buffer, cx| {
1504 buffer.apply_diff(diff, cx);
1505 },
1506 )?;
1507 }
1508 Formatter::LanguageServer(specifier) => {
1509 let logger = zlog::scoped!(logger => "language-server");
1510 zlog::trace!(logger => "formatting");
1511 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1512
1513 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1514 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1515 continue;
1516 };
1517
1518 let language_server = match specifier {
1519 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1520 adapters_and_servers.iter().find_map(|(adapter, server)| {
1521 if adapter.name.0.as_ref() == name {
1522 Some(server.clone())
1523 } else {
1524 None
1525 }
1526 })
1527 }
1528 settings::LanguageServerFormatterSpecifier::Current => {
1529 adapters_and_servers.first().map(|e| e.1.clone())
1530 }
1531 };
1532
1533 let Some(language_server) = language_server else {
1534 log::debug!(
1535 "No language server found to format buffer '{:?}'. Skipping",
1536 buffer_path_abs.as_path().to_string_lossy()
1537 );
1538 continue;
1539 };
1540
1541 zlog::trace!(
1542 logger =>
1543 "Formatting buffer '{:?}' using language server '{:?}'",
1544 buffer_path_abs.as_path().to_string_lossy(),
1545 language_server.name()
1546 );
1547
1548 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1549 zlog::trace!(logger => "formatting ranges");
1550 Self::format_ranges_via_lsp(
1551 &lsp_store,
1552 &buffer.handle,
1553 ranges,
1554 buffer_path_abs,
1555 &language_server,
1556 &settings,
1557 cx,
1558 )
1559 .await
1560 .context("Failed to format ranges via language server")?
1561 } else {
1562 zlog::trace!(logger => "formatting full");
1563 Self::format_via_lsp(
1564 &lsp_store,
1565 &buffer.handle,
1566 buffer_path_abs,
1567 &language_server,
1568 &settings,
1569 cx,
1570 )
1571 .await
1572 .context("failed to format via language server")?
1573 };
1574
1575 if edits.is_empty() {
1576 zlog::trace!(logger => "No changes");
1577 continue;
1578 }
1579 extend_formatting_transaction(
1580 buffer,
1581 formatting_transaction_id,
1582 cx,
1583 |buffer, cx| {
1584 buffer.edit(edits, None, cx);
1585 },
1586 )?;
1587 }
1588 Formatter::CodeAction(code_action_name) => {
1589 let logger = zlog::scoped!(logger => "code-actions");
1590 zlog::trace!(logger => "formatting");
1591 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1592
1593 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1594 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1595 continue;
1596 };
1597
1598 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1599 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1600
1601 let mut actions_and_servers = Vec::new();
1602
1603 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1604 let actions_result = Self::get_server_code_actions_from_action_kinds(
1605 &lsp_store,
1606 language_server.server_id(),
1607 vec![code_action_kind.clone()],
1608 &buffer.handle,
1609 cx,
1610 )
1611 .await
1612 .with_context(|| {
1613 format!(
1614 "Failed to resolve code action {:?} with language server {}",
1615 code_action_kind,
1616 language_server.name()
1617 )
1618 });
1619 let Ok(actions) = actions_result else {
1620 // note: it may be better to set result to the error and break formatters here
1621 // but for now we try to execute the actions that we can resolve and skip the rest
1622 zlog::error!(
1623 logger =>
1624 "Failed to resolve code action {:?} with language server {}",
1625 code_action_kind,
1626 language_server.name()
1627 );
1628 continue;
1629 };
1630 for action in actions {
1631 actions_and_servers.push((action, index));
1632 }
1633 }
1634
1635 if actions_and_servers.is_empty() {
1636 zlog::warn!(logger => "No code actions were resolved, continuing");
1637 continue;
1638 }
1639
1640 'actions: for (mut action, server_index) in actions_and_servers {
1641 let server = &adapters_and_servers[server_index].1;
1642
1643 let describe_code_action = |action: &CodeAction| {
1644 format!(
1645 "code action '{}' with title \"{}\" on server {}",
1646 action
1647 .lsp_action
1648 .action_kind()
1649 .unwrap_or("unknown".into())
1650 .as_str(),
1651 action.lsp_action.title(),
1652 server.name(),
1653 )
1654 };
1655
1656 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1657
1658 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1659 zlog::error!(
1660 logger =>
1661 "Failed to resolve {}. Error: {}",
1662 describe_code_action(&action),
1663 err
1664 );
1665 continue;
1666 }
1667
1668 if let Some(edit) = action.lsp_action.edit().cloned() {
1669 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1670 // but filters out and logs warnings for code actions that require unreasonably
1671 // difficult handling on our part, such as:
1672 // - applying edits that call commands
1673 // which can result in arbitrary workspace edits being sent from the server that
1674 // have no way of being tied back to the command that initiated them (i.e. we
1675 // can't know which edits are part of the format request, or if the server is done sending
1676 // actions in response to the command)
1677 // - actions that create/delete/modify/rename files other than the one we are formatting
1678 // as we then would need to handle such changes correctly in the local history as well
1679 // as the remote history through the ProjectTransaction
1680 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1681 // Supporting these actions is not impossible, but not supported as of yet.
1682 if edit.changes.is_none() && edit.document_changes.is_none() {
1683 zlog::trace!(
1684 logger =>
1685 "No changes for code action. Skipping {}",
1686 describe_code_action(&action),
1687 );
1688 continue;
1689 }
1690
1691 let mut operations = Vec::new();
1692 if let Some(document_changes) = edit.document_changes {
1693 match document_changes {
1694 lsp::DocumentChanges::Edits(edits) => operations.extend(
1695 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1696 ),
1697 lsp::DocumentChanges::Operations(ops) => operations = ops,
1698 }
1699 } else if let Some(changes) = edit.changes {
1700 operations.extend(changes.into_iter().map(|(uri, edits)| {
1701 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1702 text_document:
1703 lsp::OptionalVersionedTextDocumentIdentifier {
1704 uri,
1705 version: None,
1706 },
1707 edits: edits.into_iter().map(Edit::Plain).collect(),
1708 })
1709 }));
1710 }
1711
1712 let mut edits = Vec::with_capacity(operations.len());
1713
1714 if operations.is_empty() {
1715 zlog::trace!(
1716 logger =>
1717 "No changes for code action. Skipping {}",
1718 describe_code_action(&action),
1719 );
1720 continue;
1721 }
1722 for operation in operations {
1723 let op = match operation {
1724 lsp::DocumentChangeOperation::Edit(op) => op,
1725 lsp::DocumentChangeOperation::Op(_) => {
1726 zlog::warn!(
1727 logger =>
1728 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1729 describe_code_action(&action),
1730 );
1731 continue 'actions;
1732 }
1733 };
1734 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1735 zlog::warn!(
1736 logger =>
1737 "Failed to convert URI '{:?}' to file path. Skipping {}",
1738 &op.text_document.uri,
1739 describe_code_action(&action),
1740 );
1741 continue 'actions;
1742 };
1743 if &file_path != buffer_path_abs {
1744 zlog::warn!(
1745 logger =>
1746 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1747 file_path,
1748 buffer_path_abs,
1749 describe_code_action(&action),
1750 );
1751 continue 'actions;
1752 }
1753
1754 let mut lsp_edits = Vec::new();
1755 for edit in op.edits {
1756 match edit {
1757 Edit::Plain(edit) => {
1758 if !lsp_edits.contains(&edit) {
1759 lsp_edits.push(edit);
1760 }
1761 }
1762 Edit::Annotated(edit) => {
1763 if !lsp_edits.contains(&edit.text_edit) {
1764 lsp_edits.push(edit.text_edit);
1765 }
1766 }
1767 Edit::Snippet(_) => {
1768 zlog::warn!(
1769 logger =>
1770 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1771 describe_code_action(&action),
1772 );
1773 continue 'actions;
1774 }
1775 }
1776 }
1777 let edits_result = lsp_store
1778 .update(cx, |lsp_store, cx| {
1779 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1780 &buffer.handle,
1781 lsp_edits,
1782 server.server_id(),
1783 op.text_document.version,
1784 cx,
1785 )
1786 })?
1787 .await;
1788 let Ok(resolved_edits) = edits_result else {
1789 zlog::warn!(
1790 logger =>
1791 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1792 buffer_path_abs.as_path(),
1793 describe_code_action(&action),
1794 );
1795 continue 'actions;
1796 };
1797 edits.extend(resolved_edits);
1798 }
1799
1800 if edits.is_empty() {
1801 zlog::warn!(logger => "No edits resolved from LSP");
1802 continue;
1803 }
1804
1805 extend_formatting_transaction(
1806 buffer,
1807 formatting_transaction_id,
1808 cx,
1809 |buffer, cx| {
1810 zlog::info!(
1811 "Applying edits {edits:?}. Content: {:?}",
1812 buffer.text()
1813 );
1814 buffer.edit(edits, None, cx);
1815 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1816 },
1817 )?;
1818 }
1819
1820 if let Some(command) = action.lsp_action.command() {
1821 zlog::warn!(
1822 logger =>
1823 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1824 &command.command,
1825 );
1826
1827 // bail early if command is invalid
1828 let server_capabilities = server.capabilities();
1829 let available_commands = server_capabilities
1830 .execute_command_provider
1831 .as_ref()
1832 .map(|options| options.commands.as_slice())
1833 .unwrap_or_default();
1834 if !available_commands.contains(&command.command) {
1835 zlog::warn!(
1836 logger =>
1837 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1838 command.command,
1839 server.name(),
1840 );
1841 continue;
1842 }
1843
1844 // noop so we just ensure buffer hasn't been edited since resolving code actions
1845 extend_formatting_transaction(
1846 buffer,
1847 formatting_transaction_id,
1848 cx,
1849 |_, _| {},
1850 )?;
1851 zlog::info!(logger => "Executing command {}", &command.command);
1852
1853 lsp_store.update(cx, |this, _| {
1854 this.as_local_mut()
1855 .unwrap()
1856 .last_workspace_edits_by_language_server
1857 .remove(&server.server_id());
1858 })?;
1859
1860 let execute_command_result = server
1861 .request::<lsp::request::ExecuteCommand>(
1862 lsp::ExecuteCommandParams {
1863 command: command.command.clone(),
1864 arguments: command.arguments.clone().unwrap_or_default(),
1865 ..Default::default()
1866 },
1867 )
1868 .await
1869 .into_response();
1870
1871 if execute_command_result.is_err() {
1872 zlog::error!(
1873 logger =>
1874 "Failed to execute command '{}' as part of {}",
1875 &command.command,
1876 describe_code_action(&action),
1877 );
1878 continue 'actions;
1879 }
1880
1881 let mut project_transaction_command =
1882 lsp_store.update(cx, |this, _| {
1883 this.as_local_mut()
1884 .unwrap()
1885 .last_workspace_edits_by_language_server
1886 .remove(&server.server_id())
1887 .unwrap_or_default()
1888 })?;
1889
1890 if let Some(transaction) =
1891 project_transaction_command.0.remove(&buffer.handle)
1892 {
1893 zlog::trace!(
1894 logger =>
1895 "Successfully captured {} edits that resulted from command {}",
1896 transaction.edit_ids.len(),
1897 &command.command,
1898 );
1899 let transaction_id_project_transaction = transaction.id;
1900 buffer.handle.update(cx, |buffer, _| {
1901 // it may have been removed from history if push_to_history was
1902 // false in deserialize_workspace_edit. If so push it so we
1903 // can merge it with the format transaction
1904 // and pop the combined transaction off the history stack
1905 // later if push_to_history is false
1906 if buffer.get_transaction(transaction.id).is_none() {
1907 buffer.push_transaction(transaction, Instant::now());
1908 }
1909 buffer.merge_transactions(
1910 transaction_id_project_transaction,
1911 formatting_transaction_id,
1912 );
1913 })?;
1914 }
1915
1916 if !project_transaction_command.0.is_empty() {
1917 let mut extra_buffers = String::new();
1918 for buffer in project_transaction_command.0.keys() {
1919 buffer
1920 .read_with(cx, |b, cx| {
1921 if let Some(path) = b.project_path(cx) {
1922 if !extra_buffers.is_empty() {
1923 extra_buffers.push_str(", ");
1924 }
1925 extra_buffers.push_str(path.path.as_unix_str());
1926 }
1927 })
1928 .ok();
1929 }
1930 zlog::warn!(
1931 logger =>
1932 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1933 &command.command,
1934 extra_buffers,
1935 );
1936 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1937 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1938 // add it so it's included, and merge it into the format transaction when its created later
1939 }
1940 }
1941 }
1942 }
1943 }
1944 }
1945
1946 Ok(())
1947 }
1948
1949 pub async fn format_ranges_via_lsp(
1950 this: &WeakEntity<LspStore>,
1951 buffer_handle: &Entity<Buffer>,
1952 ranges: &[Range<Anchor>],
1953 abs_path: &Path,
1954 language_server: &Arc<LanguageServer>,
1955 settings: &LanguageSettings,
1956 cx: &mut AsyncApp,
1957 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1958 let capabilities = &language_server.capabilities();
1959 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1960 if range_formatting_provider == Some(&OneOf::Left(false)) {
1961 anyhow::bail!(
1962 "{} language server does not support range formatting",
1963 language_server.name()
1964 );
1965 }
1966
1967 let uri = file_path_to_lsp_url(abs_path)?;
1968 let text_document = lsp::TextDocumentIdentifier::new(uri);
1969
1970 let lsp_edits = {
1971 let mut lsp_ranges = Vec::new();
1972 this.update(cx, |_this, cx| {
1973 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1974 // not have been sent to the language server. This seems like a fairly systemic
1975 // issue, though, the resolution probably is not specific to formatting.
1976 //
1977 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1978 // LSP.
1979 let snapshot = buffer_handle.read(cx).snapshot();
1980 for range in ranges {
1981 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1982 }
1983 anyhow::Ok(())
1984 })??;
1985
1986 let mut edits = None;
1987 for range in lsp_ranges {
1988 if let Some(mut edit) = language_server
1989 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1990 text_document: text_document.clone(),
1991 range,
1992 options: lsp_command::lsp_formatting_options(settings),
1993 work_done_progress_params: Default::default(),
1994 })
1995 .await
1996 .into_response()?
1997 {
1998 edits.get_or_insert_with(Vec::new).append(&mut edit);
1999 }
2000 }
2001 edits
2002 };
2003
2004 if let Some(lsp_edits) = lsp_edits {
2005 this.update(cx, |this, cx| {
2006 this.as_local_mut().unwrap().edits_from_lsp(
2007 buffer_handle,
2008 lsp_edits,
2009 language_server.server_id(),
2010 None,
2011 cx,
2012 )
2013 })?
2014 .await
2015 } else {
2016 Ok(Vec::with_capacity(0))
2017 }
2018 }
2019
2020 async fn format_via_lsp(
2021 this: &WeakEntity<LspStore>,
2022 buffer: &Entity<Buffer>,
2023 abs_path: &Path,
2024 language_server: &Arc<LanguageServer>,
2025 settings: &LanguageSettings,
2026 cx: &mut AsyncApp,
2027 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2028 let logger = zlog::scoped!("lsp_format");
2029 zlog::info!(logger => "Formatting via LSP");
2030
2031 let uri = file_path_to_lsp_url(abs_path)?;
2032 let text_document = lsp::TextDocumentIdentifier::new(uri);
2033 let capabilities = &language_server.capabilities();
2034
2035 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2036 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2037
2038 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2039 let _timer = zlog::time!(logger => "format-full");
2040 language_server
2041 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2042 text_document,
2043 options: lsp_command::lsp_formatting_options(settings),
2044 work_done_progress_params: Default::default(),
2045 })
2046 .await
2047 .into_response()?
2048 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2049 let _timer = zlog::time!(logger => "format-range");
2050 let buffer_start = lsp::Position::new(0, 0);
2051 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2052 language_server
2053 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2054 text_document: text_document.clone(),
2055 range: lsp::Range::new(buffer_start, buffer_end),
2056 options: lsp_command::lsp_formatting_options(settings),
2057 work_done_progress_params: Default::default(),
2058 })
2059 .await
2060 .into_response()?
2061 } else {
2062 None
2063 };
2064
2065 if let Some(lsp_edits) = lsp_edits {
2066 this.update(cx, |this, cx| {
2067 this.as_local_mut().unwrap().edits_from_lsp(
2068 buffer,
2069 lsp_edits,
2070 language_server.server_id(),
2071 None,
2072 cx,
2073 )
2074 })?
2075 .await
2076 } else {
2077 Ok(Vec::with_capacity(0))
2078 }
2079 }
2080
2081 async fn format_via_external_command(
2082 buffer: &FormattableBuffer,
2083 command: &str,
2084 arguments: Option<&[String]>,
2085 cx: &mut AsyncApp,
2086 ) -> Result<Option<Diff>> {
2087 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2088 let file = File::from_dyn(buffer.file())?;
2089 let worktree = file.worktree.read(cx);
2090 let mut worktree_path = worktree.abs_path().to_path_buf();
2091 if worktree.root_entry()?.is_file() {
2092 worktree_path.pop();
2093 }
2094 Some(worktree_path)
2095 })?;
2096
2097 let mut child = util::command::new_smol_command(command);
2098
2099 if let Some(buffer_env) = buffer.env.as_ref() {
2100 child.envs(buffer_env);
2101 }
2102
2103 if let Some(working_dir_path) = working_dir_path {
2104 child.current_dir(working_dir_path);
2105 }
2106
2107 if let Some(arguments) = arguments {
2108 child.args(arguments.iter().map(|arg| {
2109 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2110 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2111 } else {
2112 arg.replace("{buffer_path}", "Untitled")
2113 }
2114 }));
2115 }
2116
2117 let mut child = child
2118 .stdin(smol::process::Stdio::piped())
2119 .stdout(smol::process::Stdio::piped())
2120 .stderr(smol::process::Stdio::piped())
2121 .spawn()?;
2122
2123 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2124 let text = buffer
2125 .handle
2126 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2127 for chunk in text.chunks() {
2128 stdin.write_all(chunk.as_bytes()).await?;
2129 }
2130 stdin.flush().await?;
2131
2132 let output = child.output().await?;
2133 anyhow::ensure!(
2134 output.status.success(),
2135 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2136 output.status.code(),
2137 String::from_utf8_lossy(&output.stdout),
2138 String::from_utf8_lossy(&output.stderr),
2139 );
2140
2141 let stdout = String::from_utf8(output.stdout)?;
2142 Ok(Some(
2143 buffer
2144 .handle
2145 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2146 .await,
2147 ))
2148 }
2149
2150 async fn try_resolve_code_action(
2151 lang_server: &LanguageServer,
2152 action: &mut CodeAction,
2153 ) -> anyhow::Result<()> {
2154 match &mut action.lsp_action {
2155 LspAction::Action(lsp_action) => {
2156 if !action.resolved
2157 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2158 && lsp_action.data.is_some()
2159 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2160 {
2161 *lsp_action = Box::new(
2162 lang_server
2163 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2164 .await
2165 .into_response()?,
2166 );
2167 }
2168 }
2169 LspAction::CodeLens(lens) => {
2170 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2171 *lens = lang_server
2172 .request::<lsp::request::CodeLensResolve>(lens.clone())
2173 .await
2174 .into_response()?;
2175 }
2176 }
2177 LspAction::Command(_) => {}
2178 }
2179
2180 action.resolved = true;
2181 anyhow::Ok(())
2182 }
2183
2184 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2185 let buffer = buffer_handle.read(cx);
2186
2187 let file = buffer.file().cloned();
2188
2189 let Some(file) = File::from_dyn(file.as_ref()) else {
2190 return;
2191 };
2192 if !file.is_local() {
2193 return;
2194 }
2195 let path = ProjectPath::from_file(file, cx);
2196 let worktree_id = file.worktree_id(cx);
2197 let language = buffer.language().cloned();
2198
2199 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2200 for (server_id, diagnostics) in
2201 diagnostics.get(file.path()).cloned().unwrap_or_default()
2202 {
2203 self.update_buffer_diagnostics(
2204 buffer_handle,
2205 server_id,
2206 None,
2207 None,
2208 diagnostics,
2209 Vec::new(),
2210 cx,
2211 )
2212 .log_err();
2213 }
2214 }
2215 let Some(language) = language else {
2216 return;
2217 };
2218 let Some(snapshot) = self
2219 .worktree_store
2220 .read(cx)
2221 .worktree_for_id(worktree_id, cx)
2222 .map(|worktree| worktree.read(cx).snapshot())
2223 else {
2224 return;
2225 };
2226 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2227
2228 for server_id in
2229 self.lsp_tree
2230 .get(path, language.name(), language.manifest(), &delegate, cx)
2231 {
2232 let server = self
2233 .language_servers
2234 .get(&server_id)
2235 .and_then(|server_state| {
2236 if let LanguageServerState::Running { server, .. } = server_state {
2237 Some(server.clone())
2238 } else {
2239 None
2240 }
2241 });
2242 let server = match server {
2243 Some(server) => server,
2244 None => continue,
2245 };
2246
2247 buffer_handle.update(cx, |buffer, cx| {
2248 buffer.set_completion_triggers(
2249 server.server_id(),
2250 server
2251 .capabilities()
2252 .completion_provider
2253 .as_ref()
2254 .and_then(|provider| {
2255 provider
2256 .trigger_characters
2257 .as_ref()
2258 .map(|characters| characters.iter().cloned().collect())
2259 })
2260 .unwrap_or_default(),
2261 cx,
2262 );
2263 });
2264 }
2265 }
2266
2267 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2268 buffer.update(cx, |buffer, cx| {
2269 let Some(language) = buffer.language() else {
2270 return;
2271 };
2272 let path = ProjectPath {
2273 worktree_id: old_file.worktree_id(cx),
2274 path: old_file.path.clone(),
2275 };
2276 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2277 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2278 buffer.set_completion_triggers(server_id, Default::default(), cx);
2279 }
2280 });
2281 }
2282
2283 fn update_buffer_diagnostics(
2284 &mut self,
2285 buffer: &Entity<Buffer>,
2286 server_id: LanguageServerId,
2287 result_id: Option<String>,
2288 version: Option<i32>,
2289 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2290 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2291 cx: &mut Context<LspStore>,
2292 ) -> Result<()> {
2293 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2294 Ordering::Equal
2295 .then_with(|| b.is_primary.cmp(&a.is_primary))
2296 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2297 .then_with(|| a.severity.cmp(&b.severity))
2298 .then_with(|| a.message.cmp(&b.message))
2299 }
2300
2301 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2302 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2303 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2304
2305 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2306 Ordering::Equal
2307 .then_with(|| a.range.start.cmp(&b.range.start))
2308 .then_with(|| b.range.end.cmp(&a.range.end))
2309 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2310 });
2311
2312 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2313
2314 let edits_since_save = std::cell::LazyCell::new(|| {
2315 let saved_version = buffer.read(cx).saved_version();
2316 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2317 });
2318
2319 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2320
2321 for (new_diagnostic, entry) in diagnostics {
2322 let start;
2323 let end;
2324 if new_diagnostic && entry.diagnostic.is_disk_based {
2325 // Some diagnostics are based on files on disk instead of buffers'
2326 // current contents. Adjust these diagnostics' ranges to reflect
2327 // any unsaved edits.
2328 // Do not alter the reused ones though, as their coordinates were stored as anchors
2329 // and were properly adjusted on reuse.
2330 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2331 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2332 } else {
2333 start = entry.range.start;
2334 end = entry.range.end;
2335 }
2336
2337 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2338 ..snapshot.clip_point_utf16(end, Bias::Right);
2339
2340 // Expand empty ranges by one codepoint
2341 if range.start == range.end {
2342 // This will be go to the next boundary when being clipped
2343 range.end.column += 1;
2344 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2345 if range.start == range.end && range.end.column > 0 {
2346 range.start.column -= 1;
2347 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2348 }
2349 }
2350
2351 sanitized_diagnostics.push(DiagnosticEntry {
2352 range,
2353 diagnostic: entry.diagnostic,
2354 });
2355 }
2356 drop(edits_since_save);
2357
2358 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2359 buffer.update(cx, |buffer, cx| {
2360 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2361 self.buffer_pull_diagnostics_result_ids
2362 .entry(server_id)
2363 .or_default()
2364 .insert(abs_path, result_id);
2365 }
2366
2367 buffer.update_diagnostics(server_id, set, cx)
2368 });
2369
2370 Ok(())
2371 }
2372
2373 fn register_language_server_for_invisible_worktree(
2374 &mut self,
2375 worktree: &Entity<Worktree>,
2376 language_server_id: LanguageServerId,
2377 cx: &mut App,
2378 ) {
2379 let worktree = worktree.read(cx);
2380 let worktree_id = worktree.id();
2381 debug_assert!(!worktree.is_visible());
2382 let Some(mut origin_seed) = self
2383 .language_server_ids
2384 .iter()
2385 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2386 else {
2387 return;
2388 };
2389 origin_seed.worktree_id = worktree_id;
2390 self.language_server_ids
2391 .entry(origin_seed)
2392 .or_insert_with(|| UnifiedLanguageServer {
2393 id: language_server_id,
2394 project_roots: Default::default(),
2395 });
2396 }
2397
2398 fn register_buffer_with_language_servers(
2399 &mut self,
2400 buffer_handle: &Entity<Buffer>,
2401 only_register_servers: HashSet<LanguageServerSelector>,
2402 cx: &mut Context<LspStore>,
2403 ) {
2404 let buffer = buffer_handle.read(cx);
2405 let buffer_id = buffer.remote_id();
2406
2407 let Some(file) = File::from_dyn(buffer.file()) else {
2408 return;
2409 };
2410 if !file.is_local() {
2411 return;
2412 }
2413
2414 let abs_path = file.abs_path(cx);
2415 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2416 return;
2417 };
2418 let initial_snapshot = buffer.text_snapshot();
2419 let worktree_id = file.worktree_id(cx);
2420
2421 let Some(language) = buffer.language().cloned() else {
2422 return;
2423 };
2424 let path: Arc<RelPath> = file
2425 .path()
2426 .parent()
2427 .map(Arc::from)
2428 .unwrap_or_else(|| file.path().clone());
2429 let Some(worktree) = self
2430 .worktree_store
2431 .read(cx)
2432 .worktree_for_id(worktree_id, cx)
2433 else {
2434 return;
2435 };
2436 let language_name = language.name();
2437 let (reused, delegate, servers) = self
2438 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2439 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2440 .unwrap_or_else(|| {
2441 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2442 let delegate: Arc<dyn ManifestDelegate> =
2443 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2444
2445 let servers = self
2446 .lsp_tree
2447 .walk(
2448 ProjectPath { worktree_id, path },
2449 language.name(),
2450 language.manifest(),
2451 &delegate,
2452 cx,
2453 )
2454 .collect::<Vec<_>>();
2455 (false, lsp_delegate, servers)
2456 });
2457 let servers_and_adapters = servers
2458 .into_iter()
2459 .filter_map(|server_node| {
2460 if reused && server_node.server_id().is_none() {
2461 return None;
2462 }
2463 if !only_register_servers.is_empty() {
2464 if let Some(server_id) = server_node.server_id()
2465 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2466 {
2467 return None;
2468 }
2469 if let Some(name) = server_node.name()
2470 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2471 {
2472 return None;
2473 }
2474 }
2475
2476 let server_id = server_node.server_id_or_init(|disposition| {
2477 let path = &disposition.path;
2478
2479 {
2480 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2481
2482 let server_id = self.get_or_insert_language_server(
2483 &worktree,
2484 delegate.clone(),
2485 disposition,
2486 &language_name,
2487 cx,
2488 );
2489
2490 if let Some(state) = self.language_servers.get(&server_id)
2491 && let Ok(uri) = uri
2492 {
2493 state.add_workspace_folder(uri);
2494 };
2495 server_id
2496 }
2497 })?;
2498 let server_state = self.language_servers.get(&server_id)?;
2499 if let LanguageServerState::Running {
2500 server, adapter, ..
2501 } = server_state
2502 {
2503 Some((server.clone(), adapter.clone()))
2504 } else {
2505 None
2506 }
2507 })
2508 .collect::<Vec<_>>();
2509 for (server, adapter) in servers_and_adapters {
2510 buffer_handle.update(cx, |buffer, cx| {
2511 buffer.set_completion_triggers(
2512 server.server_id(),
2513 server
2514 .capabilities()
2515 .completion_provider
2516 .as_ref()
2517 .and_then(|provider| {
2518 provider
2519 .trigger_characters
2520 .as_ref()
2521 .map(|characters| characters.iter().cloned().collect())
2522 })
2523 .unwrap_or_default(),
2524 cx,
2525 );
2526 });
2527
2528 let snapshot = LspBufferSnapshot {
2529 version: 0,
2530 snapshot: initial_snapshot.clone(),
2531 };
2532
2533 let mut registered = false;
2534 self.buffer_snapshots
2535 .entry(buffer_id)
2536 .or_default()
2537 .entry(server.server_id())
2538 .or_insert_with(|| {
2539 registered = true;
2540 server.register_buffer(
2541 uri.clone(),
2542 adapter.language_id(&language.name()),
2543 0,
2544 initial_snapshot.text(),
2545 );
2546
2547 vec![snapshot]
2548 });
2549
2550 self.buffers_opened_in_servers
2551 .entry(buffer_id)
2552 .or_default()
2553 .insert(server.server_id());
2554 if registered {
2555 cx.emit(LspStoreEvent::LanguageServerUpdate {
2556 language_server_id: server.server_id(),
2557 name: None,
2558 message: proto::update_language_server::Variant::RegisteredForBuffer(
2559 proto::RegisteredForBuffer {
2560 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2561 buffer_id: buffer_id.to_proto(),
2562 },
2563 ),
2564 });
2565 }
2566 }
2567 }
2568
2569 fn reuse_existing_language_server<'lang_name>(
2570 &self,
2571 server_tree: &LanguageServerTree,
2572 worktree: &Entity<Worktree>,
2573 language_name: &'lang_name LanguageName,
2574 cx: &mut App,
2575 ) -> Option<(
2576 Arc<LocalLspAdapterDelegate>,
2577 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2578 )> {
2579 if worktree.read(cx).is_visible() {
2580 return None;
2581 }
2582
2583 let worktree_store = self.worktree_store.read(cx);
2584 let servers = server_tree
2585 .instances
2586 .iter()
2587 .filter(|(worktree_id, _)| {
2588 worktree_store
2589 .worktree_for_id(**worktree_id, cx)
2590 .is_some_and(|worktree| worktree.read(cx).is_visible())
2591 })
2592 .flat_map(|(worktree_id, servers)| {
2593 servers
2594 .roots
2595 .iter()
2596 .flat_map(|(_, language_servers)| language_servers)
2597 .map(move |(_, (server_node, server_languages))| {
2598 (worktree_id, server_node, server_languages)
2599 })
2600 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2601 .map(|(worktree_id, server_node, _)| {
2602 (
2603 *worktree_id,
2604 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2605 )
2606 })
2607 })
2608 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2609 acc.entry(worktree_id)
2610 .or_insert_with(Vec::new)
2611 .push(server_node);
2612 acc
2613 })
2614 .into_values()
2615 .max_by_key(|servers| servers.len())?;
2616
2617 let worktree_id = worktree.read(cx).id();
2618 let apply = move |tree: &mut LanguageServerTree| {
2619 for server_node in &servers {
2620 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2621 }
2622 servers
2623 };
2624
2625 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2626 Some((delegate, apply))
2627 }
2628
2629 pub(crate) fn unregister_old_buffer_from_language_servers(
2630 &mut self,
2631 buffer: &Entity<Buffer>,
2632 old_file: &File,
2633 cx: &mut App,
2634 ) {
2635 let old_path = match old_file.as_local() {
2636 Some(local) => local.abs_path(cx),
2637 None => return,
2638 };
2639
2640 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2641 debug_panic!("{old_path:?} is not parseable as an URI");
2642 return;
2643 };
2644 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2645 }
2646
2647 pub(crate) fn unregister_buffer_from_language_servers(
2648 &mut self,
2649 buffer: &Entity<Buffer>,
2650 file_url: &lsp::Uri,
2651 cx: &mut App,
2652 ) {
2653 buffer.update(cx, |buffer, cx| {
2654 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2655
2656 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2657 language_server.unregister_buffer(file_url.clone());
2658 }
2659 });
2660 }
2661
2662 fn buffer_snapshot_for_lsp_version(
2663 &mut self,
2664 buffer: &Entity<Buffer>,
2665 server_id: LanguageServerId,
2666 version: Option<i32>,
2667 cx: &App,
2668 ) -> Result<TextBufferSnapshot> {
2669 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2670
2671 if let Some(version) = version {
2672 let buffer_id = buffer.read(cx).remote_id();
2673 let snapshots = if let Some(snapshots) = self
2674 .buffer_snapshots
2675 .get_mut(&buffer_id)
2676 .and_then(|m| m.get_mut(&server_id))
2677 {
2678 snapshots
2679 } else if version == 0 {
2680 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2681 // We detect this case and treat it as if the version was `None`.
2682 return Ok(buffer.read(cx).text_snapshot());
2683 } else {
2684 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2685 };
2686
2687 let found_snapshot = snapshots
2688 .binary_search_by_key(&version, |e| e.version)
2689 .map(|ix| snapshots[ix].snapshot.clone())
2690 .map_err(|_| {
2691 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2692 })?;
2693
2694 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2695 Ok(found_snapshot)
2696 } else {
2697 Ok((buffer.read(cx)).text_snapshot())
2698 }
2699 }
2700
2701 async fn get_server_code_actions_from_action_kinds(
2702 lsp_store: &WeakEntity<LspStore>,
2703 language_server_id: LanguageServerId,
2704 code_action_kinds: Vec<lsp::CodeActionKind>,
2705 buffer: &Entity<Buffer>,
2706 cx: &mut AsyncApp,
2707 ) -> Result<Vec<CodeAction>> {
2708 let actions = lsp_store
2709 .update(cx, move |this, cx| {
2710 let request = GetCodeActions {
2711 range: text::Anchor::MIN..text::Anchor::MAX,
2712 kinds: Some(code_action_kinds),
2713 };
2714 let server = LanguageServerToQuery::Other(language_server_id);
2715 this.request_lsp(buffer.clone(), server, request, cx)
2716 })?
2717 .await?;
2718 Ok(actions)
2719 }
2720
2721 pub async fn execute_code_actions_on_server(
2722 lsp_store: &WeakEntity<LspStore>,
2723 language_server: &Arc<LanguageServer>,
2724
2725 actions: Vec<CodeAction>,
2726 push_to_history: bool,
2727 project_transaction: &mut ProjectTransaction,
2728 cx: &mut AsyncApp,
2729 ) -> anyhow::Result<()> {
2730 for mut action in actions {
2731 Self::try_resolve_code_action(language_server, &mut action)
2732 .await
2733 .context("resolving a formatting code action")?;
2734
2735 if let Some(edit) = action.lsp_action.edit() {
2736 if edit.changes.is_none() && edit.document_changes.is_none() {
2737 continue;
2738 }
2739
2740 let new = Self::deserialize_workspace_edit(
2741 lsp_store.upgrade().context("project dropped")?,
2742 edit.clone(),
2743 push_to_history,
2744 language_server.clone(),
2745 cx,
2746 )
2747 .await?;
2748 project_transaction.0.extend(new.0);
2749 }
2750
2751 if let Some(command) = action.lsp_action.command() {
2752 let server_capabilities = language_server.capabilities();
2753 let available_commands = server_capabilities
2754 .execute_command_provider
2755 .as_ref()
2756 .map(|options| options.commands.as_slice())
2757 .unwrap_or_default();
2758 if available_commands.contains(&command.command) {
2759 lsp_store.update(cx, |lsp_store, _| {
2760 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2761 mode.last_workspace_edits_by_language_server
2762 .remove(&language_server.server_id());
2763 }
2764 })?;
2765
2766 language_server
2767 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2768 command: command.command.clone(),
2769 arguments: command.arguments.clone().unwrap_or_default(),
2770 ..Default::default()
2771 })
2772 .await
2773 .into_response()
2774 .context("execute command")?;
2775
2776 lsp_store.update(cx, |this, _| {
2777 if let LspStoreMode::Local(mode) = &mut this.mode {
2778 project_transaction.0.extend(
2779 mode.last_workspace_edits_by_language_server
2780 .remove(&language_server.server_id())
2781 .unwrap_or_default()
2782 .0,
2783 )
2784 }
2785 })?;
2786 } else {
2787 log::warn!(
2788 "Cannot execute a command {} not listed in the language server capabilities",
2789 command.command
2790 )
2791 }
2792 }
2793 }
2794 Ok(())
2795 }
2796
2797 pub async fn deserialize_text_edits(
2798 this: Entity<LspStore>,
2799 buffer_to_edit: Entity<Buffer>,
2800 edits: Vec<lsp::TextEdit>,
2801 push_to_history: bool,
2802 _: Arc<CachedLspAdapter>,
2803 language_server: Arc<LanguageServer>,
2804 cx: &mut AsyncApp,
2805 ) -> Result<Option<Transaction>> {
2806 let edits = this
2807 .update(cx, |this, cx| {
2808 this.as_local_mut().unwrap().edits_from_lsp(
2809 &buffer_to_edit,
2810 edits,
2811 language_server.server_id(),
2812 None,
2813 cx,
2814 )
2815 })?
2816 .await?;
2817
2818 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2819 buffer.finalize_last_transaction();
2820 buffer.start_transaction();
2821 for (range, text) in edits {
2822 buffer.edit([(range, text)], None, cx);
2823 }
2824
2825 if buffer.end_transaction(cx).is_some() {
2826 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2827 if !push_to_history {
2828 buffer.forget_transaction(transaction.id);
2829 }
2830 Some(transaction)
2831 } else {
2832 None
2833 }
2834 })?;
2835
2836 Ok(transaction)
2837 }
2838
2839 #[allow(clippy::type_complexity)]
2840 pub(crate) fn edits_from_lsp(
2841 &mut self,
2842 buffer: &Entity<Buffer>,
2843 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2844 server_id: LanguageServerId,
2845 version: Option<i32>,
2846 cx: &mut Context<LspStore>,
2847 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2848 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2849 cx.background_spawn(async move {
2850 let snapshot = snapshot?;
2851 let mut lsp_edits = lsp_edits
2852 .into_iter()
2853 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2854 .collect::<Vec<_>>();
2855
2856 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2857
2858 let mut lsp_edits = lsp_edits.into_iter().peekable();
2859 let mut edits = Vec::new();
2860 while let Some((range, mut new_text)) = lsp_edits.next() {
2861 // Clip invalid ranges provided by the language server.
2862 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2863 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2864
2865 // Combine any LSP edits that are adjacent.
2866 //
2867 // Also, combine LSP edits that are separated from each other by only
2868 // a newline. This is important because for some code actions,
2869 // Rust-analyzer rewrites the entire buffer via a series of edits that
2870 // are separated by unchanged newline characters.
2871 //
2872 // In order for the diffing logic below to work properly, any edits that
2873 // cancel each other out must be combined into one.
2874 while let Some((next_range, next_text)) = lsp_edits.peek() {
2875 if next_range.start.0 > range.end {
2876 if next_range.start.0.row > range.end.row + 1
2877 || next_range.start.0.column > 0
2878 || snapshot.clip_point_utf16(
2879 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2880 Bias::Left,
2881 ) > range.end
2882 {
2883 break;
2884 }
2885 new_text.push('\n');
2886 }
2887 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2888 new_text.push_str(next_text);
2889 lsp_edits.next();
2890 }
2891
2892 // For multiline edits, perform a diff of the old and new text so that
2893 // we can identify the changes more precisely, preserving the locations
2894 // of any anchors positioned in the unchanged regions.
2895 if range.end.row > range.start.row {
2896 let offset = range.start.to_offset(&snapshot);
2897 let old_text = snapshot.text_for_range(range).collect::<String>();
2898 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2899 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2900 (
2901 snapshot.anchor_after(offset + range.start)
2902 ..snapshot.anchor_before(offset + range.end),
2903 replacement,
2904 )
2905 }));
2906 } else if range.end == range.start {
2907 let anchor = snapshot.anchor_after(range.start);
2908 edits.push((anchor..anchor, new_text.into()));
2909 } else {
2910 let edit_start = snapshot.anchor_after(range.start);
2911 let edit_end = snapshot.anchor_before(range.end);
2912 edits.push((edit_start..edit_end, new_text.into()));
2913 }
2914 }
2915
2916 Ok(edits)
2917 })
2918 }
2919
2920 pub(crate) async fn deserialize_workspace_edit(
2921 this: Entity<LspStore>,
2922 edit: lsp::WorkspaceEdit,
2923 push_to_history: bool,
2924 language_server: Arc<LanguageServer>,
2925 cx: &mut AsyncApp,
2926 ) -> Result<ProjectTransaction> {
2927 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2928
2929 let mut operations = Vec::new();
2930 if let Some(document_changes) = edit.document_changes {
2931 match document_changes {
2932 lsp::DocumentChanges::Edits(edits) => {
2933 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2934 }
2935 lsp::DocumentChanges::Operations(ops) => operations = ops,
2936 }
2937 } else if let Some(changes) = edit.changes {
2938 operations.extend(changes.into_iter().map(|(uri, edits)| {
2939 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2940 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2941 uri,
2942 version: None,
2943 },
2944 edits: edits.into_iter().map(Edit::Plain).collect(),
2945 })
2946 }));
2947 }
2948
2949 let mut project_transaction = ProjectTransaction::default();
2950 for operation in operations {
2951 match operation {
2952 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2953 let abs_path = op
2954 .uri
2955 .to_file_path()
2956 .map_err(|()| anyhow!("can't convert URI to path"))?;
2957
2958 if let Some(parent_path) = abs_path.parent() {
2959 fs.create_dir(parent_path).await?;
2960 }
2961 if abs_path.ends_with("/") {
2962 fs.create_dir(&abs_path).await?;
2963 } else {
2964 fs.create_file(
2965 &abs_path,
2966 op.options
2967 .map(|options| fs::CreateOptions {
2968 overwrite: options.overwrite.unwrap_or(false),
2969 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2970 })
2971 .unwrap_or_default(),
2972 )
2973 .await?;
2974 }
2975 }
2976
2977 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2978 let source_abs_path = op
2979 .old_uri
2980 .to_file_path()
2981 .map_err(|()| anyhow!("can't convert URI to path"))?;
2982 let target_abs_path = op
2983 .new_uri
2984 .to_file_path()
2985 .map_err(|()| anyhow!("can't convert URI to path"))?;
2986 fs.rename(
2987 &source_abs_path,
2988 &target_abs_path,
2989 op.options
2990 .map(|options| fs::RenameOptions {
2991 overwrite: options.overwrite.unwrap_or(false),
2992 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2993 })
2994 .unwrap_or_default(),
2995 )
2996 .await?;
2997 }
2998
2999 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3000 let abs_path = op
3001 .uri
3002 .to_file_path()
3003 .map_err(|()| anyhow!("can't convert URI to path"))?;
3004 let options = op
3005 .options
3006 .map(|options| fs::RemoveOptions {
3007 recursive: options.recursive.unwrap_or(false),
3008 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3009 })
3010 .unwrap_or_default();
3011 if abs_path.ends_with("/") {
3012 fs.remove_dir(&abs_path, options).await?;
3013 } else {
3014 fs.remove_file(&abs_path, options).await?;
3015 }
3016 }
3017
3018 lsp::DocumentChangeOperation::Edit(op) => {
3019 let buffer_to_edit = this
3020 .update(cx, |this, cx| {
3021 this.open_local_buffer_via_lsp(
3022 op.text_document.uri.clone(),
3023 language_server.server_id(),
3024 cx,
3025 )
3026 })?
3027 .await?;
3028
3029 let edits = this
3030 .update(cx, |this, cx| {
3031 let path = buffer_to_edit.read(cx).project_path(cx);
3032 let active_entry = this.active_entry;
3033 let is_active_entry = path.is_some_and(|project_path| {
3034 this.worktree_store
3035 .read(cx)
3036 .entry_for_path(&project_path, cx)
3037 .is_some_and(|entry| Some(entry.id) == active_entry)
3038 });
3039 let local = this.as_local_mut().unwrap();
3040
3041 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3042 for edit in op.edits {
3043 match edit {
3044 Edit::Plain(edit) => {
3045 if !edits.contains(&edit) {
3046 edits.push(edit)
3047 }
3048 }
3049 Edit::Annotated(edit) => {
3050 if !edits.contains(&edit.text_edit) {
3051 edits.push(edit.text_edit)
3052 }
3053 }
3054 Edit::Snippet(edit) => {
3055 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3056 else {
3057 continue;
3058 };
3059
3060 if is_active_entry {
3061 snippet_edits.push((edit.range, snippet));
3062 } else {
3063 // Since this buffer is not focused, apply a normal edit.
3064 let new_edit = TextEdit {
3065 range: edit.range,
3066 new_text: snippet.text,
3067 };
3068 if !edits.contains(&new_edit) {
3069 edits.push(new_edit);
3070 }
3071 }
3072 }
3073 }
3074 }
3075 if !snippet_edits.is_empty() {
3076 let buffer_id = buffer_to_edit.read(cx).remote_id();
3077 let version = if let Some(buffer_version) = op.text_document.version
3078 {
3079 local
3080 .buffer_snapshot_for_lsp_version(
3081 &buffer_to_edit,
3082 language_server.server_id(),
3083 Some(buffer_version),
3084 cx,
3085 )
3086 .ok()
3087 .map(|snapshot| snapshot.version)
3088 } else {
3089 Some(buffer_to_edit.read(cx).saved_version().clone())
3090 };
3091
3092 let most_recent_edit =
3093 version.and_then(|version| version.most_recent());
3094 // Check if the edit that triggered that edit has been made by this participant.
3095
3096 if let Some(most_recent_edit) = most_recent_edit {
3097 cx.emit(LspStoreEvent::SnippetEdit {
3098 buffer_id,
3099 edits: snippet_edits,
3100 most_recent_edit,
3101 });
3102 }
3103 }
3104
3105 local.edits_from_lsp(
3106 &buffer_to_edit,
3107 edits,
3108 language_server.server_id(),
3109 op.text_document.version,
3110 cx,
3111 )
3112 })?
3113 .await?;
3114
3115 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3116 buffer.finalize_last_transaction();
3117 buffer.start_transaction();
3118 for (range, text) in edits {
3119 buffer.edit([(range, text)], None, cx);
3120 }
3121
3122 buffer.end_transaction(cx).and_then(|transaction_id| {
3123 if push_to_history {
3124 buffer.finalize_last_transaction();
3125 buffer.get_transaction(transaction_id).cloned()
3126 } else {
3127 buffer.forget_transaction(transaction_id)
3128 }
3129 })
3130 })?;
3131 if let Some(transaction) = transaction {
3132 project_transaction.0.insert(buffer_to_edit, transaction);
3133 }
3134 }
3135 }
3136 }
3137
3138 Ok(project_transaction)
3139 }
3140
3141 async fn on_lsp_workspace_edit(
3142 this: WeakEntity<LspStore>,
3143 params: lsp::ApplyWorkspaceEditParams,
3144 server_id: LanguageServerId,
3145 cx: &mut AsyncApp,
3146 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3147 let this = this.upgrade().context("project project closed")?;
3148 let language_server = this
3149 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3150 .context("language server not found")?;
3151 let transaction = Self::deserialize_workspace_edit(
3152 this.clone(),
3153 params.edit,
3154 true,
3155 language_server.clone(),
3156 cx,
3157 )
3158 .await
3159 .log_err();
3160 this.update(cx, |this, _| {
3161 if let Some(transaction) = transaction {
3162 this.as_local_mut()
3163 .unwrap()
3164 .last_workspace_edits_by_language_server
3165 .insert(server_id, transaction);
3166 }
3167 })?;
3168 Ok(lsp::ApplyWorkspaceEditResponse {
3169 applied: true,
3170 failed_change: None,
3171 failure_reason: None,
3172 })
3173 }
3174
3175 fn remove_worktree(
3176 &mut self,
3177 id_to_remove: WorktreeId,
3178 cx: &mut Context<LspStore>,
3179 ) -> Vec<LanguageServerId> {
3180 self.diagnostics.remove(&id_to_remove);
3181 self.prettier_store.update(cx, |prettier_store, cx| {
3182 prettier_store.remove_worktree(id_to_remove, cx);
3183 });
3184
3185 let mut servers_to_remove = BTreeSet::default();
3186 let mut servers_to_preserve = HashSet::default();
3187 for (seed, state) in &self.language_server_ids {
3188 if seed.worktree_id == id_to_remove {
3189 servers_to_remove.insert(state.id);
3190 } else {
3191 servers_to_preserve.insert(state.id);
3192 }
3193 }
3194 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3195 self.language_server_ids
3196 .retain(|_, state| !servers_to_remove.contains(&state.id));
3197 for server_id_to_remove in &servers_to_remove {
3198 self.language_server_watched_paths
3199 .remove(server_id_to_remove);
3200 self.language_server_paths_watched_for_rename
3201 .remove(server_id_to_remove);
3202 self.last_workspace_edits_by_language_server
3203 .remove(server_id_to_remove);
3204 self.language_servers.remove(server_id_to_remove);
3205 self.buffer_pull_diagnostics_result_ids
3206 .remove(server_id_to_remove);
3207 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3208 buffer_servers.remove(server_id_to_remove);
3209 }
3210 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3211 }
3212 servers_to_remove.into_iter().collect()
3213 }
3214
3215 fn rebuild_watched_paths_inner<'a>(
3216 &'a self,
3217 language_server_id: LanguageServerId,
3218 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3219 cx: &mut Context<LspStore>,
3220 ) -> LanguageServerWatchedPathsBuilder {
3221 let worktrees = self
3222 .worktree_store
3223 .read(cx)
3224 .worktrees()
3225 .filter_map(|worktree| {
3226 self.language_servers_for_worktree(worktree.read(cx).id())
3227 .find(|server| server.server_id() == language_server_id)
3228 .map(|_| worktree)
3229 })
3230 .collect::<Vec<_>>();
3231
3232 let mut worktree_globs = HashMap::default();
3233 let mut abs_globs = HashMap::default();
3234 log::trace!(
3235 "Processing new watcher paths for language server with id {}",
3236 language_server_id
3237 );
3238
3239 for watcher in watchers {
3240 if let Some((worktree, literal_prefix, pattern)) =
3241 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3242 {
3243 worktree.update(cx, |worktree, _| {
3244 if let Some((tree, glob)) =
3245 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3246 {
3247 tree.add_path_prefix_to_scan(literal_prefix);
3248 worktree_globs
3249 .entry(tree.id())
3250 .or_insert_with(GlobSetBuilder::new)
3251 .add(glob);
3252 }
3253 });
3254 } else {
3255 let (path, pattern) = match &watcher.glob_pattern {
3256 lsp::GlobPattern::String(s) => {
3257 let watcher_path = SanitizedPath::new(s);
3258 let path = glob_literal_prefix(watcher_path.as_path());
3259 let pattern = watcher_path
3260 .as_path()
3261 .strip_prefix(&path)
3262 .map(|p| p.to_string_lossy().into_owned())
3263 .unwrap_or_else(|e| {
3264 debug_panic!(
3265 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3266 s,
3267 path.display(),
3268 e
3269 );
3270 watcher_path.as_path().to_string_lossy().into_owned()
3271 });
3272 (path, pattern)
3273 }
3274 lsp::GlobPattern::Relative(rp) => {
3275 let Ok(mut base_uri) = match &rp.base_uri {
3276 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3277 lsp::OneOf::Right(base_uri) => base_uri,
3278 }
3279 .to_file_path() else {
3280 continue;
3281 };
3282
3283 let path = glob_literal_prefix(Path::new(&rp.pattern));
3284 let pattern = Path::new(&rp.pattern)
3285 .strip_prefix(&path)
3286 .map(|p| p.to_string_lossy().into_owned())
3287 .unwrap_or_else(|e| {
3288 debug_panic!(
3289 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3290 rp.pattern,
3291 path.display(),
3292 e
3293 );
3294 rp.pattern.clone()
3295 });
3296 base_uri.push(path);
3297 (base_uri, pattern)
3298 }
3299 };
3300
3301 if let Some(glob) = Glob::new(&pattern).log_err() {
3302 if !path
3303 .components()
3304 .any(|c| matches!(c, path::Component::Normal(_)))
3305 {
3306 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3307 // rather than adding a new watcher for `/`.
3308 for worktree in &worktrees {
3309 worktree_globs
3310 .entry(worktree.read(cx).id())
3311 .or_insert_with(GlobSetBuilder::new)
3312 .add(glob.clone());
3313 }
3314 } else {
3315 abs_globs
3316 .entry(path.into())
3317 .or_insert_with(GlobSetBuilder::new)
3318 .add(glob);
3319 }
3320 }
3321 }
3322 }
3323
3324 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3325 for (worktree_id, builder) in worktree_globs {
3326 if let Ok(globset) = builder.build() {
3327 watch_builder.watch_worktree(worktree_id, globset);
3328 }
3329 }
3330 for (abs_path, builder) in abs_globs {
3331 if let Ok(globset) = builder.build() {
3332 watch_builder.watch_abs_path(abs_path, globset);
3333 }
3334 }
3335 watch_builder
3336 }
3337
3338 fn worktree_and_path_for_file_watcher(
3339 worktrees: &[Entity<Worktree>],
3340 watcher: &FileSystemWatcher,
3341 cx: &App,
3342 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3343 worktrees.iter().find_map(|worktree| {
3344 let tree = worktree.read(cx);
3345 let worktree_root_path = tree.abs_path();
3346 let path_style = tree.path_style();
3347 match &watcher.glob_pattern {
3348 lsp::GlobPattern::String(s) => {
3349 let watcher_path = SanitizedPath::new(s);
3350 let relative = watcher_path
3351 .as_path()
3352 .strip_prefix(&worktree_root_path)
3353 .ok()?;
3354 let literal_prefix = glob_literal_prefix(relative);
3355 Some((
3356 worktree.clone(),
3357 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3358 relative.to_string_lossy().into_owned(),
3359 ))
3360 }
3361 lsp::GlobPattern::Relative(rp) => {
3362 let base_uri = match &rp.base_uri {
3363 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3364 lsp::OneOf::Right(base_uri) => base_uri,
3365 }
3366 .to_file_path()
3367 .ok()?;
3368 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3369 let mut literal_prefix = relative.to_owned();
3370 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3371 Some((
3372 worktree.clone(),
3373 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3374 rp.pattern.clone(),
3375 ))
3376 }
3377 }
3378 })
3379 }
3380
3381 fn rebuild_watched_paths(
3382 &mut self,
3383 language_server_id: LanguageServerId,
3384 cx: &mut Context<LspStore>,
3385 ) {
3386 let Some(registrations) = self
3387 .language_server_dynamic_registrations
3388 .get(&language_server_id)
3389 else {
3390 return;
3391 };
3392
3393 let watch_builder = self.rebuild_watched_paths_inner(
3394 language_server_id,
3395 registrations.did_change_watched_files.values().flatten(),
3396 cx,
3397 );
3398 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3399 self.language_server_watched_paths
3400 .insert(language_server_id, watcher);
3401
3402 cx.notify();
3403 }
3404
3405 fn on_lsp_did_change_watched_files(
3406 &mut self,
3407 language_server_id: LanguageServerId,
3408 registration_id: &str,
3409 params: DidChangeWatchedFilesRegistrationOptions,
3410 cx: &mut Context<LspStore>,
3411 ) {
3412 let registrations = self
3413 .language_server_dynamic_registrations
3414 .entry(language_server_id)
3415 .or_default();
3416
3417 registrations
3418 .did_change_watched_files
3419 .insert(registration_id.to_string(), params.watchers);
3420
3421 self.rebuild_watched_paths(language_server_id, cx);
3422 }
3423
3424 fn on_lsp_unregister_did_change_watched_files(
3425 &mut self,
3426 language_server_id: LanguageServerId,
3427 registration_id: &str,
3428 cx: &mut Context<LspStore>,
3429 ) {
3430 let registrations = self
3431 .language_server_dynamic_registrations
3432 .entry(language_server_id)
3433 .or_default();
3434
3435 if registrations
3436 .did_change_watched_files
3437 .remove(registration_id)
3438 .is_some()
3439 {
3440 log::info!(
3441 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3442 language_server_id,
3443 registration_id
3444 );
3445 } else {
3446 log::warn!(
3447 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3448 language_server_id,
3449 registration_id
3450 );
3451 }
3452
3453 self.rebuild_watched_paths(language_server_id, cx);
3454 }
3455
3456 async fn initialization_options_for_adapter(
3457 adapter: Arc<dyn LspAdapter>,
3458 delegate: &Arc<dyn LspAdapterDelegate>,
3459 ) -> Result<Option<serde_json::Value>> {
3460 let Some(mut initialization_config) =
3461 adapter.clone().initialization_options(delegate).await?
3462 else {
3463 return Ok(None);
3464 };
3465
3466 for other_adapter in delegate.registered_lsp_adapters() {
3467 if other_adapter.name() == adapter.name() {
3468 continue;
3469 }
3470 if let Ok(Some(target_config)) = other_adapter
3471 .clone()
3472 .additional_initialization_options(adapter.name(), delegate)
3473 .await
3474 {
3475 merge_json_value_into(target_config.clone(), &mut initialization_config);
3476 }
3477 }
3478
3479 Ok(Some(initialization_config))
3480 }
3481
3482 async fn workspace_configuration_for_adapter(
3483 adapter: Arc<dyn LspAdapter>,
3484 delegate: &Arc<dyn LspAdapterDelegate>,
3485 toolchain: Option<Toolchain>,
3486 cx: &mut AsyncApp,
3487 ) -> Result<serde_json::Value> {
3488 let mut workspace_config = adapter
3489 .clone()
3490 .workspace_configuration(delegate, toolchain, cx)
3491 .await?;
3492
3493 for other_adapter in delegate.registered_lsp_adapters() {
3494 if other_adapter.name() == adapter.name() {
3495 continue;
3496 }
3497 if let Ok(Some(target_config)) = other_adapter
3498 .clone()
3499 .additional_workspace_configuration(adapter.name(), delegate, cx)
3500 .await
3501 {
3502 merge_json_value_into(target_config.clone(), &mut workspace_config);
3503 }
3504 }
3505
3506 Ok(workspace_config)
3507 }
3508
3509 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3510 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3511 Some(server.clone())
3512 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3513 Some(Arc::clone(server))
3514 } else {
3515 None
3516 }
3517 }
3518}
3519
3520fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3521 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3522 cx.emit(LspStoreEvent::LanguageServerUpdate {
3523 language_server_id: server.server_id(),
3524 name: Some(server.name()),
3525 message: proto::update_language_server::Variant::MetadataUpdated(
3526 proto::ServerMetadataUpdated {
3527 capabilities: Some(capabilities),
3528 },
3529 ),
3530 });
3531 }
3532}
3533
3534#[derive(Debug)]
3535pub struct FormattableBuffer {
3536 handle: Entity<Buffer>,
3537 abs_path: Option<PathBuf>,
3538 env: Option<HashMap<String, String>>,
3539 ranges: Option<Vec<Range<Anchor>>>,
3540}
3541
3542pub struct RemoteLspStore {
3543 upstream_client: Option<AnyProtoClient>,
3544 upstream_project_id: u64,
3545}
3546
3547pub(crate) enum LspStoreMode {
3548 Local(LocalLspStore), // ssh host and collab host
3549 Remote(RemoteLspStore), // collab guest
3550}
3551
3552impl LspStoreMode {
3553 fn is_local(&self) -> bool {
3554 matches!(self, LspStoreMode::Local(_))
3555 }
3556}
3557
3558pub struct LspStore {
3559 mode: LspStoreMode,
3560 last_formatting_failure: Option<String>,
3561 downstream_client: Option<(AnyProtoClient, u64)>,
3562 nonce: u128,
3563 buffer_store: Entity<BufferStore>,
3564 worktree_store: Entity<WorktreeStore>,
3565 pub languages: Arc<LanguageRegistry>,
3566 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3567 active_entry: Option<ProjectEntryId>,
3568 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3569 _maintain_buffer_languages: Task<()>,
3570 diagnostic_summaries:
3571 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3572 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3573 lsp_data: HashMap<BufferId, BufferLspData>,
3574 next_hint_id: Arc<AtomicUsize>,
3575}
3576
3577#[derive(Debug)]
3578pub struct BufferLspData {
3579 buffer_version: Global,
3580 document_colors: Option<DocumentColorData>,
3581 code_lens: Option<CodeLensData>,
3582 inlay_hints: BufferInlayHints,
3583 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3584 chunk_lsp_requests: HashMap<LspKey, HashMap<BufferChunk, LspRequestId>>,
3585}
3586
3587#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3588struct LspKey {
3589 request_type: TypeId,
3590 server_queried: Option<LanguageServerId>,
3591}
3592
3593impl BufferLspData {
3594 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3595 Self {
3596 buffer_version: buffer.read(cx).version(),
3597 document_colors: None,
3598 code_lens: None,
3599 inlay_hints: BufferInlayHints::new(buffer, cx),
3600 lsp_requests: HashMap::default(),
3601 chunk_lsp_requests: HashMap::default(),
3602 }
3603 }
3604
3605 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3606 if let Some(document_colors) = &mut self.document_colors {
3607 document_colors.colors.remove(&for_server);
3608 document_colors.cache_version += 1;
3609 }
3610
3611 if let Some(code_lens) = &mut self.code_lens {
3612 code_lens.lens.remove(&for_server);
3613 }
3614
3615 self.inlay_hints.remove_server_data(for_server);
3616 }
3617
3618 #[cfg(any(test, feature = "test-support"))]
3619 pub fn inlay_hints(&self) -> &BufferInlayHints {
3620 &self.inlay_hints
3621 }
3622}
3623
3624#[derive(Debug, Default, Clone)]
3625pub struct DocumentColors {
3626 pub colors: HashSet<DocumentColor>,
3627 pub cache_version: Option<usize>,
3628}
3629
3630type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3631type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3632
3633#[derive(Debug, Default)]
3634struct DocumentColorData {
3635 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3636 cache_version: usize,
3637 colors_update: Option<(Global, DocumentColorTask)>,
3638}
3639
3640#[derive(Debug, Default)]
3641struct CodeLensData {
3642 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3643 update: Option<(Global, CodeLensTask)>,
3644}
3645
3646#[derive(Debug)]
3647pub enum LspStoreEvent {
3648 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3649 LanguageServerRemoved(LanguageServerId),
3650 LanguageServerUpdate {
3651 language_server_id: LanguageServerId,
3652 name: Option<LanguageServerName>,
3653 message: proto::update_language_server::Variant,
3654 },
3655 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3656 LanguageServerPrompt(LanguageServerPromptRequest),
3657 LanguageDetected {
3658 buffer: Entity<Buffer>,
3659 new_language: Option<Arc<Language>>,
3660 },
3661 Notification(String),
3662 RefreshInlayHints(LanguageServerId),
3663 RefreshCodeLens,
3664 DiagnosticsUpdated {
3665 server_id: LanguageServerId,
3666 paths: Vec<ProjectPath>,
3667 },
3668 DiskBasedDiagnosticsStarted {
3669 language_server_id: LanguageServerId,
3670 },
3671 DiskBasedDiagnosticsFinished {
3672 language_server_id: LanguageServerId,
3673 },
3674 SnippetEdit {
3675 buffer_id: BufferId,
3676 edits: Vec<(lsp::Range, Snippet)>,
3677 most_recent_edit: clock::Lamport,
3678 },
3679}
3680
3681#[derive(Clone, Debug, Serialize)]
3682pub struct LanguageServerStatus {
3683 pub name: LanguageServerName,
3684 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3685 pub has_pending_diagnostic_updates: bool,
3686 progress_tokens: HashSet<ProgressToken>,
3687 pub worktree: Option<WorktreeId>,
3688}
3689
3690#[derive(Clone, Debug)]
3691struct CoreSymbol {
3692 pub language_server_name: LanguageServerName,
3693 pub source_worktree_id: WorktreeId,
3694 pub source_language_server_id: LanguageServerId,
3695 pub path: SymbolLocation,
3696 pub name: String,
3697 pub kind: lsp::SymbolKind,
3698 pub range: Range<Unclipped<PointUtf16>>,
3699}
3700
3701#[derive(Clone, Debug, PartialEq, Eq)]
3702pub enum SymbolLocation {
3703 InProject(ProjectPath),
3704 OutsideProject {
3705 abs_path: Arc<Path>,
3706 signature: [u8; 32],
3707 },
3708}
3709
3710impl SymbolLocation {
3711 fn file_name(&self) -> Option<&str> {
3712 match self {
3713 Self::InProject(path) => path.path.file_name(),
3714 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3715 }
3716 }
3717}
3718
3719impl LspStore {
3720 pub fn init(client: &AnyProtoClient) {
3721 client.add_entity_request_handler(Self::handle_lsp_query);
3722 client.add_entity_message_handler(Self::handle_lsp_query_response);
3723 client.add_entity_request_handler(Self::handle_restart_language_servers);
3724 client.add_entity_request_handler(Self::handle_stop_language_servers);
3725 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3726 client.add_entity_message_handler(Self::handle_start_language_server);
3727 client.add_entity_message_handler(Self::handle_update_language_server);
3728 client.add_entity_message_handler(Self::handle_language_server_log);
3729 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3730 client.add_entity_request_handler(Self::handle_format_buffers);
3731 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3732 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3733 client.add_entity_request_handler(Self::handle_apply_code_action);
3734 client.add_entity_request_handler(Self::handle_get_project_symbols);
3735 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3736 client.add_entity_request_handler(Self::handle_get_color_presentation);
3737 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3738 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3739 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3740 client.add_entity_request_handler(Self::handle_on_type_formatting);
3741 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3742 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3743 client.add_entity_request_handler(Self::handle_rename_project_entry);
3744 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3745 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3746 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3747 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3748 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3749 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3750 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3751
3752 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3753 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3754 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3755 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3756 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3757 client.add_entity_request_handler(
3758 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3759 );
3760 client.add_entity_request_handler(
3761 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3762 );
3763 client.add_entity_request_handler(
3764 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3765 );
3766 }
3767
3768 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3769 match &self.mode {
3770 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3771 _ => None,
3772 }
3773 }
3774
3775 pub fn as_local(&self) -> Option<&LocalLspStore> {
3776 match &self.mode {
3777 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3778 _ => None,
3779 }
3780 }
3781
3782 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3783 match &mut self.mode {
3784 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3785 _ => None,
3786 }
3787 }
3788
3789 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3790 match &self.mode {
3791 LspStoreMode::Remote(RemoteLspStore {
3792 upstream_client: Some(upstream_client),
3793 upstream_project_id,
3794 ..
3795 }) => Some((upstream_client.clone(), *upstream_project_id)),
3796
3797 LspStoreMode::Remote(RemoteLspStore {
3798 upstream_client: None,
3799 ..
3800 }) => None,
3801 LspStoreMode::Local(_) => None,
3802 }
3803 }
3804
3805 pub fn new_local(
3806 buffer_store: Entity<BufferStore>,
3807 worktree_store: Entity<WorktreeStore>,
3808 prettier_store: Entity<PrettierStore>,
3809 toolchain_store: Entity<LocalToolchainStore>,
3810 environment: Entity<ProjectEnvironment>,
3811 manifest_tree: Entity<ManifestTree>,
3812 languages: Arc<LanguageRegistry>,
3813 http_client: Arc<dyn HttpClient>,
3814 fs: Arc<dyn Fs>,
3815 cx: &mut Context<Self>,
3816 ) -> Self {
3817 let yarn = YarnPathStore::new(fs.clone(), cx);
3818 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3819 .detach();
3820 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3821 .detach();
3822 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3823 .detach();
3824 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3825 .detach();
3826 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3827 .detach();
3828 subscribe_to_binary_statuses(&languages, cx).detach();
3829
3830 let _maintain_workspace_config = {
3831 let (sender, receiver) = watch::channel();
3832 (Self::maintain_workspace_config(receiver, cx), sender)
3833 };
3834
3835 Self {
3836 mode: LspStoreMode::Local(LocalLspStore {
3837 weak: cx.weak_entity(),
3838 worktree_store: worktree_store.clone(),
3839
3840 supplementary_language_servers: Default::default(),
3841 languages: languages.clone(),
3842 language_server_ids: Default::default(),
3843 language_servers: Default::default(),
3844 last_workspace_edits_by_language_server: Default::default(),
3845 language_server_watched_paths: Default::default(),
3846 language_server_paths_watched_for_rename: Default::default(),
3847 language_server_dynamic_registrations: Default::default(),
3848 buffers_being_formatted: Default::default(),
3849 buffer_snapshots: Default::default(),
3850 prettier_store,
3851 environment,
3852 http_client,
3853 fs,
3854 yarn,
3855 next_diagnostic_group_id: Default::default(),
3856 diagnostics: Default::default(),
3857 _subscription: cx.on_app_quit(|this, cx| {
3858 this.as_local_mut()
3859 .unwrap()
3860 .shutdown_language_servers_on_quit(cx)
3861 }),
3862 lsp_tree: LanguageServerTree::new(
3863 manifest_tree,
3864 languages.clone(),
3865 toolchain_store.clone(),
3866 ),
3867 toolchain_store,
3868 registered_buffers: HashMap::default(),
3869 buffers_opened_in_servers: HashMap::default(),
3870 buffer_pull_diagnostics_result_ids: HashMap::default(),
3871 watched_manifest_filenames: ManifestProvidersStore::global(cx)
3872 .manifest_file_names(),
3873 }),
3874 last_formatting_failure: None,
3875 downstream_client: None,
3876 buffer_store,
3877 worktree_store,
3878 languages: languages.clone(),
3879 language_server_statuses: Default::default(),
3880 nonce: StdRng::from_os_rng().random(),
3881 diagnostic_summaries: HashMap::default(),
3882 lsp_server_capabilities: HashMap::default(),
3883 lsp_data: HashMap::default(),
3884 next_hint_id: Arc::default(),
3885 active_entry: None,
3886 _maintain_workspace_config,
3887 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3888 }
3889 }
3890
3891 fn send_lsp_proto_request<R: LspCommand>(
3892 &self,
3893 buffer: Entity<Buffer>,
3894 client: AnyProtoClient,
3895 upstream_project_id: u64,
3896 request: R,
3897 cx: &mut Context<LspStore>,
3898 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3899 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3900 return Task::ready(Ok(R::Response::default()));
3901 }
3902 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3903 cx.spawn(async move |this, cx| {
3904 let response = client.request(message).await?;
3905 let this = this.upgrade().context("project dropped")?;
3906 request
3907 .response_from_proto(response, this, buffer, cx.clone())
3908 .await
3909 })
3910 }
3911
3912 pub(super) fn new_remote(
3913 buffer_store: Entity<BufferStore>,
3914 worktree_store: Entity<WorktreeStore>,
3915 languages: Arc<LanguageRegistry>,
3916 upstream_client: AnyProtoClient,
3917 project_id: u64,
3918 cx: &mut Context<Self>,
3919 ) -> Self {
3920 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3921 .detach();
3922 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3923 .detach();
3924 subscribe_to_binary_statuses(&languages, cx).detach();
3925 let _maintain_workspace_config = {
3926 let (sender, receiver) = watch::channel();
3927 (Self::maintain_workspace_config(receiver, cx), sender)
3928 };
3929 Self {
3930 mode: LspStoreMode::Remote(RemoteLspStore {
3931 upstream_client: Some(upstream_client),
3932 upstream_project_id: project_id,
3933 }),
3934 downstream_client: None,
3935 last_formatting_failure: None,
3936 buffer_store,
3937 worktree_store,
3938 languages: languages.clone(),
3939 language_server_statuses: Default::default(),
3940 nonce: StdRng::from_os_rng().random(),
3941 diagnostic_summaries: HashMap::default(),
3942 lsp_server_capabilities: HashMap::default(),
3943 next_hint_id: Arc::default(),
3944 lsp_data: HashMap::default(),
3945 active_entry: None,
3946
3947 _maintain_workspace_config,
3948 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3949 }
3950 }
3951
3952 fn on_buffer_store_event(
3953 &mut self,
3954 _: Entity<BufferStore>,
3955 event: &BufferStoreEvent,
3956 cx: &mut Context<Self>,
3957 ) {
3958 match event {
3959 BufferStoreEvent::BufferAdded(buffer) => {
3960 self.on_buffer_added(buffer, cx).log_err();
3961 }
3962 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3963 let buffer_id = buffer.read(cx).remote_id();
3964 if let Some(local) = self.as_local_mut()
3965 && let Some(old_file) = File::from_dyn(old_file.as_ref())
3966 {
3967 local.reset_buffer(buffer, old_file, cx);
3968
3969 if local.registered_buffers.contains_key(&buffer_id) {
3970 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3971 }
3972 }
3973
3974 self.detect_language_for_buffer(buffer, cx);
3975 if let Some(local) = self.as_local_mut() {
3976 local.initialize_buffer(buffer, cx);
3977 if local.registered_buffers.contains_key(&buffer_id) {
3978 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3979 }
3980 }
3981 }
3982 _ => {}
3983 }
3984 }
3985
3986 fn on_worktree_store_event(
3987 &mut self,
3988 _: Entity<WorktreeStore>,
3989 event: &WorktreeStoreEvent,
3990 cx: &mut Context<Self>,
3991 ) {
3992 match event {
3993 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3994 if !worktree.read(cx).is_local() {
3995 return;
3996 }
3997 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3998 worktree::Event::UpdatedEntries(changes) => {
3999 this.update_local_worktree_language_servers(&worktree, changes, cx);
4000 }
4001 worktree::Event::UpdatedGitRepositories(_)
4002 | worktree::Event::DeletedEntry(_) => {}
4003 })
4004 .detach()
4005 }
4006 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4007 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4008 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4009 }
4010 WorktreeStoreEvent::WorktreeReleased(..)
4011 | WorktreeStoreEvent::WorktreeOrderChanged
4012 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4013 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4014 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4015 }
4016 }
4017
4018 fn on_prettier_store_event(
4019 &mut self,
4020 _: Entity<PrettierStore>,
4021 event: &PrettierStoreEvent,
4022 cx: &mut Context<Self>,
4023 ) {
4024 match event {
4025 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4026 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4027 }
4028 PrettierStoreEvent::LanguageServerAdded {
4029 new_server_id,
4030 name,
4031 prettier_server,
4032 } => {
4033 self.register_supplementary_language_server(
4034 *new_server_id,
4035 name.clone(),
4036 prettier_server.clone(),
4037 cx,
4038 );
4039 }
4040 }
4041 }
4042
4043 fn on_toolchain_store_event(
4044 &mut self,
4045 _: Entity<LocalToolchainStore>,
4046 event: &ToolchainStoreEvent,
4047 _: &mut Context<Self>,
4048 ) {
4049 if let ToolchainStoreEvent::ToolchainActivated = event {
4050 self.request_workspace_config_refresh()
4051 }
4052 }
4053
4054 fn request_workspace_config_refresh(&mut self) {
4055 *self._maintain_workspace_config.1.borrow_mut() = ();
4056 }
4057
4058 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4059 self.as_local().map(|local| local.prettier_store.clone())
4060 }
4061
4062 fn on_buffer_event(
4063 &mut self,
4064 buffer: Entity<Buffer>,
4065 event: &language::BufferEvent,
4066 cx: &mut Context<Self>,
4067 ) {
4068 match event {
4069 language::BufferEvent::Edited => {
4070 self.on_buffer_edited(buffer, cx);
4071 }
4072
4073 language::BufferEvent::Saved => {
4074 self.on_buffer_saved(buffer, cx);
4075 }
4076
4077 _ => {}
4078 }
4079 }
4080
4081 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4082 buffer
4083 .read(cx)
4084 .set_language_registry(self.languages.clone());
4085
4086 cx.subscribe(buffer, |this, buffer, event, cx| {
4087 this.on_buffer_event(buffer, event, cx);
4088 })
4089 .detach();
4090
4091 self.detect_language_for_buffer(buffer, cx);
4092 if let Some(local) = self.as_local_mut() {
4093 local.initialize_buffer(buffer, cx);
4094 }
4095
4096 Ok(())
4097 }
4098
4099 pub(crate) fn register_buffer_with_language_servers(
4100 &mut self,
4101 buffer: &Entity<Buffer>,
4102 only_register_servers: HashSet<LanguageServerSelector>,
4103 ignore_refcounts: bool,
4104 cx: &mut Context<Self>,
4105 ) -> OpenLspBufferHandle {
4106 let buffer_id = buffer.read(cx).remote_id();
4107 let handle = cx.new(|_| buffer.clone());
4108 if let Some(local) = self.as_local_mut() {
4109 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4110 if !ignore_refcounts {
4111 *refcount += 1;
4112 }
4113
4114 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4115 // 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
4116 // 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
4117 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4118 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4119 return handle;
4120 };
4121 if !file.is_local() {
4122 return handle;
4123 }
4124
4125 if ignore_refcounts || *refcount == 1 {
4126 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4127 }
4128 if !ignore_refcounts {
4129 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4130 let refcount = {
4131 let local = lsp_store.as_local_mut().unwrap();
4132 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4133 debug_panic!("bad refcounting");
4134 return;
4135 };
4136
4137 *refcount -= 1;
4138 *refcount
4139 };
4140 if refcount == 0 {
4141 lsp_store.lsp_data.remove(&buffer_id);
4142 let local = lsp_store.as_local_mut().unwrap();
4143 local.registered_buffers.remove(&buffer_id);
4144 local.buffers_opened_in_servers.remove(&buffer_id);
4145 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4146 local.unregister_old_buffer_from_language_servers(buffer, &file, cx);
4147 }
4148 }
4149 })
4150 .detach();
4151 }
4152 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4153 let buffer_id = buffer.read(cx).remote_id().to_proto();
4154 cx.background_spawn(async move {
4155 upstream_client
4156 .request(proto::RegisterBufferWithLanguageServers {
4157 project_id: upstream_project_id,
4158 buffer_id,
4159 only_servers: only_register_servers
4160 .into_iter()
4161 .map(|selector| {
4162 let selector = match selector {
4163 LanguageServerSelector::Id(language_server_id) => {
4164 proto::language_server_selector::Selector::ServerId(
4165 language_server_id.to_proto(),
4166 )
4167 }
4168 LanguageServerSelector::Name(language_server_name) => {
4169 proto::language_server_selector::Selector::Name(
4170 language_server_name.to_string(),
4171 )
4172 }
4173 };
4174 proto::LanguageServerSelector {
4175 selector: Some(selector),
4176 }
4177 })
4178 .collect(),
4179 })
4180 .await
4181 })
4182 .detach();
4183 } else {
4184 panic!("oops!");
4185 }
4186 handle
4187 }
4188
4189 fn maintain_buffer_languages(
4190 languages: Arc<LanguageRegistry>,
4191 cx: &mut Context<Self>,
4192 ) -> Task<()> {
4193 let mut subscription = languages.subscribe();
4194 let mut prev_reload_count = languages.reload_count();
4195 cx.spawn(async move |this, cx| {
4196 while let Some(()) = subscription.next().await {
4197 if let Some(this) = this.upgrade() {
4198 // If the language registry has been reloaded, then remove and
4199 // re-assign the languages on all open buffers.
4200 let reload_count = languages.reload_count();
4201 if reload_count > prev_reload_count {
4202 prev_reload_count = reload_count;
4203 this.update(cx, |this, cx| {
4204 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4205 for buffer in buffer_store.buffers() {
4206 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4207 {
4208 buffer
4209 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4210 if let Some(local) = this.as_local_mut() {
4211 local.reset_buffer(&buffer, &f, cx);
4212
4213 if local
4214 .registered_buffers
4215 .contains_key(&buffer.read(cx).remote_id())
4216 && let Some(file_url) =
4217 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4218 {
4219 local.unregister_buffer_from_language_servers(
4220 &buffer, &file_url, cx,
4221 );
4222 }
4223 }
4224 }
4225 }
4226 });
4227 })
4228 .ok();
4229 }
4230
4231 this.update(cx, |this, cx| {
4232 let mut plain_text_buffers = Vec::new();
4233 let mut buffers_with_unknown_injections = Vec::new();
4234 for handle in this.buffer_store.read(cx).buffers() {
4235 let buffer = handle.read(cx);
4236 if buffer.language().is_none()
4237 || buffer.language() == Some(&*language::PLAIN_TEXT)
4238 {
4239 plain_text_buffers.push(handle);
4240 } else if buffer.contains_unknown_injections() {
4241 buffers_with_unknown_injections.push(handle);
4242 }
4243 }
4244
4245 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4246 // and reused later in the invisible worktrees.
4247 plain_text_buffers.sort_by_key(|buffer| {
4248 Reverse(
4249 File::from_dyn(buffer.read(cx).file())
4250 .map(|file| file.worktree.read(cx).is_visible()),
4251 )
4252 });
4253
4254 for buffer in plain_text_buffers {
4255 this.detect_language_for_buffer(&buffer, cx);
4256 if let Some(local) = this.as_local_mut() {
4257 local.initialize_buffer(&buffer, cx);
4258 if local
4259 .registered_buffers
4260 .contains_key(&buffer.read(cx).remote_id())
4261 {
4262 local.register_buffer_with_language_servers(
4263 &buffer,
4264 HashSet::default(),
4265 cx,
4266 );
4267 }
4268 }
4269 }
4270
4271 for buffer in buffers_with_unknown_injections {
4272 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4273 }
4274 })
4275 .ok();
4276 }
4277 }
4278 })
4279 }
4280
4281 fn detect_language_for_buffer(
4282 &mut self,
4283 buffer_handle: &Entity<Buffer>,
4284 cx: &mut Context<Self>,
4285 ) -> Option<language::AvailableLanguage> {
4286 // If the buffer has a language, set it and start the language server if we haven't already.
4287 let buffer = buffer_handle.read(cx);
4288 let file = buffer.file()?;
4289
4290 let content = buffer.as_rope();
4291 let available_language = self.languages.language_for_file(file, Some(content), cx);
4292 if let Some(available_language) = &available_language {
4293 if let Some(Ok(Ok(new_language))) = self
4294 .languages
4295 .load_language(available_language)
4296 .now_or_never()
4297 {
4298 self.set_language_for_buffer(buffer_handle, new_language, cx);
4299 }
4300 } else {
4301 cx.emit(LspStoreEvent::LanguageDetected {
4302 buffer: buffer_handle.clone(),
4303 new_language: None,
4304 });
4305 }
4306
4307 available_language
4308 }
4309
4310 pub(crate) fn set_language_for_buffer(
4311 &mut self,
4312 buffer_entity: &Entity<Buffer>,
4313 new_language: Arc<Language>,
4314 cx: &mut Context<Self>,
4315 ) {
4316 let buffer = buffer_entity.read(cx);
4317 let buffer_file = buffer.file().cloned();
4318 let buffer_id = buffer.remote_id();
4319 if let Some(local_store) = self.as_local_mut()
4320 && local_store.registered_buffers.contains_key(&buffer_id)
4321 && let Some(abs_path) =
4322 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4323 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4324 {
4325 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4326 }
4327 buffer_entity.update(cx, |buffer, cx| {
4328 if buffer
4329 .language()
4330 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4331 {
4332 buffer.set_language(Some(new_language.clone()), cx);
4333 }
4334 });
4335
4336 let settings =
4337 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4338 let buffer_file = File::from_dyn(buffer_file.as_ref());
4339
4340 let worktree_id = if let Some(file) = buffer_file {
4341 let worktree = file.worktree.clone();
4342
4343 if let Some(local) = self.as_local_mut()
4344 && local.registered_buffers.contains_key(&buffer_id)
4345 {
4346 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4347 }
4348 Some(worktree.read(cx).id())
4349 } else {
4350 None
4351 };
4352
4353 if settings.prettier.allowed
4354 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4355 {
4356 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4357 if let Some(prettier_store) = prettier_store {
4358 prettier_store.update(cx, |prettier_store, cx| {
4359 prettier_store.install_default_prettier(
4360 worktree_id,
4361 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4362 cx,
4363 )
4364 })
4365 }
4366 }
4367
4368 cx.emit(LspStoreEvent::LanguageDetected {
4369 buffer: buffer_entity.clone(),
4370 new_language: Some(new_language),
4371 })
4372 }
4373
4374 pub fn buffer_store(&self) -> Entity<BufferStore> {
4375 self.buffer_store.clone()
4376 }
4377
4378 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4379 self.active_entry = active_entry;
4380 }
4381
4382 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4383 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4384 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4385 {
4386 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4387 summaries
4388 .iter()
4389 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4390 });
4391 if let Some(summary) = summaries.next() {
4392 client
4393 .send(proto::UpdateDiagnosticSummary {
4394 project_id: downstream_project_id,
4395 worktree_id: worktree.id().to_proto(),
4396 summary: Some(summary),
4397 more_summaries: summaries.collect(),
4398 })
4399 .log_err();
4400 }
4401 }
4402 }
4403
4404 fn is_capable_for_proto_request<R>(
4405 &self,
4406 buffer: &Entity<Buffer>,
4407 request: &R,
4408 cx: &App,
4409 ) -> bool
4410 where
4411 R: LspCommand,
4412 {
4413 self.check_if_capable_for_proto_request(
4414 buffer,
4415 |capabilities| {
4416 request.check_capabilities(AdapterServerCapabilities {
4417 server_capabilities: capabilities.clone(),
4418 code_action_kinds: None,
4419 })
4420 },
4421 cx,
4422 )
4423 }
4424
4425 fn check_if_capable_for_proto_request<F>(
4426 &self,
4427 buffer: &Entity<Buffer>,
4428 check: F,
4429 cx: &App,
4430 ) -> bool
4431 where
4432 F: FnMut(&lsp::ServerCapabilities) -> bool,
4433 {
4434 let Some(language) = buffer.read(cx).language().cloned() else {
4435 return false;
4436 };
4437 let relevant_language_servers = self
4438 .languages
4439 .lsp_adapters(&language.name())
4440 .into_iter()
4441 .map(|lsp_adapter| lsp_adapter.name())
4442 .collect::<HashSet<_>>();
4443 self.language_server_statuses
4444 .iter()
4445 .filter_map(|(server_id, server_status)| {
4446 relevant_language_servers
4447 .contains(&server_status.name)
4448 .then_some(server_id)
4449 })
4450 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4451 .any(check)
4452 }
4453
4454 pub fn request_lsp<R>(
4455 &mut self,
4456 buffer: Entity<Buffer>,
4457 server: LanguageServerToQuery,
4458 request: R,
4459 cx: &mut Context<Self>,
4460 ) -> Task<Result<R::Response>>
4461 where
4462 R: LspCommand,
4463 <R::LspRequest as lsp::request::Request>::Result: Send,
4464 <R::LspRequest as lsp::request::Request>::Params: Send,
4465 {
4466 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4467 return self.send_lsp_proto_request(
4468 buffer,
4469 upstream_client,
4470 upstream_project_id,
4471 request,
4472 cx,
4473 );
4474 }
4475
4476 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4477 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4478 local
4479 .language_servers_for_buffer(buffer, cx)
4480 .find(|(_, server)| {
4481 request.check_capabilities(server.adapter_server_capabilities())
4482 })
4483 .map(|(_, server)| server.clone())
4484 }),
4485 LanguageServerToQuery::Other(id) => self
4486 .language_server_for_local_buffer(buffer, id, cx)
4487 .and_then(|(_, server)| {
4488 request
4489 .check_capabilities(server.adapter_server_capabilities())
4490 .then(|| Arc::clone(server))
4491 }),
4492 }) else {
4493 return Task::ready(Ok(Default::default()));
4494 };
4495
4496 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4497
4498 let Some(file) = file else {
4499 return Task::ready(Ok(Default::default()));
4500 };
4501
4502 let lsp_params = match request.to_lsp_params_or_response(
4503 &file.abs_path(cx),
4504 buffer.read(cx),
4505 &language_server,
4506 cx,
4507 ) {
4508 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4509 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4510
4511 Err(err) => {
4512 let message = format!(
4513 "{} via {} failed: {}",
4514 request.display_name(),
4515 language_server.name(),
4516 err
4517 );
4518 log::warn!("{message}");
4519 return Task::ready(Err(anyhow!(message)));
4520 }
4521 };
4522
4523 let status = request.status();
4524 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4525 return Task::ready(Ok(Default::default()));
4526 }
4527 cx.spawn(async move |this, cx| {
4528 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4529
4530 let id = lsp_request.id();
4531 let _cleanup = if status.is_some() {
4532 cx.update(|cx| {
4533 this.update(cx, |this, cx| {
4534 this.on_lsp_work_start(
4535 language_server.server_id(),
4536 ProgressToken::Number(id),
4537 LanguageServerProgress {
4538 is_disk_based_diagnostics_progress: false,
4539 is_cancellable: false,
4540 title: None,
4541 message: status.clone(),
4542 percentage: None,
4543 last_update_at: cx.background_executor().now(),
4544 },
4545 cx,
4546 );
4547 })
4548 })
4549 .log_err();
4550
4551 Some(defer(|| {
4552 cx.update(|cx| {
4553 this.update(cx, |this, cx| {
4554 this.on_lsp_work_end(
4555 language_server.server_id(),
4556 ProgressToken::Number(id),
4557 cx,
4558 );
4559 })
4560 })
4561 .log_err();
4562 }))
4563 } else {
4564 None
4565 };
4566
4567 let result = lsp_request.await.into_response();
4568
4569 let response = result.map_err(|err| {
4570 let message = format!(
4571 "{} via {} failed: {}",
4572 request.display_name(),
4573 language_server.name(),
4574 err
4575 );
4576 log::warn!("{message}");
4577 anyhow::anyhow!(message)
4578 })?;
4579
4580 request
4581 .response_from_lsp(
4582 response,
4583 this.upgrade().context("no app context")?,
4584 buffer,
4585 language_server.server_id(),
4586 cx.clone(),
4587 )
4588 .await
4589 })
4590 }
4591
4592 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4593 let mut language_formatters_to_check = Vec::new();
4594 for buffer in self.buffer_store.read(cx).buffers() {
4595 let buffer = buffer.read(cx);
4596 let buffer_file = File::from_dyn(buffer.file());
4597 let buffer_language = buffer.language();
4598 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4599 if buffer_language.is_some() {
4600 language_formatters_to_check.push((
4601 buffer_file.map(|f| f.worktree_id(cx)),
4602 settings.into_owned(),
4603 ));
4604 }
4605 }
4606
4607 self.request_workspace_config_refresh();
4608
4609 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4610 prettier_store.update(cx, |prettier_store, cx| {
4611 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4612 })
4613 }
4614
4615 cx.notify();
4616 }
4617
4618 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4619 let buffer_store = self.buffer_store.clone();
4620 let Some(local) = self.as_local_mut() else {
4621 return;
4622 };
4623 let mut adapters = BTreeMap::default();
4624 let get_adapter = {
4625 let languages = local.languages.clone();
4626 let environment = local.environment.clone();
4627 let weak = local.weak.clone();
4628 let worktree_store = local.worktree_store.clone();
4629 let http_client = local.http_client.clone();
4630 let fs = local.fs.clone();
4631 move |worktree_id, cx: &mut App| {
4632 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4633 Some(LocalLspAdapterDelegate::new(
4634 languages.clone(),
4635 &environment,
4636 weak.clone(),
4637 &worktree,
4638 http_client.clone(),
4639 fs.clone(),
4640 cx,
4641 ))
4642 }
4643 };
4644
4645 let mut messages_to_report = Vec::new();
4646 let (new_tree, to_stop) = {
4647 let mut rebase = local.lsp_tree.rebase();
4648 let buffers = buffer_store
4649 .read(cx)
4650 .buffers()
4651 .filter_map(|buffer| {
4652 let raw_buffer = buffer.read(cx);
4653 if !local
4654 .registered_buffers
4655 .contains_key(&raw_buffer.remote_id())
4656 {
4657 return None;
4658 }
4659 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4660 let language = raw_buffer.language().cloned()?;
4661 Some((file, language, raw_buffer.remote_id()))
4662 })
4663 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4664 for (file, language, buffer_id) in buffers {
4665 let worktree_id = file.worktree_id(cx);
4666 let Some(worktree) = local
4667 .worktree_store
4668 .read(cx)
4669 .worktree_for_id(worktree_id, cx)
4670 else {
4671 continue;
4672 };
4673
4674 if let Some((_, apply)) = local.reuse_existing_language_server(
4675 rebase.server_tree(),
4676 &worktree,
4677 &language.name(),
4678 cx,
4679 ) {
4680 (apply)(rebase.server_tree());
4681 } else if let Some(lsp_delegate) = adapters
4682 .entry(worktree_id)
4683 .or_insert_with(|| get_adapter(worktree_id, cx))
4684 .clone()
4685 {
4686 let delegate =
4687 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4688 let path = file
4689 .path()
4690 .parent()
4691 .map(Arc::from)
4692 .unwrap_or_else(|| file.path().clone());
4693 let worktree_path = ProjectPath { worktree_id, path };
4694 let abs_path = file.abs_path(cx);
4695 let nodes = rebase
4696 .walk(
4697 worktree_path,
4698 language.name(),
4699 language.manifest(),
4700 delegate.clone(),
4701 cx,
4702 )
4703 .collect::<Vec<_>>();
4704 for node in nodes {
4705 let server_id = node.server_id_or_init(|disposition| {
4706 let path = &disposition.path;
4707 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4708 let key = LanguageServerSeed {
4709 worktree_id,
4710 name: disposition.server_name.clone(),
4711 settings: disposition.settings.clone(),
4712 toolchain: local.toolchain_store.read(cx).active_toolchain(
4713 path.worktree_id,
4714 &path.path,
4715 language.name(),
4716 ),
4717 };
4718 local.language_server_ids.remove(&key);
4719
4720 let server_id = local.get_or_insert_language_server(
4721 &worktree,
4722 lsp_delegate.clone(),
4723 disposition,
4724 &language.name(),
4725 cx,
4726 );
4727 if let Some(state) = local.language_servers.get(&server_id)
4728 && let Ok(uri) = uri
4729 {
4730 state.add_workspace_folder(uri);
4731 };
4732 server_id
4733 });
4734
4735 if let Some(language_server_id) = server_id {
4736 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4737 language_server_id,
4738 name: node.name(),
4739 message:
4740 proto::update_language_server::Variant::RegisteredForBuffer(
4741 proto::RegisteredForBuffer {
4742 buffer_abs_path: abs_path
4743 .to_string_lossy()
4744 .into_owned(),
4745 buffer_id: buffer_id.to_proto(),
4746 },
4747 ),
4748 });
4749 }
4750 }
4751 } else {
4752 continue;
4753 }
4754 }
4755 rebase.finish()
4756 };
4757 for message in messages_to_report {
4758 cx.emit(message);
4759 }
4760 local.lsp_tree = new_tree;
4761 for (id, _) in to_stop {
4762 self.stop_local_language_server(id, cx).detach();
4763 }
4764 }
4765
4766 pub fn apply_code_action(
4767 &self,
4768 buffer_handle: Entity<Buffer>,
4769 mut action: CodeAction,
4770 push_to_history: bool,
4771 cx: &mut Context<Self>,
4772 ) -> Task<Result<ProjectTransaction>> {
4773 if let Some((upstream_client, project_id)) = self.upstream_client() {
4774 let request = proto::ApplyCodeAction {
4775 project_id,
4776 buffer_id: buffer_handle.read(cx).remote_id().into(),
4777 action: Some(Self::serialize_code_action(&action)),
4778 };
4779 let buffer_store = self.buffer_store();
4780 cx.spawn(async move |_, cx| {
4781 let response = upstream_client
4782 .request(request)
4783 .await?
4784 .transaction
4785 .context("missing transaction")?;
4786
4787 buffer_store
4788 .update(cx, |buffer_store, cx| {
4789 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4790 })?
4791 .await
4792 })
4793 } else if self.mode.is_local() {
4794 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4795 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4796 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4797 }) else {
4798 return Task::ready(Ok(ProjectTransaction::default()));
4799 };
4800 cx.spawn(async move |this, cx| {
4801 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4802 .await
4803 .context("resolving a code action")?;
4804 if let Some(edit) = action.lsp_action.edit()
4805 && (edit.changes.is_some() || edit.document_changes.is_some()) {
4806 return LocalLspStore::deserialize_workspace_edit(
4807 this.upgrade().context("no app present")?,
4808 edit.clone(),
4809 push_to_history,
4810
4811 lang_server.clone(),
4812 cx,
4813 )
4814 .await;
4815 }
4816
4817 if let Some(command) = action.lsp_action.command() {
4818 let server_capabilities = lang_server.capabilities();
4819 let available_commands = server_capabilities
4820 .execute_command_provider
4821 .as_ref()
4822 .map(|options| options.commands.as_slice())
4823 .unwrap_or_default();
4824 if available_commands.contains(&command.command) {
4825 this.update(cx, |this, _| {
4826 this.as_local_mut()
4827 .unwrap()
4828 .last_workspace_edits_by_language_server
4829 .remove(&lang_server.server_id());
4830 })?;
4831
4832 let _result = lang_server
4833 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4834 command: command.command.clone(),
4835 arguments: command.arguments.clone().unwrap_or_default(),
4836 ..lsp::ExecuteCommandParams::default()
4837 })
4838 .await.into_response()
4839 .context("execute command")?;
4840
4841 return this.update(cx, |this, _| {
4842 this.as_local_mut()
4843 .unwrap()
4844 .last_workspace_edits_by_language_server
4845 .remove(&lang_server.server_id())
4846 .unwrap_or_default()
4847 });
4848 } else {
4849 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4850 }
4851 }
4852
4853 Ok(ProjectTransaction::default())
4854 })
4855 } else {
4856 Task::ready(Err(anyhow!("no upstream client and not local")))
4857 }
4858 }
4859
4860 pub fn apply_code_action_kind(
4861 &mut self,
4862 buffers: HashSet<Entity<Buffer>>,
4863 kind: CodeActionKind,
4864 push_to_history: bool,
4865 cx: &mut Context<Self>,
4866 ) -> Task<anyhow::Result<ProjectTransaction>> {
4867 if self.as_local().is_some() {
4868 cx.spawn(async move |lsp_store, cx| {
4869 let buffers = buffers.into_iter().collect::<Vec<_>>();
4870 let result = LocalLspStore::execute_code_action_kind_locally(
4871 lsp_store.clone(),
4872 buffers,
4873 kind,
4874 push_to_history,
4875 cx,
4876 )
4877 .await;
4878 lsp_store.update(cx, |lsp_store, _| {
4879 lsp_store.update_last_formatting_failure(&result);
4880 })?;
4881 result
4882 })
4883 } else if let Some((client, project_id)) = self.upstream_client() {
4884 let buffer_store = self.buffer_store();
4885 cx.spawn(async move |lsp_store, cx| {
4886 let result = client
4887 .request(proto::ApplyCodeActionKind {
4888 project_id,
4889 kind: kind.as_str().to_owned(),
4890 buffer_ids: buffers
4891 .iter()
4892 .map(|buffer| {
4893 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4894 })
4895 .collect::<Result<_>>()?,
4896 })
4897 .await
4898 .and_then(|result| result.transaction.context("missing transaction"));
4899 lsp_store.update(cx, |lsp_store, _| {
4900 lsp_store.update_last_formatting_failure(&result);
4901 })?;
4902
4903 let transaction_response = result?;
4904 buffer_store
4905 .update(cx, |buffer_store, cx| {
4906 buffer_store.deserialize_project_transaction(
4907 transaction_response,
4908 push_to_history,
4909 cx,
4910 )
4911 })?
4912 .await
4913 })
4914 } else {
4915 Task::ready(Ok(ProjectTransaction::default()))
4916 }
4917 }
4918
4919 pub fn resolved_hint(
4920 &mut self,
4921 buffer_id: BufferId,
4922 id: InlayId,
4923 cx: &mut Context<Self>,
4924 ) -> Option<ResolvedHint> {
4925 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
4926
4927 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
4928 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
4929 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
4930 let (server_id, resolve_data) = match &hint.resolve_state {
4931 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
4932 ResolveState::Resolving => {
4933 return Some(ResolvedHint::Resolving(
4934 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
4935 ));
4936 }
4937 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
4938 };
4939
4940 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
4941 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
4942 let previous_task = buffer_lsp_hints.hint_resolves.insert(
4943 id,
4944 cx.spawn(async move |lsp_store, cx| {
4945 let resolved_hint = resolve_task.await;
4946 lsp_store
4947 .update(cx, |lsp_store, _| {
4948 if let Some(old_inlay_hint) = lsp_store
4949 .lsp_data
4950 .get_mut(&buffer_id)
4951 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
4952 {
4953 match resolved_hint {
4954 Ok(resolved_hint) => {
4955 *old_inlay_hint = resolved_hint;
4956 }
4957 Err(e) => {
4958 old_inlay_hint.resolve_state =
4959 ResolveState::CanResolve(server_id, resolve_data);
4960 log::error!("Inlay hint resolve failed: {e:#}");
4961 }
4962 }
4963 }
4964 })
4965 .ok();
4966 })
4967 .shared(),
4968 );
4969 debug_assert!(
4970 previous_task.is_none(),
4971 "Did not change hint's resolve state after spawning its resolve"
4972 );
4973 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
4974 None
4975 }
4976
4977 fn resolve_inlay_hint(
4978 &self,
4979 mut hint: InlayHint,
4980 buffer: Entity<Buffer>,
4981 server_id: LanguageServerId,
4982 cx: &mut Context<Self>,
4983 ) -> Task<anyhow::Result<InlayHint>> {
4984 if let Some((upstream_client, project_id)) = self.upstream_client() {
4985 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
4986 {
4987 hint.resolve_state = ResolveState::Resolved;
4988 return Task::ready(Ok(hint));
4989 }
4990 let request = proto::ResolveInlayHint {
4991 project_id,
4992 buffer_id: buffer.read(cx).remote_id().into(),
4993 language_server_id: server_id.0 as u64,
4994 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
4995 };
4996 cx.background_spawn(async move {
4997 let response = upstream_client
4998 .request(request)
4999 .await
5000 .context("inlay hints proto request")?;
5001 match response.hint {
5002 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5003 .context("inlay hints proto resolve response conversion"),
5004 None => Ok(hint),
5005 }
5006 })
5007 } else {
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(hint));
5013 };
5014 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5015 return Task::ready(Ok(hint));
5016 }
5017 let buffer_snapshot = buffer.read(cx).snapshot();
5018 cx.spawn(async move |_, cx| {
5019 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5020 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5021 );
5022 let resolved_hint = resolve_task
5023 .await
5024 .into_response()
5025 .context("inlay hint resolve LSP request")?;
5026 let resolved_hint = InlayHints::lsp_to_project_hint(
5027 resolved_hint,
5028 &buffer,
5029 server_id,
5030 ResolveState::Resolved,
5031 false,
5032 cx,
5033 )
5034 .await?;
5035 Ok(resolved_hint)
5036 })
5037 }
5038 }
5039
5040 pub fn resolve_color_presentation(
5041 &mut self,
5042 mut color: DocumentColor,
5043 buffer: Entity<Buffer>,
5044 server_id: LanguageServerId,
5045 cx: &mut Context<Self>,
5046 ) -> Task<Result<DocumentColor>> {
5047 if color.resolved {
5048 return Task::ready(Ok(color));
5049 }
5050
5051 if let Some((upstream_client, project_id)) = self.upstream_client() {
5052 let start = color.lsp_range.start;
5053 let end = color.lsp_range.end;
5054 let request = proto::GetColorPresentation {
5055 project_id,
5056 server_id: server_id.to_proto(),
5057 buffer_id: buffer.read(cx).remote_id().into(),
5058 color: Some(proto::ColorInformation {
5059 red: color.color.red,
5060 green: color.color.green,
5061 blue: color.color.blue,
5062 alpha: color.color.alpha,
5063 lsp_range_start: Some(proto::PointUtf16 {
5064 row: start.line,
5065 column: start.character,
5066 }),
5067 lsp_range_end: Some(proto::PointUtf16 {
5068 row: end.line,
5069 column: end.character,
5070 }),
5071 }),
5072 };
5073 cx.background_spawn(async move {
5074 let response = upstream_client
5075 .request(request)
5076 .await
5077 .context("color presentation proto request")?;
5078 color.resolved = true;
5079 color.color_presentations = response
5080 .presentations
5081 .into_iter()
5082 .map(|presentation| ColorPresentation {
5083 label: SharedString::from(presentation.label),
5084 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5085 additional_text_edits: presentation
5086 .additional_text_edits
5087 .into_iter()
5088 .filter_map(deserialize_lsp_edit)
5089 .collect(),
5090 })
5091 .collect();
5092 Ok(color)
5093 })
5094 } else {
5095 let path = match buffer
5096 .update(cx, |buffer, cx| {
5097 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5098 })
5099 .context("buffer with the missing path")
5100 {
5101 Ok(path) => path,
5102 Err(e) => return Task::ready(Err(e)),
5103 };
5104 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5105 self.language_server_for_local_buffer(buffer, server_id, cx)
5106 .map(|(_, server)| server.clone())
5107 }) else {
5108 return Task::ready(Ok(color));
5109 };
5110 cx.background_spawn(async move {
5111 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5112 lsp::ColorPresentationParams {
5113 text_document: make_text_document_identifier(&path)?,
5114 color: color.color,
5115 range: color.lsp_range,
5116 work_done_progress_params: Default::default(),
5117 partial_result_params: Default::default(),
5118 },
5119 );
5120 color.color_presentations = resolve_task
5121 .await
5122 .into_response()
5123 .context("color presentation resolve LSP request")?
5124 .into_iter()
5125 .map(|presentation| ColorPresentation {
5126 label: SharedString::from(presentation.label),
5127 text_edit: presentation.text_edit,
5128 additional_text_edits: presentation
5129 .additional_text_edits
5130 .unwrap_or_default(),
5131 })
5132 .collect();
5133 color.resolved = true;
5134 Ok(color)
5135 })
5136 }
5137 }
5138
5139 pub(crate) fn linked_edits(
5140 &mut self,
5141 buffer: &Entity<Buffer>,
5142 position: Anchor,
5143 cx: &mut Context<Self>,
5144 ) -> Task<Result<Vec<Range<Anchor>>>> {
5145 let snapshot = buffer.read(cx).snapshot();
5146 let scope = snapshot.language_scope_at(position);
5147 let Some(server_id) = self
5148 .as_local()
5149 .and_then(|local| {
5150 buffer.update(cx, |buffer, cx| {
5151 local
5152 .language_servers_for_buffer(buffer, cx)
5153 .filter(|(_, server)| {
5154 LinkedEditingRange::check_server_capabilities(server.capabilities())
5155 })
5156 .filter(|(adapter, _)| {
5157 scope
5158 .as_ref()
5159 .map(|scope| scope.language_allowed(&adapter.name))
5160 .unwrap_or(true)
5161 })
5162 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5163 .next()
5164 })
5165 })
5166 .or_else(|| {
5167 self.upstream_client()
5168 .is_some()
5169 .then_some(LanguageServerToQuery::FirstCapable)
5170 })
5171 .filter(|_| {
5172 maybe!({
5173 let language = buffer.read(cx).language_at(position)?;
5174 Some(
5175 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5176 .linked_edits,
5177 )
5178 }) == Some(true)
5179 })
5180 else {
5181 return Task::ready(Ok(Vec::new()));
5182 };
5183
5184 self.request_lsp(
5185 buffer.clone(),
5186 server_id,
5187 LinkedEditingRange { position },
5188 cx,
5189 )
5190 }
5191
5192 fn apply_on_type_formatting(
5193 &mut self,
5194 buffer: Entity<Buffer>,
5195 position: Anchor,
5196 trigger: String,
5197 cx: &mut Context<Self>,
5198 ) -> Task<Result<Option<Transaction>>> {
5199 if let Some((client, project_id)) = self.upstream_client() {
5200 if !self.check_if_capable_for_proto_request(
5201 &buffer,
5202 |capabilities| {
5203 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5204 },
5205 cx,
5206 ) {
5207 return Task::ready(Ok(None));
5208 }
5209 let request = proto::OnTypeFormatting {
5210 project_id,
5211 buffer_id: buffer.read(cx).remote_id().into(),
5212 position: Some(serialize_anchor(&position)),
5213 trigger,
5214 version: serialize_version(&buffer.read(cx).version()),
5215 };
5216 cx.background_spawn(async move {
5217 client
5218 .request(request)
5219 .await?
5220 .transaction
5221 .map(language::proto::deserialize_transaction)
5222 .transpose()
5223 })
5224 } else if let Some(local) = self.as_local_mut() {
5225 let buffer_id = buffer.read(cx).remote_id();
5226 local.buffers_being_formatted.insert(buffer_id);
5227 cx.spawn(async move |this, cx| {
5228 let _cleanup = defer({
5229 let this = this.clone();
5230 let mut cx = cx.clone();
5231 move || {
5232 this.update(&mut cx, |this, _| {
5233 if let Some(local) = this.as_local_mut() {
5234 local.buffers_being_formatted.remove(&buffer_id);
5235 }
5236 })
5237 .ok();
5238 }
5239 });
5240
5241 buffer
5242 .update(cx, |buffer, _| {
5243 buffer.wait_for_edits(Some(position.timestamp))
5244 })?
5245 .await?;
5246 this.update(cx, |this, cx| {
5247 let position = position.to_point_utf16(buffer.read(cx));
5248 this.on_type_format(buffer, position, trigger, false, cx)
5249 })?
5250 .await
5251 })
5252 } else {
5253 Task::ready(Err(anyhow!("No upstream client or local language server")))
5254 }
5255 }
5256
5257 pub fn on_type_format<T: ToPointUtf16>(
5258 &mut self,
5259 buffer: Entity<Buffer>,
5260 position: T,
5261 trigger: String,
5262 push_to_history: bool,
5263 cx: &mut Context<Self>,
5264 ) -> Task<Result<Option<Transaction>>> {
5265 let position = position.to_point_utf16(buffer.read(cx));
5266 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5267 }
5268
5269 fn on_type_format_impl(
5270 &mut self,
5271 buffer: Entity<Buffer>,
5272 position: PointUtf16,
5273 trigger: String,
5274 push_to_history: bool,
5275 cx: &mut Context<Self>,
5276 ) -> Task<Result<Option<Transaction>>> {
5277 let options = buffer.update(cx, |buffer, cx| {
5278 lsp_command::lsp_formatting_options(
5279 language_settings(
5280 buffer.language_at(position).map(|l| l.name()),
5281 buffer.file(),
5282 cx,
5283 )
5284 .as_ref(),
5285 )
5286 });
5287
5288 cx.spawn(async move |this, cx| {
5289 if let Some(waiter) =
5290 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5291 {
5292 waiter.await?;
5293 }
5294 cx.update(|cx| {
5295 this.update(cx, |this, cx| {
5296 this.request_lsp(
5297 buffer.clone(),
5298 LanguageServerToQuery::FirstCapable,
5299 OnTypeFormatting {
5300 position,
5301 trigger,
5302 options,
5303 push_to_history,
5304 },
5305 cx,
5306 )
5307 })
5308 })??
5309 .await
5310 })
5311 }
5312
5313 pub fn definitions(
5314 &mut self,
5315 buffer: &Entity<Buffer>,
5316 position: PointUtf16,
5317 cx: &mut Context<Self>,
5318 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5319 if let Some((upstream_client, project_id)) = self.upstream_client() {
5320 let request = GetDefinitions { position };
5321 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5322 return Task::ready(Ok(None));
5323 }
5324 let request_task = upstream_client.request_lsp(
5325 project_id,
5326 None,
5327 LSP_REQUEST_TIMEOUT,
5328 cx.background_executor().clone(),
5329 request.to_proto(project_id, buffer.read(cx)),
5330 );
5331 let buffer = buffer.clone();
5332 cx.spawn(async move |weak_project, cx| {
5333 let Some(project) = weak_project.upgrade() else {
5334 return Ok(None);
5335 };
5336 let Some(responses) = request_task.await? else {
5337 return Ok(None);
5338 };
5339 let actions = join_all(responses.payload.into_iter().map(|response| {
5340 GetDefinitions { position }.response_from_proto(
5341 response.response,
5342 project.clone(),
5343 buffer.clone(),
5344 cx.clone(),
5345 )
5346 }))
5347 .await;
5348
5349 Ok(Some(
5350 actions
5351 .into_iter()
5352 .collect::<Result<Vec<Vec<_>>>>()?
5353 .into_iter()
5354 .flatten()
5355 .dedup()
5356 .collect(),
5357 ))
5358 })
5359 } else {
5360 let definitions_task = self.request_multiple_lsp_locally(
5361 buffer,
5362 Some(position),
5363 GetDefinitions { position },
5364 cx,
5365 );
5366 cx.background_spawn(async move {
5367 Ok(Some(
5368 definitions_task
5369 .await
5370 .into_iter()
5371 .flat_map(|(_, definitions)| definitions)
5372 .dedup()
5373 .collect(),
5374 ))
5375 })
5376 }
5377 }
5378
5379 pub fn declarations(
5380 &mut self,
5381 buffer: &Entity<Buffer>,
5382 position: PointUtf16,
5383 cx: &mut Context<Self>,
5384 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5385 if let Some((upstream_client, project_id)) = self.upstream_client() {
5386 let request = GetDeclarations { position };
5387 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5388 return Task::ready(Ok(None));
5389 }
5390 let request_task = upstream_client.request_lsp(
5391 project_id,
5392 None,
5393 LSP_REQUEST_TIMEOUT,
5394 cx.background_executor().clone(),
5395 request.to_proto(project_id, buffer.read(cx)),
5396 );
5397 let buffer = buffer.clone();
5398 cx.spawn(async move |weak_project, cx| {
5399 let Some(project) = weak_project.upgrade() else {
5400 return Ok(None);
5401 };
5402 let Some(responses) = request_task.await? else {
5403 return Ok(None);
5404 };
5405 let actions = join_all(responses.payload.into_iter().map(|response| {
5406 GetDeclarations { position }.response_from_proto(
5407 response.response,
5408 project.clone(),
5409 buffer.clone(),
5410 cx.clone(),
5411 )
5412 }))
5413 .await;
5414
5415 Ok(Some(
5416 actions
5417 .into_iter()
5418 .collect::<Result<Vec<Vec<_>>>>()?
5419 .into_iter()
5420 .flatten()
5421 .dedup()
5422 .collect(),
5423 ))
5424 })
5425 } else {
5426 let declarations_task = self.request_multiple_lsp_locally(
5427 buffer,
5428 Some(position),
5429 GetDeclarations { position },
5430 cx,
5431 );
5432 cx.background_spawn(async move {
5433 Ok(Some(
5434 declarations_task
5435 .await
5436 .into_iter()
5437 .flat_map(|(_, declarations)| declarations)
5438 .dedup()
5439 .collect(),
5440 ))
5441 })
5442 }
5443 }
5444
5445 pub fn type_definitions(
5446 &mut self,
5447 buffer: &Entity<Buffer>,
5448 position: PointUtf16,
5449 cx: &mut Context<Self>,
5450 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5451 if let Some((upstream_client, project_id)) = self.upstream_client() {
5452 let request = GetTypeDefinitions { position };
5453 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5454 return Task::ready(Ok(None));
5455 }
5456 let request_task = upstream_client.request_lsp(
5457 project_id,
5458 None,
5459 LSP_REQUEST_TIMEOUT,
5460 cx.background_executor().clone(),
5461 request.to_proto(project_id, buffer.read(cx)),
5462 );
5463 let buffer = buffer.clone();
5464 cx.spawn(async move |weak_project, cx| {
5465 let Some(project) = weak_project.upgrade() else {
5466 return Ok(None);
5467 };
5468 let Some(responses) = request_task.await? else {
5469 return Ok(None);
5470 };
5471 let actions = join_all(responses.payload.into_iter().map(|response| {
5472 GetTypeDefinitions { position }.response_from_proto(
5473 response.response,
5474 project.clone(),
5475 buffer.clone(),
5476 cx.clone(),
5477 )
5478 }))
5479 .await;
5480
5481 Ok(Some(
5482 actions
5483 .into_iter()
5484 .collect::<Result<Vec<Vec<_>>>>()?
5485 .into_iter()
5486 .flatten()
5487 .dedup()
5488 .collect(),
5489 ))
5490 })
5491 } else {
5492 let type_definitions_task = self.request_multiple_lsp_locally(
5493 buffer,
5494 Some(position),
5495 GetTypeDefinitions { position },
5496 cx,
5497 );
5498 cx.background_spawn(async move {
5499 Ok(Some(
5500 type_definitions_task
5501 .await
5502 .into_iter()
5503 .flat_map(|(_, type_definitions)| type_definitions)
5504 .dedup()
5505 .collect(),
5506 ))
5507 })
5508 }
5509 }
5510
5511 pub fn implementations(
5512 &mut self,
5513 buffer: &Entity<Buffer>,
5514 position: PointUtf16,
5515 cx: &mut Context<Self>,
5516 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5517 if let Some((upstream_client, project_id)) = self.upstream_client() {
5518 let request = GetImplementations { position };
5519 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5520 return Task::ready(Ok(None));
5521 }
5522 let request_task = upstream_client.request_lsp(
5523 project_id,
5524 None,
5525 LSP_REQUEST_TIMEOUT,
5526 cx.background_executor().clone(),
5527 request.to_proto(project_id, buffer.read(cx)),
5528 );
5529 let buffer = buffer.clone();
5530 cx.spawn(async move |weak_project, cx| {
5531 let Some(project) = weak_project.upgrade() else {
5532 return Ok(None);
5533 };
5534 let Some(responses) = request_task.await? else {
5535 return Ok(None);
5536 };
5537 let actions = join_all(responses.payload.into_iter().map(|response| {
5538 GetImplementations { position }.response_from_proto(
5539 response.response,
5540 project.clone(),
5541 buffer.clone(),
5542 cx.clone(),
5543 )
5544 }))
5545 .await;
5546
5547 Ok(Some(
5548 actions
5549 .into_iter()
5550 .collect::<Result<Vec<Vec<_>>>>()?
5551 .into_iter()
5552 .flatten()
5553 .dedup()
5554 .collect(),
5555 ))
5556 })
5557 } else {
5558 let implementations_task = self.request_multiple_lsp_locally(
5559 buffer,
5560 Some(position),
5561 GetImplementations { position },
5562 cx,
5563 );
5564 cx.background_spawn(async move {
5565 Ok(Some(
5566 implementations_task
5567 .await
5568 .into_iter()
5569 .flat_map(|(_, implementations)| implementations)
5570 .dedup()
5571 .collect(),
5572 ))
5573 })
5574 }
5575 }
5576
5577 pub fn references(
5578 &mut self,
5579 buffer: &Entity<Buffer>,
5580 position: PointUtf16,
5581 cx: &mut Context<Self>,
5582 ) -> Task<Result<Option<Vec<Location>>>> {
5583 if let Some((upstream_client, project_id)) = self.upstream_client() {
5584 let request = GetReferences { position };
5585 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5586 return Task::ready(Ok(None));
5587 }
5588
5589 let request_task = upstream_client.request_lsp(
5590 project_id,
5591 None,
5592 LSP_REQUEST_TIMEOUT,
5593 cx.background_executor().clone(),
5594 request.to_proto(project_id, buffer.read(cx)),
5595 );
5596 let buffer = buffer.clone();
5597 cx.spawn(async move |weak_project, cx| {
5598 let Some(project) = weak_project.upgrade() else {
5599 return Ok(None);
5600 };
5601 let Some(responses) = request_task.await? else {
5602 return Ok(None);
5603 };
5604
5605 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5606 GetReferences { position }.response_from_proto(
5607 lsp_response.response,
5608 project.clone(),
5609 buffer.clone(),
5610 cx.clone(),
5611 )
5612 }))
5613 .await
5614 .into_iter()
5615 .collect::<Result<Vec<Vec<_>>>>()?
5616 .into_iter()
5617 .flatten()
5618 .dedup()
5619 .collect();
5620 Ok(Some(locations))
5621 })
5622 } else {
5623 let references_task = self.request_multiple_lsp_locally(
5624 buffer,
5625 Some(position),
5626 GetReferences { position },
5627 cx,
5628 );
5629 cx.background_spawn(async move {
5630 Ok(Some(
5631 references_task
5632 .await
5633 .into_iter()
5634 .flat_map(|(_, references)| references)
5635 .dedup()
5636 .collect(),
5637 ))
5638 })
5639 }
5640 }
5641
5642 pub fn code_actions(
5643 &mut self,
5644 buffer: &Entity<Buffer>,
5645 range: Range<Anchor>,
5646 kinds: Option<Vec<CodeActionKind>>,
5647 cx: &mut Context<Self>,
5648 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5649 if let Some((upstream_client, project_id)) = self.upstream_client() {
5650 let request = GetCodeActions {
5651 range: range.clone(),
5652 kinds: kinds.clone(),
5653 };
5654 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5655 return Task::ready(Ok(None));
5656 }
5657 let request_task = upstream_client.request_lsp(
5658 project_id,
5659 None,
5660 LSP_REQUEST_TIMEOUT,
5661 cx.background_executor().clone(),
5662 request.to_proto(project_id, buffer.read(cx)),
5663 );
5664 let buffer = buffer.clone();
5665 cx.spawn(async move |weak_project, cx| {
5666 let Some(project) = weak_project.upgrade() else {
5667 return Ok(None);
5668 };
5669 let Some(responses) = request_task.await? else {
5670 return Ok(None);
5671 };
5672 let actions = join_all(responses.payload.into_iter().map(|response| {
5673 GetCodeActions {
5674 range: range.clone(),
5675 kinds: kinds.clone(),
5676 }
5677 .response_from_proto(
5678 response.response,
5679 project.clone(),
5680 buffer.clone(),
5681 cx.clone(),
5682 )
5683 }))
5684 .await;
5685
5686 Ok(Some(
5687 actions
5688 .into_iter()
5689 .collect::<Result<Vec<Vec<_>>>>()?
5690 .into_iter()
5691 .flatten()
5692 .collect(),
5693 ))
5694 })
5695 } else {
5696 let all_actions_task = self.request_multiple_lsp_locally(
5697 buffer,
5698 Some(range.start),
5699 GetCodeActions { range, kinds },
5700 cx,
5701 );
5702 cx.background_spawn(async move {
5703 Ok(Some(
5704 all_actions_task
5705 .await
5706 .into_iter()
5707 .flat_map(|(_, actions)| actions)
5708 .collect(),
5709 ))
5710 })
5711 }
5712 }
5713
5714 pub fn code_lens_actions(
5715 &mut self,
5716 buffer: &Entity<Buffer>,
5717 cx: &mut Context<Self>,
5718 ) -> CodeLensTask {
5719 let version_queried_for = buffer.read(cx).version();
5720 let buffer_id = buffer.read(cx).remote_id();
5721 let existing_servers = self.as_local().map(|local| {
5722 local
5723 .buffers_opened_in_servers
5724 .get(&buffer_id)
5725 .cloned()
5726 .unwrap_or_default()
5727 });
5728
5729 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5730 if let Some(cached_lens) = &lsp_data.code_lens {
5731 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5732 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5733 existing_servers != cached_lens.lens.keys().copied().collect()
5734 });
5735 if !has_different_servers {
5736 return Task::ready(Ok(Some(
5737 cached_lens.lens.values().flatten().cloned().collect(),
5738 )))
5739 .shared();
5740 }
5741 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5742 if !version_queried_for.changed_since(updating_for) {
5743 return running_update.clone();
5744 }
5745 }
5746 }
5747 }
5748
5749 let lens_lsp_data = self
5750 .latest_lsp_data(buffer, cx)
5751 .code_lens
5752 .get_or_insert_default();
5753 let buffer = buffer.clone();
5754 let query_version_queried_for = version_queried_for.clone();
5755 let new_task = cx
5756 .spawn(async move |lsp_store, cx| {
5757 cx.background_executor()
5758 .timer(Duration::from_millis(30))
5759 .await;
5760 let fetched_lens = lsp_store
5761 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5762 .map_err(Arc::new)?
5763 .await
5764 .context("fetching code lens")
5765 .map_err(Arc::new);
5766 let fetched_lens = match fetched_lens {
5767 Ok(fetched_lens) => fetched_lens,
5768 Err(e) => {
5769 lsp_store
5770 .update(cx, |lsp_store, _| {
5771 if let Some(lens_lsp_data) = lsp_store
5772 .lsp_data
5773 .get_mut(&buffer_id)
5774 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
5775 {
5776 lens_lsp_data.update = None;
5777 }
5778 })
5779 .ok();
5780 return Err(e);
5781 }
5782 };
5783
5784 lsp_store
5785 .update(cx, |lsp_store, _| {
5786 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
5787 let code_lens = lsp_data.code_lens.as_mut()?;
5788 if let Some(fetched_lens) = fetched_lens {
5789 if lsp_data.buffer_version == query_version_queried_for {
5790 code_lens.lens.extend(fetched_lens);
5791 } else if !lsp_data
5792 .buffer_version
5793 .changed_since(&query_version_queried_for)
5794 {
5795 lsp_data.buffer_version = query_version_queried_for;
5796 code_lens.lens = fetched_lens;
5797 }
5798 }
5799 code_lens.update = None;
5800 Some(code_lens.lens.values().flatten().cloned().collect())
5801 })
5802 .map_err(Arc::new)
5803 })
5804 .shared();
5805 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
5806 new_task
5807 }
5808
5809 fn fetch_code_lens(
5810 &mut self,
5811 buffer: &Entity<Buffer>,
5812 cx: &mut Context<Self>,
5813 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
5814 if let Some((upstream_client, project_id)) = self.upstream_client() {
5815 let request = GetCodeLens;
5816 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5817 return Task::ready(Ok(None));
5818 }
5819 let request_task = upstream_client.request_lsp(
5820 project_id,
5821 None,
5822 LSP_REQUEST_TIMEOUT,
5823 cx.background_executor().clone(),
5824 request.to_proto(project_id, buffer.read(cx)),
5825 );
5826 let buffer = buffer.clone();
5827 cx.spawn(async move |weak_lsp_store, cx| {
5828 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5829 return Ok(None);
5830 };
5831 let Some(responses) = request_task.await? else {
5832 return Ok(None);
5833 };
5834
5835 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
5836 let lsp_store = lsp_store.clone();
5837 let buffer = buffer.clone();
5838 let cx = cx.clone();
5839 async move {
5840 (
5841 LanguageServerId::from_proto(response.server_id),
5842 GetCodeLens
5843 .response_from_proto(response.response, lsp_store, buffer, cx)
5844 .await,
5845 )
5846 }
5847 }))
5848 .await;
5849
5850 let mut has_errors = false;
5851 let code_lens_actions = code_lens_actions
5852 .into_iter()
5853 .filter_map(|(server_id, code_lens)| match code_lens {
5854 Ok(code_lens) => Some((server_id, code_lens)),
5855 Err(e) => {
5856 has_errors = true;
5857 log::error!("{e:#}");
5858 None
5859 }
5860 })
5861 .collect::<HashMap<_, _>>();
5862 anyhow::ensure!(
5863 !has_errors || !code_lens_actions.is_empty(),
5864 "Failed to fetch code lens"
5865 );
5866 Ok(Some(code_lens_actions))
5867 })
5868 } else {
5869 let code_lens_actions_task =
5870 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5871 cx.background_spawn(async move {
5872 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
5873 })
5874 }
5875 }
5876
5877 #[inline(never)]
5878 pub fn completions(
5879 &self,
5880 buffer: &Entity<Buffer>,
5881 position: PointUtf16,
5882 context: CompletionContext,
5883 cx: &mut Context<Self>,
5884 ) -> Task<Result<Vec<CompletionResponse>>> {
5885 let language_registry = self.languages.clone();
5886
5887 if let Some((upstream_client, project_id)) = self.upstream_client() {
5888 let request = GetCompletions { position, context };
5889 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5890 return Task::ready(Ok(Vec::new()));
5891 }
5892 let task = self.send_lsp_proto_request(
5893 buffer.clone(),
5894 upstream_client,
5895 project_id,
5896 request,
5897 cx,
5898 );
5899 let language = buffer.read(cx).language().cloned();
5900
5901 // In the future, we should provide project guests with the names of LSP adapters,
5902 // so that they can use the correct LSP adapter when computing labels. For now,
5903 // guests just use the first LSP adapter associated with the buffer's language.
5904 let lsp_adapter = language.as_ref().and_then(|language| {
5905 language_registry
5906 .lsp_adapters(&language.name())
5907 .first()
5908 .cloned()
5909 });
5910
5911 cx.foreground_executor().spawn(async move {
5912 let completion_response = task.await?;
5913 let completions = populate_labels_for_completions(
5914 completion_response.completions,
5915 language,
5916 lsp_adapter,
5917 )
5918 .await;
5919 Ok(vec![CompletionResponse {
5920 completions,
5921 display_options: CompletionDisplayOptions::default(),
5922 is_incomplete: completion_response.is_incomplete,
5923 }])
5924 })
5925 } else if let Some(local) = self.as_local() {
5926 let snapshot = buffer.read(cx).snapshot();
5927 let offset = position.to_offset(&snapshot);
5928 let scope = snapshot.language_scope_at(offset);
5929 let language = snapshot.language().cloned();
5930 let completion_settings = language_settings(
5931 language.as_ref().map(|language| language.name()),
5932 buffer.read(cx).file(),
5933 cx,
5934 )
5935 .completions
5936 .clone();
5937 if !completion_settings.lsp {
5938 return Task::ready(Ok(Vec::new()));
5939 }
5940
5941 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
5942 local
5943 .language_servers_for_buffer(buffer, cx)
5944 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
5945 .filter(|(adapter, _)| {
5946 scope
5947 .as_ref()
5948 .map(|scope| scope.language_allowed(&adapter.name))
5949 .unwrap_or(true)
5950 })
5951 .map(|(_, server)| server.server_id())
5952 .collect()
5953 });
5954
5955 let buffer = buffer.clone();
5956 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
5957 let lsp_timeout = if lsp_timeout > 0 {
5958 Some(Duration::from_millis(lsp_timeout))
5959 } else {
5960 None
5961 };
5962 cx.spawn(async move |this, cx| {
5963 let mut tasks = Vec::with_capacity(server_ids.len());
5964 this.update(cx, |lsp_store, cx| {
5965 for server_id in server_ids {
5966 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
5967 let lsp_timeout = lsp_timeout
5968 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
5969 let mut timeout = cx.background_spawn(async move {
5970 match lsp_timeout {
5971 Some(lsp_timeout) => {
5972 lsp_timeout.await;
5973 true
5974 },
5975 None => false,
5976 }
5977 }).fuse();
5978 let mut lsp_request = lsp_store.request_lsp(
5979 buffer.clone(),
5980 LanguageServerToQuery::Other(server_id),
5981 GetCompletions {
5982 position,
5983 context: context.clone(),
5984 },
5985 cx,
5986 ).fuse();
5987 let new_task = cx.background_spawn(async move {
5988 select_biased! {
5989 response = lsp_request => anyhow::Ok(Some(response?)),
5990 timeout_happened = timeout => {
5991 if timeout_happened {
5992 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
5993 Ok(None)
5994 } else {
5995 let completions = lsp_request.await?;
5996 Ok(Some(completions))
5997 }
5998 },
5999 }
6000 });
6001 tasks.push((lsp_adapter, new_task));
6002 }
6003 })?;
6004
6005 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6006 let completion_response = task.await.ok()??;
6007 let completions = populate_labels_for_completions(
6008 completion_response.completions,
6009 language.clone(),
6010 lsp_adapter,
6011 )
6012 .await;
6013 Some(CompletionResponse {
6014 completions,
6015 display_options: CompletionDisplayOptions::default(),
6016 is_incomplete: completion_response.is_incomplete,
6017 })
6018 });
6019
6020 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6021
6022 Ok(responses.into_iter().flatten().collect())
6023 })
6024 } else {
6025 Task::ready(Err(anyhow!("No upstream client or local language server")))
6026 }
6027 }
6028
6029 pub fn resolve_completions(
6030 &self,
6031 buffer: Entity<Buffer>,
6032 completion_indices: Vec<usize>,
6033 completions: Rc<RefCell<Box<[Completion]>>>,
6034 cx: &mut Context<Self>,
6035 ) -> Task<Result<bool>> {
6036 let client = self.upstream_client();
6037 let buffer_id = buffer.read(cx).remote_id();
6038 let buffer_snapshot = buffer.read(cx).snapshot();
6039
6040 if !self.check_if_capable_for_proto_request(
6041 &buffer,
6042 GetCompletions::can_resolve_completions,
6043 cx,
6044 ) {
6045 return Task::ready(Ok(false));
6046 }
6047 cx.spawn(async move |lsp_store, cx| {
6048 let mut did_resolve = false;
6049 if let Some((client, project_id)) = client {
6050 for completion_index in completion_indices {
6051 let server_id = {
6052 let completion = &completions.borrow()[completion_index];
6053 completion.source.server_id()
6054 };
6055 if let Some(server_id) = server_id {
6056 if Self::resolve_completion_remote(
6057 project_id,
6058 server_id,
6059 buffer_id,
6060 completions.clone(),
6061 completion_index,
6062 client.clone(),
6063 )
6064 .await
6065 .log_err()
6066 .is_some()
6067 {
6068 did_resolve = true;
6069 }
6070 } else {
6071 resolve_word_completion(
6072 &buffer_snapshot,
6073 &mut completions.borrow_mut()[completion_index],
6074 );
6075 }
6076 }
6077 } else {
6078 for completion_index in completion_indices {
6079 let server_id = {
6080 let completion = &completions.borrow()[completion_index];
6081 completion.source.server_id()
6082 };
6083 if let Some(server_id) = server_id {
6084 let server_and_adapter = lsp_store
6085 .read_with(cx, |lsp_store, _| {
6086 let server = lsp_store.language_server_for_id(server_id)?;
6087 let adapter =
6088 lsp_store.language_server_adapter_for_id(server.server_id())?;
6089 Some((server, adapter))
6090 })
6091 .ok()
6092 .flatten();
6093 let Some((server, adapter)) = server_and_adapter else {
6094 continue;
6095 };
6096
6097 let resolved = Self::resolve_completion_local(
6098 server,
6099 completions.clone(),
6100 completion_index,
6101 )
6102 .await
6103 .log_err()
6104 .is_some();
6105 if resolved {
6106 Self::regenerate_completion_labels(
6107 adapter,
6108 &buffer_snapshot,
6109 completions.clone(),
6110 completion_index,
6111 )
6112 .await
6113 .log_err();
6114 did_resolve = true;
6115 }
6116 } else {
6117 resolve_word_completion(
6118 &buffer_snapshot,
6119 &mut completions.borrow_mut()[completion_index],
6120 );
6121 }
6122 }
6123 }
6124
6125 Ok(did_resolve)
6126 })
6127 }
6128
6129 async fn resolve_completion_local(
6130 server: Arc<lsp::LanguageServer>,
6131 completions: Rc<RefCell<Box<[Completion]>>>,
6132 completion_index: usize,
6133 ) -> Result<()> {
6134 let server_id = server.server_id();
6135 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6136 return Ok(());
6137 }
6138
6139 let request = {
6140 let completion = &completions.borrow()[completion_index];
6141 match &completion.source {
6142 CompletionSource::Lsp {
6143 lsp_completion,
6144 resolved,
6145 server_id: completion_server_id,
6146 ..
6147 } => {
6148 if *resolved {
6149 return Ok(());
6150 }
6151 anyhow::ensure!(
6152 server_id == *completion_server_id,
6153 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6154 );
6155 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6156 }
6157 CompletionSource::BufferWord { .. }
6158 | CompletionSource::Dap { .. }
6159 | CompletionSource::Custom => {
6160 return Ok(());
6161 }
6162 }
6163 };
6164 let resolved_completion = request
6165 .await
6166 .into_response()
6167 .context("resolve completion")?;
6168
6169 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6170 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6171
6172 let mut completions = completions.borrow_mut();
6173 let completion = &mut completions[completion_index];
6174 if let CompletionSource::Lsp {
6175 lsp_completion,
6176 resolved,
6177 server_id: completion_server_id,
6178 ..
6179 } = &mut completion.source
6180 {
6181 if *resolved {
6182 return Ok(());
6183 }
6184 anyhow::ensure!(
6185 server_id == *completion_server_id,
6186 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6187 );
6188 *lsp_completion = Box::new(resolved_completion);
6189 *resolved = true;
6190 }
6191 Ok(())
6192 }
6193
6194 async fn regenerate_completion_labels(
6195 adapter: Arc<CachedLspAdapter>,
6196 snapshot: &BufferSnapshot,
6197 completions: Rc<RefCell<Box<[Completion]>>>,
6198 completion_index: usize,
6199 ) -> Result<()> {
6200 let completion_item = completions.borrow()[completion_index]
6201 .source
6202 .lsp_completion(true)
6203 .map(Cow::into_owned);
6204 if let Some(lsp_documentation) = completion_item
6205 .as_ref()
6206 .and_then(|completion_item| completion_item.documentation.clone())
6207 {
6208 let mut completions = completions.borrow_mut();
6209 let completion = &mut completions[completion_index];
6210 completion.documentation = Some(lsp_documentation.into());
6211 } else {
6212 let mut completions = completions.borrow_mut();
6213 let completion = &mut completions[completion_index];
6214 completion.documentation = Some(CompletionDocumentation::Undocumented);
6215 }
6216
6217 let mut new_label = match completion_item {
6218 Some(completion_item) => {
6219 // 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
6220 // So we have to update the label here anyway...
6221 let language = snapshot.language();
6222 match language {
6223 Some(language) => {
6224 adapter
6225 .labels_for_completions(
6226 std::slice::from_ref(&completion_item),
6227 language,
6228 )
6229 .await?
6230 }
6231 None => Vec::new(),
6232 }
6233 .pop()
6234 .flatten()
6235 .unwrap_or_else(|| {
6236 CodeLabel::fallback_for_completion(
6237 &completion_item,
6238 language.map(|language| language.as_ref()),
6239 )
6240 })
6241 }
6242 None => CodeLabel::plain(
6243 completions.borrow()[completion_index].new_text.clone(),
6244 None,
6245 ),
6246 };
6247 ensure_uniform_list_compatible_label(&mut new_label);
6248
6249 let mut completions = completions.borrow_mut();
6250 let completion = &mut completions[completion_index];
6251 if completion.label.filter_text() == new_label.filter_text() {
6252 completion.label = new_label;
6253 } else {
6254 log::error!(
6255 "Resolved completion changed display label from {} to {}. \
6256 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6257 completion.label.text(),
6258 new_label.text(),
6259 completion.label.filter_text(),
6260 new_label.filter_text()
6261 );
6262 }
6263
6264 Ok(())
6265 }
6266
6267 async fn resolve_completion_remote(
6268 project_id: u64,
6269 server_id: LanguageServerId,
6270 buffer_id: BufferId,
6271 completions: Rc<RefCell<Box<[Completion]>>>,
6272 completion_index: usize,
6273 client: AnyProtoClient,
6274 ) -> Result<()> {
6275 let lsp_completion = {
6276 let completion = &completions.borrow()[completion_index];
6277 match &completion.source {
6278 CompletionSource::Lsp {
6279 lsp_completion,
6280 resolved,
6281 server_id: completion_server_id,
6282 ..
6283 } => {
6284 anyhow::ensure!(
6285 server_id == *completion_server_id,
6286 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6287 );
6288 if *resolved {
6289 return Ok(());
6290 }
6291 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6292 }
6293 CompletionSource::Custom
6294 | CompletionSource::Dap { .. }
6295 | CompletionSource::BufferWord { .. } => {
6296 return Ok(());
6297 }
6298 }
6299 };
6300 let request = proto::ResolveCompletionDocumentation {
6301 project_id,
6302 language_server_id: server_id.0 as u64,
6303 lsp_completion,
6304 buffer_id: buffer_id.into(),
6305 };
6306
6307 let response = client
6308 .request(request)
6309 .await
6310 .context("completion documentation resolve proto request")?;
6311 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6312
6313 let documentation = if response.documentation.is_empty() {
6314 CompletionDocumentation::Undocumented
6315 } else if response.documentation_is_markdown {
6316 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6317 } else if response.documentation.lines().count() <= 1 {
6318 CompletionDocumentation::SingleLine(response.documentation.into())
6319 } else {
6320 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6321 };
6322
6323 let mut completions = completions.borrow_mut();
6324 let completion = &mut completions[completion_index];
6325 completion.documentation = Some(documentation);
6326 if let CompletionSource::Lsp {
6327 insert_range,
6328 lsp_completion,
6329 resolved,
6330 server_id: completion_server_id,
6331 lsp_defaults: _,
6332 } = &mut completion.source
6333 {
6334 let completion_insert_range = response
6335 .old_insert_start
6336 .and_then(deserialize_anchor)
6337 .zip(response.old_insert_end.and_then(deserialize_anchor));
6338 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6339
6340 if *resolved {
6341 return Ok(());
6342 }
6343 anyhow::ensure!(
6344 server_id == *completion_server_id,
6345 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6346 );
6347 *lsp_completion = Box::new(resolved_lsp_completion);
6348 *resolved = true;
6349 }
6350
6351 let replace_range = response
6352 .old_replace_start
6353 .and_then(deserialize_anchor)
6354 .zip(response.old_replace_end.and_then(deserialize_anchor));
6355 if let Some((old_replace_start, old_replace_end)) = replace_range
6356 && !response.new_text.is_empty()
6357 {
6358 completion.new_text = response.new_text;
6359 completion.replace_range = old_replace_start..old_replace_end;
6360 }
6361
6362 Ok(())
6363 }
6364
6365 pub fn apply_additional_edits_for_completion(
6366 &self,
6367 buffer_handle: Entity<Buffer>,
6368 completions: Rc<RefCell<Box<[Completion]>>>,
6369 completion_index: usize,
6370 push_to_history: bool,
6371 cx: &mut Context<Self>,
6372 ) -> Task<Result<Option<Transaction>>> {
6373 if let Some((client, project_id)) = self.upstream_client() {
6374 let buffer = buffer_handle.read(cx);
6375 let buffer_id = buffer.remote_id();
6376 cx.spawn(async move |_, cx| {
6377 let request = {
6378 let completion = completions.borrow()[completion_index].clone();
6379 proto::ApplyCompletionAdditionalEdits {
6380 project_id,
6381 buffer_id: buffer_id.into(),
6382 completion: Some(Self::serialize_completion(&CoreCompletion {
6383 replace_range: completion.replace_range,
6384 new_text: completion.new_text,
6385 source: completion.source,
6386 })),
6387 }
6388 };
6389
6390 if let Some(transaction) = client.request(request).await?.transaction {
6391 let transaction = language::proto::deserialize_transaction(transaction)?;
6392 buffer_handle
6393 .update(cx, |buffer, _| {
6394 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6395 })?
6396 .await?;
6397 if push_to_history {
6398 buffer_handle.update(cx, |buffer, _| {
6399 buffer.push_transaction(transaction.clone(), Instant::now());
6400 buffer.finalize_last_transaction();
6401 })?;
6402 }
6403 Ok(Some(transaction))
6404 } else {
6405 Ok(None)
6406 }
6407 })
6408 } else {
6409 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6410 let completion = &completions.borrow()[completion_index];
6411 let server_id = completion.source.server_id()?;
6412 Some(
6413 self.language_server_for_local_buffer(buffer, server_id, cx)?
6414 .1
6415 .clone(),
6416 )
6417 }) else {
6418 return Task::ready(Ok(None));
6419 };
6420
6421 cx.spawn(async move |this, cx| {
6422 Self::resolve_completion_local(
6423 server.clone(),
6424 completions.clone(),
6425 completion_index,
6426 )
6427 .await
6428 .context("resolving completion")?;
6429 let completion = completions.borrow()[completion_index].clone();
6430 let additional_text_edits = completion
6431 .source
6432 .lsp_completion(true)
6433 .as_ref()
6434 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6435 if let Some(edits) = additional_text_edits {
6436 let edits = this
6437 .update(cx, |this, cx| {
6438 this.as_local_mut().unwrap().edits_from_lsp(
6439 &buffer_handle,
6440 edits,
6441 server.server_id(),
6442 None,
6443 cx,
6444 )
6445 })?
6446 .await?;
6447
6448 buffer_handle.update(cx, |buffer, cx| {
6449 buffer.finalize_last_transaction();
6450 buffer.start_transaction();
6451
6452 for (range, text) in edits {
6453 let primary = &completion.replace_range;
6454
6455 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6456 // and the primary completion is just an insertion (empty range), then this is likely
6457 // an auto-import scenario and should not be considered overlapping
6458 // https://github.com/zed-industries/zed/issues/26136
6459 let is_file_start_auto_import = {
6460 let snapshot = buffer.snapshot();
6461 let primary_start_point = primary.start.to_point(&snapshot);
6462 let range_start_point = range.start.to_point(&snapshot);
6463
6464 let result = primary_start_point.row == 0
6465 && primary_start_point.column == 0
6466 && range_start_point.row == 0
6467 && range_start_point.column == 0;
6468
6469 result
6470 };
6471
6472 let has_overlap = if is_file_start_auto_import {
6473 false
6474 } else {
6475 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6476 && primary.end.cmp(&range.start, buffer).is_ge();
6477 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6478 && range.end.cmp(&primary.end, buffer).is_ge();
6479 let result = start_within || end_within;
6480 result
6481 };
6482
6483 //Skip additional edits which overlap with the primary completion edit
6484 //https://github.com/zed-industries/zed/pull/1871
6485 if !has_overlap {
6486 buffer.edit([(range, text)], None, cx);
6487 }
6488 }
6489
6490 let transaction = if buffer.end_transaction(cx).is_some() {
6491 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6492 if !push_to_history {
6493 buffer.forget_transaction(transaction.id);
6494 }
6495 Some(transaction)
6496 } else {
6497 None
6498 };
6499 Ok(transaction)
6500 })?
6501 } else {
6502 Ok(None)
6503 }
6504 })
6505 }
6506 }
6507
6508 pub fn pull_diagnostics(
6509 &mut self,
6510 buffer: Entity<Buffer>,
6511 cx: &mut Context<Self>,
6512 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6513 let buffer_id = buffer.read(cx).remote_id();
6514
6515 if let Some((client, upstream_project_id)) = self.upstream_client() {
6516 let mut suitable_capabilities = None;
6517 // Are we capable for proto request?
6518 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6519 &buffer,
6520 |capabilities| {
6521 if let Some(caps) = &capabilities.diagnostic_provider {
6522 suitable_capabilities = Some(caps.clone());
6523 true
6524 } else {
6525 false
6526 }
6527 },
6528 cx,
6529 );
6530 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6531 let Some(dynamic_caps) = suitable_capabilities else {
6532 return Task::ready(Ok(None));
6533 };
6534 assert!(any_server_has_diagnostics_provider);
6535
6536 let request = GetDocumentDiagnostics {
6537 previous_result_id: None,
6538 dynamic_caps,
6539 };
6540 let request_task = client.request_lsp(
6541 upstream_project_id,
6542 None,
6543 LSP_REQUEST_TIMEOUT,
6544 cx.background_executor().clone(),
6545 request.to_proto(upstream_project_id, buffer.read(cx)),
6546 );
6547 cx.background_spawn(async move {
6548 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6549 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6550 // Do not attempt to further process the dummy responses here.
6551 let _response = request_task.await?;
6552 Ok(None)
6553 })
6554 } else {
6555 let servers = buffer.update(cx, |buffer, cx| {
6556 self.language_servers_for_local_buffer(buffer, cx)
6557 .map(|(_, server)| server.clone())
6558 .collect::<Vec<_>>()
6559 });
6560
6561 let pull_diagnostics = servers
6562 .into_iter()
6563 .flat_map(|server| {
6564 let result = maybe!({
6565 let local = self.as_local()?;
6566 let server_id = server.server_id();
6567 let providers_with_identifiers = local
6568 .language_server_dynamic_registrations
6569 .get(&server_id)
6570 .into_iter()
6571 .flat_map(|registrations| registrations.diagnostics.values().cloned())
6572 .collect::<Vec<_>>();
6573 Some(
6574 providers_with_identifiers
6575 .into_iter()
6576 .map(|dynamic_caps| {
6577 let result_id = self.result_id(server_id, buffer_id, cx);
6578 self.request_lsp(
6579 buffer.clone(),
6580 LanguageServerToQuery::Other(server_id),
6581 GetDocumentDiagnostics {
6582 previous_result_id: result_id,
6583 dynamic_caps,
6584 },
6585 cx,
6586 )
6587 })
6588 .collect::<Vec<_>>(),
6589 )
6590 });
6591
6592 result.unwrap_or_default()
6593 })
6594 .collect::<Vec<_>>();
6595
6596 cx.background_spawn(async move {
6597 let mut responses = Vec::new();
6598 for diagnostics in join_all(pull_diagnostics).await {
6599 responses.extend(diagnostics?);
6600 }
6601 Ok(Some(responses))
6602 })
6603 }
6604 }
6605
6606 pub fn applicable_inlay_chunks(
6607 &mut self,
6608 buffer: &Entity<Buffer>,
6609 ranges: &[Range<text::Anchor>],
6610 cx: &mut Context<Self>,
6611 ) -> Vec<Range<BufferRow>> {
6612 self.latest_lsp_data(buffer, cx)
6613 .inlay_hints
6614 .applicable_chunks(ranges)
6615 .map(|chunk| chunk.start..chunk.end)
6616 .collect()
6617 }
6618
6619 pub fn invalidate_inlay_hints<'a>(
6620 &'a mut self,
6621 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6622 ) {
6623 for buffer_id in for_buffers {
6624 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6625 lsp_data.inlay_hints.clear();
6626 }
6627 }
6628 }
6629
6630 pub fn inlay_hints(
6631 &mut self,
6632 invalidate: InvalidationStrategy,
6633 buffer: Entity<Buffer>,
6634 ranges: Vec<Range<text::Anchor>>,
6635 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6636 cx: &mut Context<Self>,
6637 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6638 let buffer_snapshot = buffer.read(cx).snapshot();
6639 let for_server = if let InvalidationStrategy::RefreshRequested(server_id) = invalidate {
6640 Some(server_id)
6641 } else {
6642 None
6643 };
6644 let invalidate_cache = invalidate.should_invalidate();
6645 let next_hint_id = self.next_hint_id.clone();
6646 let lsp_data = self.latest_lsp_data(&buffer, cx);
6647 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6648 let known_chunks = known_chunks
6649 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6650 .map(|(_, known_chunks)| known_chunks)
6651 .unwrap_or_default();
6652
6653 let mut hint_fetch_tasks = Vec::new();
6654 let mut cached_inlay_hints = HashMap::default();
6655 let mut ranges_to_query = Vec::new();
6656 let applicable_chunks = existing_inlay_hints
6657 .applicable_chunks(ranges.as_slice())
6658 .filter(|chunk| !known_chunks.contains(&(chunk.start..chunk.end)))
6659 .collect::<Vec<_>>();
6660 if applicable_chunks.is_empty() {
6661 return HashMap::default();
6662 }
6663
6664 let last_chunk_number = existing_inlay_hints.buffer_chunks_len() - 1;
6665
6666 for row_chunk in applicable_chunks {
6667 match (
6668 existing_inlay_hints
6669 .cached_hints(&row_chunk)
6670 .filter(|_| !invalidate_cache)
6671 .cloned(),
6672 existing_inlay_hints
6673 .fetched_hints(&row_chunk)
6674 .as_ref()
6675 .filter(|_| !invalidate_cache)
6676 .cloned(),
6677 ) {
6678 (None, None) => {
6679 let end = if last_chunk_number == row_chunk.id {
6680 Point::new(row_chunk.end, buffer_snapshot.line_len(row_chunk.end))
6681 } else {
6682 Point::new(row_chunk.end, 0)
6683 };
6684 ranges_to_query.push((
6685 row_chunk,
6686 buffer_snapshot.anchor_before(Point::new(row_chunk.start, 0))
6687 ..buffer_snapshot.anchor_after(end),
6688 ));
6689 }
6690 (None, Some(fetched_hints)) => {
6691 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()))
6692 }
6693 (Some(cached_hints), None) => {
6694 for (server_id, cached_hints) in cached_hints {
6695 if for_server.is_none_or(|for_server| for_server == server_id) {
6696 cached_inlay_hints
6697 .entry(row_chunk.start..row_chunk.end)
6698 .or_insert_with(HashMap::default)
6699 .entry(server_id)
6700 .or_insert_with(Vec::new)
6701 .extend(cached_hints);
6702 }
6703 }
6704 }
6705 (Some(cached_hints), Some(fetched_hints)) => {
6706 hint_fetch_tasks.push((row_chunk, fetched_hints.clone()));
6707 for (server_id, cached_hints) in cached_hints {
6708 if for_server.is_none_or(|for_server| for_server == server_id) {
6709 cached_inlay_hints
6710 .entry(row_chunk.start..row_chunk.end)
6711 .or_insert_with(HashMap::default)
6712 .entry(server_id)
6713 .or_insert_with(Vec::new)
6714 .extend(cached_hints);
6715 }
6716 }
6717 }
6718 }
6719 }
6720
6721 let cached_chunk_data = cached_inlay_hints
6722 .into_iter()
6723 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
6724 .collect();
6725 if hint_fetch_tasks.is_empty() && ranges_to_query.is_empty() {
6726 cached_chunk_data
6727 } else {
6728 if invalidate_cache {
6729 lsp_data.inlay_hints.clear();
6730 }
6731
6732 for (chunk, range_to_query) in ranges_to_query {
6733 let next_hint_id = next_hint_id.clone();
6734 let buffer = buffer.clone();
6735 let new_inlay_hints = cx
6736 .spawn(async move |lsp_store, cx| {
6737 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
6738 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
6739 })?;
6740 new_fetch_task
6741 .await
6742 .and_then(|new_hints_by_server| {
6743 lsp_store.update(cx, |lsp_store, cx| {
6744 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
6745 let update_cache = !lsp_data
6746 .buffer_version
6747 .changed_since(&buffer.read(cx).version());
6748 new_hints_by_server
6749 .into_iter()
6750 .map(|(server_id, new_hints)| {
6751 let new_hints = new_hints
6752 .into_iter()
6753 .map(|new_hint| {
6754 (
6755 InlayId::Hint(next_hint_id.fetch_add(
6756 1,
6757 atomic::Ordering::AcqRel,
6758 )),
6759 new_hint,
6760 )
6761 })
6762 .collect::<Vec<_>>();
6763 if update_cache {
6764 lsp_data.inlay_hints.insert_new_hints(
6765 chunk,
6766 server_id,
6767 new_hints.clone(),
6768 );
6769 }
6770 (server_id, new_hints)
6771 })
6772 .collect()
6773 })
6774 })
6775 .map_err(Arc::new)
6776 })
6777 .shared();
6778
6779 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
6780 *fetch_task = Some(new_inlay_hints.clone());
6781 hint_fetch_tasks.push((chunk, new_inlay_hints));
6782 }
6783
6784 let mut combined_data = cached_chunk_data;
6785 combined_data.extend(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
6786 (
6787 chunk.start..chunk.end,
6788 cx.spawn(async move |_, _| {
6789 hints_fetch.await.map_err(|e| {
6790 if e.error_code() != ErrorCode::Internal {
6791 anyhow!(e.error_code())
6792 } else {
6793 anyhow!("{e:#}")
6794 }
6795 })
6796 }),
6797 )
6798 }));
6799 combined_data
6800 }
6801 }
6802
6803 fn fetch_inlay_hints(
6804 &mut self,
6805 for_server: Option<LanguageServerId>,
6806 buffer: &Entity<Buffer>,
6807 range: Range<Anchor>,
6808 cx: &mut Context<Self>,
6809 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
6810 let request = InlayHints {
6811 range: range.clone(),
6812 };
6813 if let Some((upstream_client, project_id)) = self.upstream_client() {
6814 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6815 return Task::ready(Ok(HashMap::default()));
6816 }
6817 let request_task = upstream_client.request_lsp(
6818 project_id,
6819 for_server.map(|id| id.to_proto()),
6820 LSP_REQUEST_TIMEOUT,
6821 cx.background_executor().clone(),
6822 request.to_proto(project_id, buffer.read(cx)),
6823 );
6824 let buffer = buffer.clone();
6825 cx.spawn(async move |weak_lsp_store, cx| {
6826 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6827 return Ok(HashMap::default());
6828 };
6829 let Some(responses) = request_task.await? else {
6830 return Ok(HashMap::default());
6831 };
6832
6833 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
6834 let lsp_store = lsp_store.clone();
6835 let buffer = buffer.clone();
6836 let cx = cx.clone();
6837 let request = request.clone();
6838 async move {
6839 (
6840 LanguageServerId::from_proto(response.server_id),
6841 request
6842 .response_from_proto(response.response, lsp_store, buffer, cx)
6843 .await,
6844 )
6845 }
6846 }))
6847 .await;
6848
6849 let mut has_errors = false;
6850 let inlay_hints = inlay_hints
6851 .into_iter()
6852 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
6853 Ok(inlay_hints) => Some((server_id, inlay_hints)),
6854 Err(e) => {
6855 has_errors = true;
6856 log::error!("{e:#}");
6857 None
6858 }
6859 })
6860 .collect::<HashMap<_, _>>();
6861 anyhow::ensure!(
6862 !has_errors || !inlay_hints.is_empty(),
6863 "Failed to fetch inlay hints"
6864 );
6865 Ok(inlay_hints)
6866 })
6867 } else {
6868 let inlay_hints_task = match for_server {
6869 Some(server_id) => {
6870 let server_task = self.request_lsp(
6871 buffer.clone(),
6872 LanguageServerToQuery::Other(server_id),
6873 request,
6874 cx,
6875 );
6876 cx.background_spawn(async move {
6877 let mut responses = Vec::new();
6878 match server_task.await {
6879 Ok(response) => responses.push((server_id, response)),
6880 Err(e) => log::error!(
6881 "Error handling response for inlay hints request: {e:#}"
6882 ),
6883 }
6884 responses
6885 })
6886 }
6887 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
6888 };
6889 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
6890 cx.background_spawn(async move {
6891 Ok(inlay_hints_task
6892 .await
6893 .into_iter()
6894 .map(|(server_id, mut new_hints)| {
6895 new_hints.retain(|hint| {
6896 hint.position.is_valid(&buffer_snapshot)
6897 && range.start.is_valid(&buffer_snapshot)
6898 && range.end.is_valid(&buffer_snapshot)
6899 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
6900 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
6901 });
6902 (server_id, new_hints)
6903 })
6904 .collect())
6905 })
6906 }
6907 }
6908
6909 pub fn pull_diagnostics_for_buffer(
6910 &mut self,
6911 buffer: Entity<Buffer>,
6912 cx: &mut Context<Self>,
6913 ) -> Task<anyhow::Result<()>> {
6914 let diagnostics = self.pull_diagnostics(buffer, cx);
6915 cx.spawn(async move |lsp_store, cx| {
6916 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6917 return Ok(());
6918 };
6919 lsp_store.update(cx, |lsp_store, cx| {
6920 if lsp_store.as_local().is_none() {
6921 return;
6922 }
6923
6924 let mut unchanged_buffers = HashSet::default();
6925 let mut changed_buffers = HashSet::default();
6926 let server_diagnostics_updates = diagnostics
6927 .into_iter()
6928 .filter_map(|diagnostics_set| match diagnostics_set {
6929 LspPullDiagnostics::Response {
6930 server_id,
6931 uri,
6932 diagnostics,
6933 } => Some((server_id, uri, diagnostics)),
6934 LspPullDiagnostics::Default => None,
6935 })
6936 .fold(
6937 HashMap::default(),
6938 |mut acc, (server_id, uri, diagnostics)| {
6939 let (result_id, diagnostics) = match diagnostics {
6940 PulledDiagnostics::Unchanged { result_id } => {
6941 unchanged_buffers.insert(uri.clone());
6942 (Some(result_id), Vec::new())
6943 }
6944 PulledDiagnostics::Changed {
6945 result_id,
6946 diagnostics,
6947 } => {
6948 changed_buffers.insert(uri.clone());
6949 (result_id, diagnostics)
6950 }
6951 };
6952 let disk_based_sources = Cow::Owned(
6953 lsp_store
6954 .language_server_adapter_for_id(server_id)
6955 .as_ref()
6956 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6957 .unwrap_or(&[])
6958 .to_vec(),
6959 );
6960 acc.entry(server_id).or_insert_with(Vec::new).push(
6961 DocumentDiagnosticsUpdate {
6962 server_id,
6963 diagnostics: lsp::PublishDiagnosticsParams {
6964 uri,
6965 diagnostics,
6966 version: None,
6967 },
6968 result_id,
6969 disk_based_sources,
6970 },
6971 );
6972 acc
6973 },
6974 );
6975
6976 for diagnostic_updates in server_diagnostics_updates.into_values() {
6977 lsp_store
6978 .merge_lsp_diagnostics(
6979 DiagnosticSourceKind::Pulled,
6980 diagnostic_updates,
6981 |buffer, old_diagnostic, cx| {
6982 File::from_dyn(buffer.file())
6983 .and_then(|file| {
6984 let abs_path = file.as_local()?.abs_path(cx);
6985 lsp::Uri::from_file_path(abs_path).ok()
6986 })
6987 .is_none_or(|buffer_uri| {
6988 unchanged_buffers.contains(&buffer_uri)
6989 || match old_diagnostic.source_kind {
6990 DiagnosticSourceKind::Pulled => {
6991 !changed_buffers.contains(&buffer_uri)
6992 }
6993 DiagnosticSourceKind::Other
6994 | DiagnosticSourceKind::Pushed => true,
6995 }
6996 })
6997 },
6998 cx,
6999 )
7000 .log_err();
7001 }
7002 })
7003 })
7004 }
7005
7006 pub fn document_colors(
7007 &mut self,
7008 known_cache_version: Option<usize>,
7009 buffer: Entity<Buffer>,
7010 cx: &mut Context<Self>,
7011 ) -> Option<DocumentColorTask> {
7012 let version_queried_for = buffer.read(cx).version();
7013 let buffer_id = buffer.read(cx).remote_id();
7014
7015 let current_language_servers = self.as_local().map(|local| {
7016 local
7017 .buffers_opened_in_servers
7018 .get(&buffer_id)
7019 .cloned()
7020 .unwrap_or_default()
7021 });
7022
7023 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7024 if let Some(cached_colors) = &lsp_data.document_colors {
7025 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7026 let has_different_servers =
7027 current_language_servers.is_some_and(|current_language_servers| {
7028 current_language_servers
7029 != cached_colors.colors.keys().copied().collect()
7030 });
7031 if !has_different_servers {
7032 let cache_version = cached_colors.cache_version;
7033 if Some(cache_version) == known_cache_version {
7034 return None;
7035 } else {
7036 return Some(
7037 Task::ready(Ok(DocumentColors {
7038 colors: cached_colors
7039 .colors
7040 .values()
7041 .flatten()
7042 .cloned()
7043 .collect(),
7044 cache_version: Some(cache_version),
7045 }))
7046 .shared(),
7047 );
7048 }
7049 }
7050 }
7051 }
7052 }
7053
7054 let color_lsp_data = self
7055 .latest_lsp_data(&buffer, cx)
7056 .document_colors
7057 .get_or_insert_default();
7058 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7059 && !version_queried_for.changed_since(updating_for)
7060 {
7061 return Some(running_update.clone());
7062 }
7063 let buffer_version_queried_for = version_queried_for.clone();
7064 let new_task = cx
7065 .spawn(async move |lsp_store, cx| {
7066 cx.background_executor()
7067 .timer(Duration::from_millis(30))
7068 .await;
7069 let fetched_colors = lsp_store
7070 .update(cx, |lsp_store, cx| {
7071 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7072 })?
7073 .await
7074 .context("fetching document colors")
7075 .map_err(Arc::new);
7076 let fetched_colors = match fetched_colors {
7077 Ok(fetched_colors) => {
7078 if Some(true)
7079 == buffer
7080 .update(cx, |buffer, _| {
7081 buffer.version() != buffer_version_queried_for
7082 })
7083 .ok()
7084 {
7085 return Ok(DocumentColors::default());
7086 }
7087 fetched_colors
7088 }
7089 Err(e) => {
7090 lsp_store
7091 .update(cx, |lsp_store, _| {
7092 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7093 if let Some(document_colors) = &mut lsp_data.document_colors {
7094 document_colors.colors_update = None;
7095 }
7096 }
7097 })
7098 .ok();
7099 return Err(e);
7100 }
7101 };
7102
7103 lsp_store
7104 .update(cx, |lsp_store, cx| {
7105 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7106 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7107
7108 if let Some(fetched_colors) = fetched_colors {
7109 if lsp_data.buffer_version == buffer_version_queried_for {
7110 lsp_colors.colors.extend(fetched_colors);
7111 lsp_colors.cache_version += 1;
7112 } else if !lsp_data
7113 .buffer_version
7114 .changed_since(&buffer_version_queried_for)
7115 {
7116 lsp_data.buffer_version = buffer_version_queried_for;
7117 lsp_colors.colors = fetched_colors;
7118 lsp_colors.cache_version += 1;
7119 }
7120 }
7121 lsp_colors.colors_update = None;
7122 let colors = lsp_colors
7123 .colors
7124 .values()
7125 .flatten()
7126 .cloned()
7127 .collect::<HashSet<_>>();
7128 DocumentColors {
7129 colors,
7130 cache_version: Some(lsp_colors.cache_version),
7131 }
7132 })
7133 .map_err(Arc::new)
7134 })
7135 .shared();
7136 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7137 Some(new_task)
7138 }
7139
7140 fn fetch_document_colors_for_buffer(
7141 &mut self,
7142 buffer: &Entity<Buffer>,
7143 cx: &mut Context<Self>,
7144 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7145 if let Some((client, project_id)) = self.upstream_client() {
7146 let request = GetDocumentColor {};
7147 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7148 return Task::ready(Ok(None));
7149 }
7150
7151 let request_task = client.request_lsp(
7152 project_id,
7153 None,
7154 LSP_REQUEST_TIMEOUT,
7155 cx.background_executor().clone(),
7156 request.to_proto(project_id, buffer.read(cx)),
7157 );
7158 let buffer = buffer.clone();
7159 cx.spawn(async move |lsp_store, cx| {
7160 let Some(project) = lsp_store.upgrade() else {
7161 return Ok(None);
7162 };
7163 let colors = join_all(
7164 request_task
7165 .await
7166 .log_err()
7167 .flatten()
7168 .map(|response| response.payload)
7169 .unwrap_or_default()
7170 .into_iter()
7171 .map(|color_response| {
7172 let response = request.response_from_proto(
7173 color_response.response,
7174 project.clone(),
7175 buffer.clone(),
7176 cx.clone(),
7177 );
7178 async move {
7179 (
7180 LanguageServerId::from_proto(color_response.server_id),
7181 response.await.log_err().unwrap_or_default(),
7182 )
7183 }
7184 }),
7185 )
7186 .await
7187 .into_iter()
7188 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7189 acc.entry(server_id)
7190 .or_insert_with(HashSet::default)
7191 .extend(colors);
7192 acc
7193 });
7194 Ok(Some(colors))
7195 })
7196 } else {
7197 let document_colors_task =
7198 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7199 cx.background_spawn(async move {
7200 Ok(Some(
7201 document_colors_task
7202 .await
7203 .into_iter()
7204 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7205 acc.entry(server_id)
7206 .or_insert_with(HashSet::default)
7207 .extend(colors);
7208 acc
7209 })
7210 .into_iter()
7211 .collect(),
7212 ))
7213 })
7214 }
7215 }
7216
7217 pub fn signature_help<T: ToPointUtf16>(
7218 &mut self,
7219 buffer: &Entity<Buffer>,
7220 position: T,
7221 cx: &mut Context<Self>,
7222 ) -> Task<Option<Vec<SignatureHelp>>> {
7223 let position = position.to_point_utf16(buffer.read(cx));
7224
7225 if let Some((client, upstream_project_id)) = self.upstream_client() {
7226 let request = GetSignatureHelp { position };
7227 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7228 return Task::ready(None);
7229 }
7230 let request_task = client.request_lsp(
7231 upstream_project_id,
7232 None,
7233 LSP_REQUEST_TIMEOUT,
7234 cx.background_executor().clone(),
7235 request.to_proto(upstream_project_id, buffer.read(cx)),
7236 );
7237 let buffer = buffer.clone();
7238 cx.spawn(async move |weak_project, cx| {
7239 let project = weak_project.upgrade()?;
7240 let signatures = join_all(
7241 request_task
7242 .await
7243 .log_err()
7244 .flatten()
7245 .map(|response| response.payload)
7246 .unwrap_or_default()
7247 .into_iter()
7248 .map(|response| {
7249 let response = GetSignatureHelp { position }.response_from_proto(
7250 response.response,
7251 project.clone(),
7252 buffer.clone(),
7253 cx.clone(),
7254 );
7255 async move { response.await.log_err().flatten() }
7256 }),
7257 )
7258 .await
7259 .into_iter()
7260 .flatten()
7261 .collect();
7262 Some(signatures)
7263 })
7264 } else {
7265 let all_actions_task = self.request_multiple_lsp_locally(
7266 buffer,
7267 Some(position),
7268 GetSignatureHelp { position },
7269 cx,
7270 );
7271 cx.background_spawn(async move {
7272 Some(
7273 all_actions_task
7274 .await
7275 .into_iter()
7276 .flat_map(|(_, actions)| actions)
7277 .collect::<Vec<_>>(),
7278 )
7279 })
7280 }
7281 }
7282
7283 pub fn hover(
7284 &mut self,
7285 buffer: &Entity<Buffer>,
7286 position: PointUtf16,
7287 cx: &mut Context<Self>,
7288 ) -> Task<Option<Vec<Hover>>> {
7289 if let Some((client, upstream_project_id)) = self.upstream_client() {
7290 let request = GetHover { position };
7291 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7292 return Task::ready(None);
7293 }
7294 let request_task = client.request_lsp(
7295 upstream_project_id,
7296 None,
7297 LSP_REQUEST_TIMEOUT,
7298 cx.background_executor().clone(),
7299 request.to_proto(upstream_project_id, buffer.read(cx)),
7300 );
7301 let buffer = buffer.clone();
7302 cx.spawn(async move |weak_project, cx| {
7303 let project = weak_project.upgrade()?;
7304 let hovers = join_all(
7305 request_task
7306 .await
7307 .log_err()
7308 .flatten()
7309 .map(|response| response.payload)
7310 .unwrap_or_default()
7311 .into_iter()
7312 .map(|response| {
7313 let response = GetHover { position }.response_from_proto(
7314 response.response,
7315 project.clone(),
7316 buffer.clone(),
7317 cx.clone(),
7318 );
7319 async move {
7320 response
7321 .await
7322 .log_err()
7323 .flatten()
7324 .and_then(remove_empty_hover_blocks)
7325 }
7326 }),
7327 )
7328 .await
7329 .into_iter()
7330 .flatten()
7331 .collect();
7332 Some(hovers)
7333 })
7334 } else {
7335 let all_actions_task = self.request_multiple_lsp_locally(
7336 buffer,
7337 Some(position),
7338 GetHover { position },
7339 cx,
7340 );
7341 cx.background_spawn(async move {
7342 Some(
7343 all_actions_task
7344 .await
7345 .into_iter()
7346 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7347 .collect::<Vec<Hover>>(),
7348 )
7349 })
7350 }
7351 }
7352
7353 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7354 let language_registry = self.languages.clone();
7355
7356 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7357 let request = upstream_client.request(proto::GetProjectSymbols {
7358 project_id: *project_id,
7359 query: query.to_string(),
7360 });
7361 cx.foreground_executor().spawn(async move {
7362 let response = request.await?;
7363 let mut symbols = Vec::new();
7364 let core_symbols = response
7365 .symbols
7366 .into_iter()
7367 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7368 .collect::<Vec<_>>();
7369 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7370 .await;
7371 Ok(symbols)
7372 })
7373 } else if let Some(local) = self.as_local() {
7374 struct WorkspaceSymbolsResult {
7375 server_id: LanguageServerId,
7376 lsp_adapter: Arc<CachedLspAdapter>,
7377 worktree: WeakEntity<Worktree>,
7378 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7379 }
7380
7381 let mut requests = Vec::new();
7382 let mut requested_servers = BTreeSet::new();
7383 for (seed, state) in local.language_server_ids.iter() {
7384 let Some(worktree_handle) = self
7385 .worktree_store
7386 .read(cx)
7387 .worktree_for_id(seed.worktree_id, cx)
7388 else {
7389 continue;
7390 };
7391 let worktree = worktree_handle.read(cx);
7392 if !worktree.is_visible() {
7393 continue;
7394 }
7395
7396 if !requested_servers.insert(state.id) {
7397 continue;
7398 }
7399
7400 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7401 Some(LanguageServerState::Running {
7402 adapter, server, ..
7403 }) => (adapter.clone(), server),
7404
7405 _ => continue,
7406 };
7407 let supports_workspace_symbol_request =
7408 match server.capabilities().workspace_symbol_provider {
7409 Some(OneOf::Left(supported)) => supported,
7410 Some(OneOf::Right(_)) => true,
7411 None => false,
7412 };
7413 if !supports_workspace_symbol_request {
7414 continue;
7415 }
7416 let worktree_handle = worktree_handle.clone();
7417 let server_id = server.server_id();
7418 requests.push(
7419 server
7420 .request::<lsp::request::WorkspaceSymbolRequest>(
7421 lsp::WorkspaceSymbolParams {
7422 query: query.to_string(),
7423 ..Default::default()
7424 },
7425 )
7426 .map(move |response| {
7427 let lsp_symbols = response.into_response()
7428 .context("workspace symbols request")
7429 .log_err()
7430 .flatten()
7431 .map(|symbol_response| match symbol_response {
7432 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7433 flat_responses.into_iter().map(|lsp_symbol| {
7434 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7435 }).collect::<Vec<_>>()
7436 }
7437 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7438 nested_responses.into_iter().filter_map(|lsp_symbol| {
7439 let location = match lsp_symbol.location {
7440 OneOf::Left(location) => location,
7441 OneOf::Right(_) => {
7442 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7443 return None
7444 }
7445 };
7446 Some((lsp_symbol.name, lsp_symbol.kind, location))
7447 }).collect::<Vec<_>>()
7448 }
7449 }).unwrap_or_default();
7450
7451 WorkspaceSymbolsResult {
7452 server_id,
7453 lsp_adapter,
7454 worktree: worktree_handle.downgrade(),
7455 lsp_symbols,
7456 }
7457 }),
7458 );
7459 }
7460
7461 cx.spawn(async move |this, cx| {
7462 let responses = futures::future::join_all(requests).await;
7463 let this = match this.upgrade() {
7464 Some(this) => this,
7465 None => return Ok(Vec::new()),
7466 };
7467
7468 let mut symbols = Vec::new();
7469 for result in responses {
7470 let core_symbols = this.update(cx, |this, cx| {
7471 result
7472 .lsp_symbols
7473 .into_iter()
7474 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7475 let abs_path = symbol_location.uri.to_file_path().ok()?;
7476 let source_worktree = result.worktree.upgrade()?;
7477 let source_worktree_id = source_worktree.read(cx).id();
7478
7479 let path = if let Some((tree, rel_path)) =
7480 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7481 {
7482 let worktree_id = tree.read(cx).id();
7483 SymbolLocation::InProject(ProjectPath {
7484 worktree_id,
7485 path: rel_path,
7486 })
7487 } else {
7488 SymbolLocation::OutsideProject {
7489 signature: this.symbol_signature(&abs_path),
7490 abs_path: abs_path.into(),
7491 }
7492 };
7493
7494 Some(CoreSymbol {
7495 source_language_server_id: result.server_id,
7496 language_server_name: result.lsp_adapter.name.clone(),
7497 source_worktree_id,
7498 path,
7499 kind: symbol_kind,
7500 name: symbol_name,
7501 range: range_from_lsp(symbol_location.range),
7502 })
7503 })
7504 .collect()
7505 })?;
7506
7507 populate_labels_for_symbols(
7508 core_symbols,
7509 &language_registry,
7510 Some(result.lsp_adapter),
7511 &mut symbols,
7512 )
7513 .await;
7514 }
7515
7516 Ok(symbols)
7517 })
7518 } else {
7519 Task::ready(Err(anyhow!("No upstream client or local language server")))
7520 }
7521 }
7522
7523 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7524 let mut summary = DiagnosticSummary::default();
7525 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7526 summary.error_count += path_summary.error_count;
7527 summary.warning_count += path_summary.warning_count;
7528 }
7529 summary
7530 }
7531
7532 /// Returns the diagnostic summary for a specific project path.
7533 pub fn diagnostic_summary_for_path(
7534 &self,
7535 project_path: &ProjectPath,
7536 _: &App,
7537 ) -> DiagnosticSummary {
7538 if let Some(summaries) = self
7539 .diagnostic_summaries
7540 .get(&project_path.worktree_id)
7541 .and_then(|map| map.get(&project_path.path))
7542 {
7543 let (error_count, warning_count) = summaries.iter().fold(
7544 (0, 0),
7545 |(error_count, warning_count), (_language_server_id, summary)| {
7546 (
7547 error_count + summary.error_count,
7548 warning_count + summary.warning_count,
7549 )
7550 },
7551 );
7552
7553 DiagnosticSummary {
7554 error_count,
7555 warning_count,
7556 }
7557 } else {
7558 DiagnosticSummary::default()
7559 }
7560 }
7561
7562 pub fn diagnostic_summaries<'a>(
7563 &'a self,
7564 include_ignored: bool,
7565 cx: &'a App,
7566 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7567 self.worktree_store
7568 .read(cx)
7569 .visible_worktrees(cx)
7570 .filter_map(|worktree| {
7571 let worktree = worktree.read(cx);
7572 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7573 })
7574 .flat_map(move |(worktree, summaries)| {
7575 let worktree_id = worktree.id();
7576 summaries
7577 .iter()
7578 .filter(move |(path, _)| {
7579 include_ignored
7580 || worktree
7581 .entry_for_path(path.as_ref())
7582 .is_some_and(|entry| !entry.is_ignored)
7583 })
7584 .flat_map(move |(path, summaries)| {
7585 summaries.iter().map(move |(server_id, summary)| {
7586 (
7587 ProjectPath {
7588 worktree_id,
7589 path: path.clone(),
7590 },
7591 *server_id,
7592 *summary,
7593 )
7594 })
7595 })
7596 })
7597 }
7598
7599 pub fn on_buffer_edited(
7600 &mut self,
7601 buffer: Entity<Buffer>,
7602 cx: &mut Context<Self>,
7603 ) -> Option<()> {
7604 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7605 Some(
7606 self.as_local()?
7607 .language_servers_for_buffer(buffer, cx)
7608 .map(|i| i.1.clone())
7609 .collect(),
7610 )
7611 })?;
7612
7613 let buffer = buffer.read(cx);
7614 let file = File::from_dyn(buffer.file())?;
7615 let abs_path = file.as_local()?.abs_path(cx);
7616 let uri = lsp::Uri::from_file_path(abs_path).unwrap();
7617 let next_snapshot = buffer.text_snapshot();
7618 for language_server in language_servers {
7619 let language_server = language_server.clone();
7620
7621 let buffer_snapshots = self
7622 .as_local_mut()
7623 .unwrap()
7624 .buffer_snapshots
7625 .get_mut(&buffer.remote_id())
7626 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7627 let previous_snapshot = buffer_snapshots.last()?;
7628
7629 let build_incremental_change = || {
7630 buffer
7631 .edits_since::<Dimensions<PointUtf16, usize>>(
7632 previous_snapshot.snapshot.version(),
7633 )
7634 .map(|edit| {
7635 let edit_start = edit.new.start.0;
7636 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7637 let new_text = next_snapshot
7638 .text_for_range(edit.new.start.1..edit.new.end.1)
7639 .collect();
7640 lsp::TextDocumentContentChangeEvent {
7641 range: Some(lsp::Range::new(
7642 point_to_lsp(edit_start),
7643 point_to_lsp(edit_end),
7644 )),
7645 range_length: None,
7646 text: new_text,
7647 }
7648 })
7649 .collect()
7650 };
7651
7652 let document_sync_kind = language_server
7653 .capabilities()
7654 .text_document_sync
7655 .as_ref()
7656 .and_then(|sync| match sync {
7657 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7658 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7659 });
7660
7661 let content_changes: Vec<_> = match document_sync_kind {
7662 Some(lsp::TextDocumentSyncKind::FULL) => {
7663 vec![lsp::TextDocumentContentChangeEvent {
7664 range: None,
7665 range_length: None,
7666 text: next_snapshot.text(),
7667 }]
7668 }
7669 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7670 _ => {
7671 #[cfg(any(test, feature = "test-support"))]
7672 {
7673 build_incremental_change()
7674 }
7675
7676 #[cfg(not(any(test, feature = "test-support")))]
7677 {
7678 continue;
7679 }
7680 }
7681 };
7682
7683 let next_version = previous_snapshot.version + 1;
7684 buffer_snapshots.push(LspBufferSnapshot {
7685 version: next_version,
7686 snapshot: next_snapshot.clone(),
7687 });
7688
7689 language_server
7690 .notify::<lsp::notification::DidChangeTextDocument>(
7691 lsp::DidChangeTextDocumentParams {
7692 text_document: lsp::VersionedTextDocumentIdentifier::new(
7693 uri.clone(),
7694 next_version,
7695 ),
7696 content_changes,
7697 },
7698 )
7699 .ok();
7700 self.pull_workspace_diagnostics(language_server.server_id());
7701 }
7702
7703 None
7704 }
7705
7706 pub fn on_buffer_saved(
7707 &mut self,
7708 buffer: Entity<Buffer>,
7709 cx: &mut Context<Self>,
7710 ) -> Option<()> {
7711 let file = File::from_dyn(buffer.read(cx).file())?;
7712 let worktree_id = file.worktree_id(cx);
7713 let abs_path = file.as_local()?.abs_path(cx);
7714 let text_document = lsp::TextDocumentIdentifier {
7715 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7716 };
7717 let local = self.as_local()?;
7718
7719 for server in local.language_servers_for_worktree(worktree_id) {
7720 if let Some(include_text) = include_text(server.as_ref()) {
7721 let text = if include_text {
7722 Some(buffer.read(cx).text())
7723 } else {
7724 None
7725 };
7726 server
7727 .notify::<lsp::notification::DidSaveTextDocument>(
7728 lsp::DidSaveTextDocumentParams {
7729 text_document: text_document.clone(),
7730 text,
7731 },
7732 )
7733 .ok();
7734 }
7735 }
7736
7737 let language_servers = buffer.update(cx, |buffer, cx| {
7738 local.language_server_ids_for_buffer(buffer, cx)
7739 });
7740 for language_server_id in language_servers {
7741 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7742 }
7743
7744 None
7745 }
7746
7747 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7748 maybe!(async move {
7749 let mut refreshed_servers = HashSet::default();
7750 let servers = lsp_store
7751 .update(cx, |lsp_store, cx| {
7752 let local = lsp_store.as_local()?;
7753
7754 let servers = local
7755 .language_server_ids
7756 .iter()
7757 .filter_map(|(seed, state)| {
7758 let worktree = lsp_store
7759 .worktree_store
7760 .read(cx)
7761 .worktree_for_id(seed.worktree_id, cx);
7762 let delegate: Arc<dyn LspAdapterDelegate> =
7763 worktree.map(|worktree| {
7764 LocalLspAdapterDelegate::new(
7765 local.languages.clone(),
7766 &local.environment,
7767 cx.weak_entity(),
7768 &worktree,
7769 local.http_client.clone(),
7770 local.fs.clone(),
7771 cx,
7772 )
7773 })?;
7774 let server_id = state.id;
7775
7776 let states = local.language_servers.get(&server_id)?;
7777
7778 match states {
7779 LanguageServerState::Starting { .. } => None,
7780 LanguageServerState::Running {
7781 adapter, server, ..
7782 } => {
7783 let adapter = adapter.clone();
7784 let server = server.clone();
7785 refreshed_servers.insert(server.name());
7786 let toolchain = seed.toolchain.clone();
7787 Some(cx.spawn(async move |_, cx| {
7788 let settings =
7789 LocalLspStore::workspace_configuration_for_adapter(
7790 adapter.adapter.clone(),
7791 &delegate,
7792 toolchain,
7793 cx,
7794 )
7795 .await
7796 .ok()?;
7797 server
7798 .notify::<lsp::notification::DidChangeConfiguration>(
7799 lsp::DidChangeConfigurationParams { settings },
7800 )
7801 .ok()?;
7802 Some(())
7803 }))
7804 }
7805 }
7806 })
7807 .collect::<Vec<_>>();
7808
7809 Some(servers)
7810 })
7811 .ok()
7812 .flatten()?;
7813
7814 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7815 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7816 // to stop and unregister its language server wrapper.
7817 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7818 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7819 let _: Vec<Option<()>> = join_all(servers).await;
7820
7821 Some(())
7822 })
7823 .await;
7824 }
7825
7826 fn maintain_workspace_config(
7827 external_refresh_requests: watch::Receiver<()>,
7828 cx: &mut Context<Self>,
7829 ) -> Task<Result<()>> {
7830 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7831 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7832
7833 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7834 *settings_changed_tx.borrow_mut() = ();
7835 });
7836
7837 let mut joint_future =
7838 futures::stream::select(settings_changed_rx, external_refresh_requests);
7839 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
7840 // - 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).
7841 // - 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.
7842 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
7843 // - 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,
7844 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
7845 cx.spawn(async move |this, cx| {
7846 while let Some(()) = joint_future.next().await {
7847 this.update(cx, |this, cx| {
7848 this.refresh_server_tree(cx);
7849 })
7850 .ok();
7851
7852 Self::refresh_workspace_configurations(&this, cx).await;
7853 }
7854
7855 drop(settings_observation);
7856 anyhow::Ok(())
7857 })
7858 }
7859
7860 pub fn language_servers_for_local_buffer<'a>(
7861 &'a self,
7862 buffer: &Buffer,
7863 cx: &mut App,
7864 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7865 let local = self.as_local();
7866 let language_server_ids = local
7867 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7868 .unwrap_or_default();
7869
7870 language_server_ids
7871 .into_iter()
7872 .filter_map(
7873 move |server_id| match local?.language_servers.get(&server_id)? {
7874 LanguageServerState::Running {
7875 adapter, server, ..
7876 } => Some((adapter, server)),
7877 _ => None,
7878 },
7879 )
7880 }
7881
7882 pub fn language_server_for_local_buffer<'a>(
7883 &'a self,
7884 buffer: &'a Buffer,
7885 server_id: LanguageServerId,
7886 cx: &'a mut App,
7887 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7888 self.as_local()?
7889 .language_servers_for_buffer(buffer, cx)
7890 .find(|(_, s)| s.server_id() == server_id)
7891 }
7892
7893 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7894 self.diagnostic_summaries.remove(&id_to_remove);
7895 if let Some(local) = self.as_local_mut() {
7896 let to_remove = local.remove_worktree(id_to_remove, cx);
7897 for server in to_remove {
7898 self.language_server_statuses.remove(&server);
7899 }
7900 }
7901 }
7902
7903 pub fn shared(
7904 &mut self,
7905 project_id: u64,
7906 downstream_client: AnyProtoClient,
7907 _: &mut Context<Self>,
7908 ) {
7909 self.downstream_client = Some((downstream_client.clone(), project_id));
7910
7911 for (server_id, status) in &self.language_server_statuses {
7912 if let Some(server) = self.language_server_for_id(*server_id) {
7913 downstream_client
7914 .send(proto::StartLanguageServer {
7915 project_id,
7916 server: Some(proto::LanguageServer {
7917 id: server_id.to_proto(),
7918 name: status.name.to_string(),
7919 worktree_id: status.worktree.map(|id| id.to_proto()),
7920 }),
7921 capabilities: serde_json::to_string(&server.capabilities())
7922 .expect("serializing server LSP capabilities"),
7923 })
7924 .log_err();
7925 }
7926 }
7927 }
7928
7929 pub fn disconnected_from_host(&mut self) {
7930 self.downstream_client.take();
7931 }
7932
7933 pub fn disconnected_from_ssh_remote(&mut self) {
7934 if let LspStoreMode::Remote(RemoteLspStore {
7935 upstream_client, ..
7936 }) = &mut self.mode
7937 {
7938 upstream_client.take();
7939 }
7940 }
7941
7942 pub(crate) fn set_language_server_statuses_from_proto(
7943 &mut self,
7944 project: WeakEntity<Project>,
7945 language_servers: Vec<proto::LanguageServer>,
7946 server_capabilities: Vec<String>,
7947 cx: &mut Context<Self>,
7948 ) {
7949 let lsp_logs = cx
7950 .try_global::<GlobalLogStore>()
7951 .map(|lsp_store| lsp_store.0.clone());
7952
7953 self.language_server_statuses = language_servers
7954 .into_iter()
7955 .zip(server_capabilities)
7956 .map(|(server, server_capabilities)| {
7957 let server_id = LanguageServerId(server.id as usize);
7958 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
7959 self.lsp_server_capabilities
7960 .insert(server_id, server_capabilities);
7961 }
7962
7963 let name = LanguageServerName::from_proto(server.name);
7964 let worktree = server.worktree_id.map(WorktreeId::from_proto);
7965
7966 if let Some(lsp_logs) = &lsp_logs {
7967 lsp_logs.update(cx, |lsp_logs, cx| {
7968 lsp_logs.add_language_server(
7969 // Only remote clients get their language servers set from proto
7970 LanguageServerKind::Remote {
7971 project: project.clone(),
7972 },
7973 server_id,
7974 Some(name.clone()),
7975 worktree,
7976 None,
7977 cx,
7978 );
7979 });
7980 }
7981
7982 (
7983 server_id,
7984 LanguageServerStatus {
7985 name,
7986 pending_work: Default::default(),
7987 has_pending_diagnostic_updates: false,
7988 progress_tokens: Default::default(),
7989 worktree,
7990 },
7991 )
7992 })
7993 .collect();
7994 }
7995
7996 #[cfg(test)]
7997 pub fn update_diagnostic_entries(
7998 &mut self,
7999 server_id: LanguageServerId,
8000 abs_path: PathBuf,
8001 result_id: Option<String>,
8002 version: Option<i32>,
8003 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8004 cx: &mut Context<Self>,
8005 ) -> anyhow::Result<()> {
8006 self.merge_diagnostic_entries(
8007 vec![DocumentDiagnosticsUpdate {
8008 diagnostics: DocumentDiagnostics {
8009 diagnostics,
8010 document_abs_path: abs_path,
8011 version,
8012 },
8013 result_id,
8014 server_id,
8015 disk_based_sources: Cow::Borrowed(&[]),
8016 }],
8017 |_, _, _| false,
8018 cx,
8019 )?;
8020 Ok(())
8021 }
8022
8023 pub fn merge_diagnostic_entries<'a>(
8024 &mut self,
8025 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8026 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
8027 cx: &mut Context<Self>,
8028 ) -> anyhow::Result<()> {
8029 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8030 let mut updated_diagnostics_paths = HashMap::default();
8031 for mut update in diagnostic_updates {
8032 let abs_path = &update.diagnostics.document_abs_path;
8033 let server_id = update.server_id;
8034 let Some((worktree, relative_path)) =
8035 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8036 else {
8037 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8038 return Ok(());
8039 };
8040
8041 let worktree_id = worktree.read(cx).id();
8042 let project_path = ProjectPath {
8043 worktree_id,
8044 path: relative_path,
8045 };
8046
8047 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8048 let snapshot = buffer_handle.read(cx).snapshot();
8049 let buffer = buffer_handle.read(cx);
8050 let reused_diagnostics = buffer
8051 .buffer_diagnostics(Some(server_id))
8052 .iter()
8053 .filter(|v| merge(buffer, &v.diagnostic, cx))
8054 .map(|v| {
8055 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8056 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8057 DiagnosticEntry {
8058 range: start..end,
8059 diagnostic: v.diagnostic.clone(),
8060 }
8061 })
8062 .collect::<Vec<_>>();
8063
8064 self.as_local_mut()
8065 .context("cannot merge diagnostics on a remote LspStore")?
8066 .update_buffer_diagnostics(
8067 &buffer_handle,
8068 server_id,
8069 update.result_id,
8070 update.diagnostics.version,
8071 update.diagnostics.diagnostics.clone(),
8072 reused_diagnostics.clone(),
8073 cx,
8074 )?;
8075
8076 update.diagnostics.diagnostics.extend(reused_diagnostics);
8077 }
8078
8079 let updated = worktree.update(cx, |worktree, cx| {
8080 self.update_worktree_diagnostics(
8081 worktree.id(),
8082 server_id,
8083 project_path.path.clone(),
8084 update.diagnostics.diagnostics,
8085 cx,
8086 )
8087 })?;
8088 match updated {
8089 ControlFlow::Continue(new_summary) => {
8090 if let Some((project_id, new_summary)) = new_summary {
8091 match &mut diagnostics_summary {
8092 Some(diagnostics_summary) => {
8093 diagnostics_summary
8094 .more_summaries
8095 .push(proto::DiagnosticSummary {
8096 path: project_path.path.as_ref().to_proto(),
8097 language_server_id: server_id.0 as u64,
8098 error_count: new_summary.error_count,
8099 warning_count: new_summary.warning_count,
8100 })
8101 }
8102 None => {
8103 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8104 project_id,
8105 worktree_id: worktree_id.to_proto(),
8106 summary: Some(proto::DiagnosticSummary {
8107 path: project_path.path.as_ref().to_proto(),
8108 language_server_id: server_id.0 as u64,
8109 error_count: new_summary.error_count,
8110 warning_count: new_summary.warning_count,
8111 }),
8112 more_summaries: Vec::new(),
8113 })
8114 }
8115 }
8116 }
8117 updated_diagnostics_paths
8118 .entry(server_id)
8119 .or_insert_with(Vec::new)
8120 .push(project_path);
8121 }
8122 ControlFlow::Break(()) => {}
8123 }
8124 }
8125
8126 if let Some((diagnostics_summary, (downstream_client, _))) =
8127 diagnostics_summary.zip(self.downstream_client.as_ref())
8128 {
8129 downstream_client.send(diagnostics_summary).log_err();
8130 }
8131 for (server_id, paths) in updated_diagnostics_paths {
8132 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8133 }
8134 Ok(())
8135 }
8136
8137 fn update_worktree_diagnostics(
8138 &mut self,
8139 worktree_id: WorktreeId,
8140 server_id: LanguageServerId,
8141 path_in_worktree: Arc<RelPath>,
8142 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8143 _: &mut Context<Worktree>,
8144 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8145 let local = match &mut self.mode {
8146 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8147 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8148 };
8149
8150 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8151 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8152 let summaries_by_server_id = summaries_for_tree
8153 .entry(path_in_worktree.clone())
8154 .or_default();
8155
8156 let old_summary = summaries_by_server_id
8157 .remove(&server_id)
8158 .unwrap_or_default();
8159
8160 let new_summary = DiagnosticSummary::new(&diagnostics);
8161 if new_summary.is_empty() {
8162 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8163 {
8164 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8165 diagnostics_by_server_id.remove(ix);
8166 }
8167 if diagnostics_by_server_id.is_empty() {
8168 diagnostics_for_tree.remove(&path_in_worktree);
8169 }
8170 }
8171 } else {
8172 summaries_by_server_id.insert(server_id, new_summary);
8173 let diagnostics_by_server_id = diagnostics_for_tree
8174 .entry(path_in_worktree.clone())
8175 .or_default();
8176 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8177 Ok(ix) => {
8178 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8179 }
8180 Err(ix) => {
8181 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8182 }
8183 }
8184 }
8185
8186 if !old_summary.is_empty() || !new_summary.is_empty() {
8187 if let Some((_, project_id)) = &self.downstream_client {
8188 Ok(ControlFlow::Continue(Some((
8189 *project_id,
8190 proto::DiagnosticSummary {
8191 path: path_in_worktree.to_proto(),
8192 language_server_id: server_id.0 as u64,
8193 error_count: new_summary.error_count as u32,
8194 warning_count: new_summary.warning_count as u32,
8195 },
8196 ))))
8197 } else {
8198 Ok(ControlFlow::Continue(None))
8199 }
8200 } else {
8201 Ok(ControlFlow::Break(()))
8202 }
8203 }
8204
8205 pub fn open_buffer_for_symbol(
8206 &mut self,
8207 symbol: &Symbol,
8208 cx: &mut Context<Self>,
8209 ) -> Task<Result<Entity<Buffer>>> {
8210 if let Some((client, project_id)) = self.upstream_client() {
8211 let request = client.request(proto::OpenBufferForSymbol {
8212 project_id,
8213 symbol: Some(Self::serialize_symbol(symbol)),
8214 });
8215 cx.spawn(async move |this, cx| {
8216 let response = request.await?;
8217 let buffer_id = BufferId::new(response.buffer_id)?;
8218 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8219 .await
8220 })
8221 } else if let Some(local) = self.as_local() {
8222 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8223 seed.worktree_id == symbol.source_worktree_id
8224 && state.id == symbol.source_language_server_id
8225 && symbol.language_server_name == seed.name
8226 });
8227 if !is_valid {
8228 return Task::ready(Err(anyhow!(
8229 "language server for worktree and language not found"
8230 )));
8231 };
8232
8233 let symbol_abs_path = match &symbol.path {
8234 SymbolLocation::InProject(project_path) => self
8235 .worktree_store
8236 .read(cx)
8237 .absolutize(&project_path, cx)
8238 .context("no such worktree"),
8239 SymbolLocation::OutsideProject {
8240 abs_path,
8241 signature: _,
8242 } => Ok(abs_path.to_path_buf()),
8243 };
8244 let symbol_abs_path = match symbol_abs_path {
8245 Ok(abs_path) => abs_path,
8246 Err(err) => return Task::ready(Err(err)),
8247 };
8248 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8249 uri
8250 } else {
8251 return Task::ready(Err(anyhow!("invalid symbol path")));
8252 };
8253
8254 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8255 } else {
8256 Task::ready(Err(anyhow!("no upstream client or local store")))
8257 }
8258 }
8259
8260 pub(crate) fn open_local_buffer_via_lsp(
8261 &mut self,
8262 abs_path: lsp::Uri,
8263 language_server_id: LanguageServerId,
8264 cx: &mut Context<Self>,
8265 ) -> Task<Result<Entity<Buffer>>> {
8266 cx.spawn(async move |lsp_store, cx| {
8267 // Escape percent-encoded string.
8268 let current_scheme = abs_path.scheme().to_owned();
8269 // Uri is immutable, so we can't modify the scheme
8270
8271 let abs_path = abs_path
8272 .to_file_path()
8273 .map_err(|()| anyhow!("can't convert URI to path"))?;
8274 let p = abs_path.clone();
8275 let yarn_worktree = lsp_store
8276 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8277 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8278 cx.spawn(async move |this, cx| {
8279 let t = this
8280 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8281 .ok()?;
8282 t.await
8283 })
8284 }),
8285 None => Task::ready(None),
8286 })?
8287 .await;
8288 let (worktree_root_target, known_relative_path) =
8289 if let Some((zip_root, relative_path)) = yarn_worktree {
8290 (zip_root, Some(relative_path))
8291 } else {
8292 (Arc::<Path>::from(abs_path.as_path()), None)
8293 };
8294 let (worktree, relative_path) = if let Some(result) =
8295 lsp_store.update(cx, |lsp_store, cx| {
8296 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8297 worktree_store.find_worktree(&worktree_root_target, cx)
8298 })
8299 })? {
8300 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8301 (result.0, relative_path)
8302 } else {
8303 let worktree = lsp_store
8304 .update(cx, |lsp_store, cx| {
8305 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8306 worktree_store.create_worktree(&worktree_root_target, false, cx)
8307 })
8308 })?
8309 .await?;
8310 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8311 lsp_store
8312 .update(cx, |lsp_store, cx| {
8313 if let Some(local) = lsp_store.as_local_mut() {
8314 local.register_language_server_for_invisible_worktree(
8315 &worktree,
8316 language_server_id,
8317 cx,
8318 )
8319 }
8320 })
8321 .ok();
8322 }
8323 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8324 let relative_path = if let Some(known_path) = known_relative_path {
8325 known_path
8326 } else {
8327 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8328 .into_arc()
8329 };
8330 (worktree, relative_path)
8331 };
8332 let project_path = ProjectPath {
8333 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8334 path: relative_path,
8335 };
8336 lsp_store
8337 .update(cx, |lsp_store, cx| {
8338 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8339 buffer_store.open_buffer(project_path, cx)
8340 })
8341 })?
8342 .await
8343 })
8344 }
8345
8346 fn request_multiple_lsp_locally<P, R>(
8347 &mut self,
8348 buffer: &Entity<Buffer>,
8349 position: Option<P>,
8350 request: R,
8351 cx: &mut Context<Self>,
8352 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8353 where
8354 P: ToOffset,
8355 R: LspCommand + Clone,
8356 <R::LspRequest as lsp::request::Request>::Result: Send,
8357 <R::LspRequest as lsp::request::Request>::Params: Send,
8358 {
8359 let Some(local) = self.as_local() else {
8360 return Task::ready(Vec::new());
8361 };
8362
8363 let snapshot = buffer.read(cx).snapshot();
8364 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8365
8366 let server_ids = buffer.update(cx, |buffer, cx| {
8367 local
8368 .language_servers_for_buffer(buffer, cx)
8369 .filter(|(adapter, _)| {
8370 scope
8371 .as_ref()
8372 .map(|scope| scope.language_allowed(&adapter.name))
8373 .unwrap_or(true)
8374 })
8375 .map(|(_, server)| server.server_id())
8376 .filter(|server_id| {
8377 self.as_local().is_none_or(|local| {
8378 local
8379 .buffers_opened_in_servers
8380 .get(&snapshot.remote_id())
8381 .is_some_and(|servers| servers.contains(server_id))
8382 })
8383 })
8384 .collect::<Vec<_>>()
8385 });
8386
8387 let mut response_results = server_ids
8388 .into_iter()
8389 .map(|server_id| {
8390 let task = self.request_lsp(
8391 buffer.clone(),
8392 LanguageServerToQuery::Other(server_id),
8393 request.clone(),
8394 cx,
8395 );
8396 async move { (server_id, task.await) }
8397 })
8398 .collect::<FuturesUnordered<_>>();
8399
8400 cx.background_spawn(async move {
8401 let mut responses = Vec::with_capacity(response_results.len());
8402 while let Some((server_id, response_result)) = response_results.next().await {
8403 match response_result {
8404 Ok(response) => responses.push((server_id, response)),
8405 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8406 }
8407 }
8408 responses
8409 })
8410 }
8411
8412 async fn handle_lsp_command<T: LspCommand>(
8413 this: Entity<Self>,
8414 envelope: TypedEnvelope<T::ProtoRequest>,
8415 mut cx: AsyncApp,
8416 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8417 where
8418 <T::LspRequest as lsp::request::Request>::Params: Send,
8419 <T::LspRequest as lsp::request::Request>::Result: Send,
8420 {
8421 let sender_id = envelope.original_sender_id().unwrap_or_default();
8422 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8423 let buffer_handle = this.update(&mut cx, |this, cx| {
8424 this.buffer_store.read(cx).get_existing(buffer_id)
8425 })??;
8426 let request = T::from_proto(
8427 envelope.payload,
8428 this.clone(),
8429 buffer_handle.clone(),
8430 cx.clone(),
8431 )
8432 .await?;
8433 let response = this
8434 .update(&mut cx, |this, cx| {
8435 this.request_lsp(
8436 buffer_handle.clone(),
8437 LanguageServerToQuery::FirstCapable,
8438 request,
8439 cx,
8440 )
8441 })?
8442 .await?;
8443 this.update(&mut cx, |this, cx| {
8444 Ok(T::response_to_proto(
8445 response,
8446 this,
8447 sender_id,
8448 &buffer_handle.read(cx).version(),
8449 cx,
8450 ))
8451 })?
8452 }
8453
8454 async fn handle_lsp_query(
8455 lsp_store: Entity<Self>,
8456 envelope: TypedEnvelope<proto::LspQuery>,
8457 mut cx: AsyncApp,
8458 ) -> Result<proto::Ack> {
8459 use proto::lsp_query::Request;
8460 let sender_id = envelope.original_sender_id().unwrap_or_default();
8461 let lsp_query = envelope.payload;
8462 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8463 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8464 match lsp_query.request.context("invalid LSP query request")? {
8465 Request::GetReferences(get_references) => {
8466 let position = get_references.position.clone().and_then(deserialize_anchor);
8467 Self::query_lsp_locally::<GetReferences>(
8468 lsp_store,
8469 server_id,
8470 sender_id,
8471 lsp_request_id,
8472 get_references,
8473 position,
8474 &mut cx,
8475 )
8476 .await?;
8477 }
8478 Request::GetDocumentColor(get_document_color) => {
8479 Self::query_lsp_locally::<GetDocumentColor>(
8480 lsp_store,
8481 server_id,
8482 sender_id,
8483 lsp_request_id,
8484 get_document_color,
8485 None,
8486 &mut cx,
8487 )
8488 .await?;
8489 }
8490 Request::GetHover(get_hover) => {
8491 let position = get_hover.position.clone().and_then(deserialize_anchor);
8492 Self::query_lsp_locally::<GetHover>(
8493 lsp_store,
8494 server_id,
8495 sender_id,
8496 lsp_request_id,
8497 get_hover,
8498 position,
8499 &mut cx,
8500 )
8501 .await?;
8502 }
8503 Request::GetCodeActions(get_code_actions) => {
8504 Self::query_lsp_locally::<GetCodeActions>(
8505 lsp_store,
8506 server_id,
8507 sender_id,
8508 lsp_request_id,
8509 get_code_actions,
8510 None,
8511 &mut cx,
8512 )
8513 .await?;
8514 }
8515 Request::GetSignatureHelp(get_signature_help) => {
8516 let position = get_signature_help
8517 .position
8518 .clone()
8519 .and_then(deserialize_anchor);
8520 Self::query_lsp_locally::<GetSignatureHelp>(
8521 lsp_store,
8522 server_id,
8523 sender_id,
8524 lsp_request_id,
8525 get_signature_help,
8526 position,
8527 &mut cx,
8528 )
8529 .await?;
8530 }
8531 Request::GetCodeLens(get_code_lens) => {
8532 Self::query_lsp_locally::<GetCodeLens>(
8533 lsp_store,
8534 server_id,
8535 sender_id,
8536 lsp_request_id,
8537 get_code_lens,
8538 None,
8539 &mut cx,
8540 )
8541 .await?;
8542 }
8543 Request::GetDefinition(get_definition) => {
8544 let position = get_definition.position.clone().and_then(deserialize_anchor);
8545 Self::query_lsp_locally::<GetDefinitions>(
8546 lsp_store,
8547 server_id,
8548 sender_id,
8549 lsp_request_id,
8550 get_definition,
8551 position,
8552 &mut cx,
8553 )
8554 .await?;
8555 }
8556 Request::GetDeclaration(get_declaration) => {
8557 let position = get_declaration
8558 .position
8559 .clone()
8560 .and_then(deserialize_anchor);
8561 Self::query_lsp_locally::<GetDeclarations>(
8562 lsp_store,
8563 server_id,
8564 sender_id,
8565 lsp_request_id,
8566 get_declaration,
8567 position,
8568 &mut cx,
8569 )
8570 .await?;
8571 }
8572 Request::GetTypeDefinition(get_type_definition) => {
8573 let position = get_type_definition
8574 .position
8575 .clone()
8576 .and_then(deserialize_anchor);
8577 Self::query_lsp_locally::<GetTypeDefinitions>(
8578 lsp_store,
8579 server_id,
8580 sender_id,
8581 lsp_request_id,
8582 get_type_definition,
8583 position,
8584 &mut cx,
8585 )
8586 .await?;
8587 }
8588 Request::GetImplementation(get_implementation) => {
8589 let position = get_implementation
8590 .position
8591 .clone()
8592 .and_then(deserialize_anchor);
8593 Self::query_lsp_locally::<GetImplementations>(
8594 lsp_store,
8595 server_id,
8596 sender_id,
8597 lsp_request_id,
8598 get_implementation,
8599 position,
8600 &mut cx,
8601 )
8602 .await?;
8603 }
8604 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8605 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
8606 let version = deserialize_version(get_document_diagnostics.buffer_version());
8607 let buffer = lsp_store.update(&mut cx, |this, cx| {
8608 this.buffer_store.read(cx).get_existing(buffer_id)
8609 })??;
8610 buffer
8611 .update(&mut cx, |buffer, _| {
8612 buffer.wait_for_version(version.clone())
8613 })?
8614 .await?;
8615 lsp_store.update(&mut cx, |lsp_store, cx| {
8616 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8617 let key = LspKey {
8618 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8619 server_queried: server_id,
8620 };
8621 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8622 ) {
8623 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8624 lsp_requests.clear();
8625 };
8626 }
8627
8628 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
8629 existing_queries.insert(
8630 lsp_request_id,
8631 cx.spawn(async move |lsp_store, cx| {
8632 let diagnostics_pull = lsp_store
8633 .update(cx, |lsp_store, cx| {
8634 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8635 })
8636 .ok();
8637 if let Some(diagnostics_pull) = diagnostics_pull {
8638 match diagnostics_pull.await {
8639 Ok(()) => {}
8640 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
8641 };
8642 }
8643 }),
8644 );
8645 })?;
8646 }
8647 Request::InlayHints(inlay_hints) => {
8648 let query_start = inlay_hints
8649 .start
8650 .clone()
8651 .and_then(deserialize_anchor)
8652 .context("invalid inlay hints range start")?;
8653 let query_end = inlay_hints
8654 .end
8655 .clone()
8656 .and_then(deserialize_anchor)
8657 .context("invalid inlay hints range end")?;
8658 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8659 &lsp_store,
8660 server_id,
8661 lsp_request_id,
8662 &inlay_hints,
8663 query_start..query_end,
8664 &mut cx,
8665 )
8666 .await
8667 .context("preparing inlay hints request")?;
8668 Self::query_lsp_locally::<InlayHints>(
8669 lsp_store,
8670 server_id,
8671 sender_id,
8672 lsp_request_id,
8673 inlay_hints,
8674 None,
8675 &mut cx,
8676 )
8677 .await
8678 .context("querying for inlay hints")?
8679 }
8680 }
8681 Ok(proto::Ack {})
8682 }
8683
8684 async fn handle_lsp_query_response(
8685 lsp_store: Entity<Self>,
8686 envelope: TypedEnvelope<proto::LspQueryResponse>,
8687 cx: AsyncApp,
8688 ) -> Result<()> {
8689 lsp_store.read_with(&cx, |lsp_store, _| {
8690 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
8691 upstream_client.handle_lsp_response(envelope.clone());
8692 }
8693 })?;
8694 Ok(())
8695 }
8696
8697 async fn handle_apply_code_action(
8698 this: Entity<Self>,
8699 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8700 mut cx: AsyncApp,
8701 ) -> Result<proto::ApplyCodeActionResponse> {
8702 let sender_id = envelope.original_sender_id().unwrap_or_default();
8703 let action =
8704 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8705 let apply_code_action = this.update(&mut cx, |this, cx| {
8706 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8707 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8708 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8709 })??;
8710
8711 let project_transaction = apply_code_action.await?;
8712 let project_transaction = this.update(&mut cx, |this, cx| {
8713 this.buffer_store.update(cx, |buffer_store, cx| {
8714 buffer_store.serialize_project_transaction_for_peer(
8715 project_transaction,
8716 sender_id,
8717 cx,
8718 )
8719 })
8720 })?;
8721 Ok(proto::ApplyCodeActionResponse {
8722 transaction: Some(project_transaction),
8723 })
8724 }
8725
8726 async fn handle_register_buffer_with_language_servers(
8727 this: Entity<Self>,
8728 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8729 mut cx: AsyncApp,
8730 ) -> Result<proto::Ack> {
8731 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8732 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8733 this.update(&mut cx, |this, cx| {
8734 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8735 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8736 project_id: upstream_project_id,
8737 buffer_id: buffer_id.to_proto(),
8738 only_servers: envelope.payload.only_servers,
8739 });
8740 }
8741
8742 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8743 anyhow::bail!("buffer is not open");
8744 };
8745
8746 let handle = this.register_buffer_with_language_servers(
8747 &buffer,
8748 envelope
8749 .payload
8750 .only_servers
8751 .into_iter()
8752 .filter_map(|selector| {
8753 Some(match selector.selector? {
8754 proto::language_server_selector::Selector::ServerId(server_id) => {
8755 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8756 }
8757 proto::language_server_selector::Selector::Name(name) => {
8758 LanguageServerSelector::Name(LanguageServerName(
8759 SharedString::from(name),
8760 ))
8761 }
8762 })
8763 })
8764 .collect(),
8765 false,
8766 cx,
8767 );
8768 this.buffer_store().update(cx, |buffer_store, _| {
8769 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8770 });
8771
8772 Ok(())
8773 })??;
8774 Ok(proto::Ack {})
8775 }
8776
8777 async fn handle_rename_project_entry(
8778 this: Entity<Self>,
8779 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8780 mut cx: AsyncApp,
8781 ) -> Result<proto::ProjectEntryResponse> {
8782 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8783 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
8784 let new_path =
8785 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
8786
8787 let (worktree_store, old_worktree, new_worktree, old_entry) = this
8788 .update(&mut cx, |this, cx| {
8789 let (worktree, entry) = this
8790 .worktree_store
8791 .read(cx)
8792 .worktree_and_entry_for_id(entry_id, cx)?;
8793 let new_worktree = this
8794 .worktree_store
8795 .read(cx)
8796 .worktree_for_id(new_worktree_id, cx)?;
8797 Some((
8798 this.worktree_store.clone(),
8799 worktree,
8800 new_worktree,
8801 entry.clone(),
8802 ))
8803 })?
8804 .context("worktree not found")?;
8805 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
8806 (worktree.absolutize(&old_entry.path), worktree.id())
8807 })?;
8808 let new_abs_path =
8809 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
8810
8811 let _transaction = Self::will_rename_entry(
8812 this.downgrade(),
8813 old_worktree_id,
8814 &old_abs_path,
8815 &new_abs_path,
8816 old_entry.is_dir(),
8817 cx.clone(),
8818 )
8819 .await;
8820 let response = WorktreeStore::handle_rename_project_entry(
8821 worktree_store,
8822 envelope.payload,
8823 cx.clone(),
8824 )
8825 .await;
8826 this.read_with(&cx, |this, _| {
8827 this.did_rename_entry(
8828 old_worktree_id,
8829 &old_abs_path,
8830 &new_abs_path,
8831 old_entry.is_dir(),
8832 );
8833 })
8834 .ok();
8835 response
8836 }
8837
8838 async fn handle_update_diagnostic_summary(
8839 this: Entity<Self>,
8840 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8841 mut cx: AsyncApp,
8842 ) -> Result<()> {
8843 this.update(&mut cx, |lsp_store, cx| {
8844 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8845 let mut updated_diagnostics_paths = HashMap::default();
8846 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8847 for message_summary in envelope
8848 .payload
8849 .summary
8850 .into_iter()
8851 .chain(envelope.payload.more_summaries)
8852 {
8853 let project_path = ProjectPath {
8854 worktree_id,
8855 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
8856 };
8857 let path = project_path.path.clone();
8858 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8859 let summary = DiagnosticSummary {
8860 error_count: message_summary.error_count as usize,
8861 warning_count: message_summary.warning_count as usize,
8862 };
8863
8864 if summary.is_empty() {
8865 if let Some(worktree_summaries) =
8866 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8867 && let Some(summaries) = worktree_summaries.get_mut(&path)
8868 {
8869 summaries.remove(&server_id);
8870 if summaries.is_empty() {
8871 worktree_summaries.remove(&path);
8872 }
8873 }
8874 } else {
8875 lsp_store
8876 .diagnostic_summaries
8877 .entry(worktree_id)
8878 .or_default()
8879 .entry(path)
8880 .or_default()
8881 .insert(server_id, summary);
8882 }
8883
8884 if let Some((_, project_id)) = &lsp_store.downstream_client {
8885 match &mut diagnostics_summary {
8886 Some(diagnostics_summary) => {
8887 diagnostics_summary
8888 .more_summaries
8889 .push(proto::DiagnosticSummary {
8890 path: project_path.path.as_ref().to_proto(),
8891 language_server_id: server_id.0 as u64,
8892 error_count: summary.error_count as u32,
8893 warning_count: summary.warning_count as u32,
8894 })
8895 }
8896 None => {
8897 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8898 project_id: *project_id,
8899 worktree_id: worktree_id.to_proto(),
8900 summary: Some(proto::DiagnosticSummary {
8901 path: project_path.path.as_ref().to_proto(),
8902 language_server_id: server_id.0 as u64,
8903 error_count: summary.error_count as u32,
8904 warning_count: summary.warning_count as u32,
8905 }),
8906 more_summaries: Vec::new(),
8907 })
8908 }
8909 }
8910 }
8911 updated_diagnostics_paths
8912 .entry(server_id)
8913 .or_insert_with(Vec::new)
8914 .push(project_path);
8915 }
8916
8917 if let Some((diagnostics_summary, (downstream_client, _))) =
8918 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8919 {
8920 downstream_client.send(diagnostics_summary).log_err();
8921 }
8922 for (server_id, paths) in updated_diagnostics_paths {
8923 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8924 }
8925 Ok(())
8926 })?
8927 }
8928
8929 async fn handle_start_language_server(
8930 lsp_store: Entity<Self>,
8931 envelope: TypedEnvelope<proto::StartLanguageServer>,
8932 mut cx: AsyncApp,
8933 ) -> Result<()> {
8934 let server = envelope.payload.server.context("invalid server")?;
8935 let server_capabilities =
8936 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8937 .with_context(|| {
8938 format!(
8939 "incorrect server capabilities {}",
8940 envelope.payload.capabilities
8941 )
8942 })?;
8943 lsp_store.update(&mut cx, |lsp_store, cx| {
8944 let server_id = LanguageServerId(server.id as usize);
8945 let server_name = LanguageServerName::from_proto(server.name.clone());
8946 lsp_store
8947 .lsp_server_capabilities
8948 .insert(server_id, server_capabilities);
8949 lsp_store.language_server_statuses.insert(
8950 server_id,
8951 LanguageServerStatus {
8952 name: server_name.clone(),
8953 pending_work: Default::default(),
8954 has_pending_diagnostic_updates: false,
8955 progress_tokens: Default::default(),
8956 worktree: server.worktree_id.map(WorktreeId::from_proto),
8957 },
8958 );
8959 cx.emit(LspStoreEvent::LanguageServerAdded(
8960 server_id,
8961 server_name,
8962 server.worktree_id.map(WorktreeId::from_proto),
8963 ));
8964 cx.notify();
8965 })?;
8966 Ok(())
8967 }
8968
8969 async fn handle_update_language_server(
8970 lsp_store: Entity<Self>,
8971 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
8972 mut cx: AsyncApp,
8973 ) -> Result<()> {
8974 lsp_store.update(&mut cx, |lsp_store, cx| {
8975 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
8976
8977 match envelope.payload.variant.context("invalid variant")? {
8978 proto::update_language_server::Variant::WorkStart(payload) => {
8979 lsp_store.on_lsp_work_start(
8980 language_server_id,
8981 ProgressToken::from_proto(payload.token.context("missing progress token")?)
8982 .context("invalid progress token value")?,
8983 LanguageServerProgress {
8984 title: payload.title,
8985 is_disk_based_diagnostics_progress: false,
8986 is_cancellable: payload.is_cancellable.unwrap_or(false),
8987 message: payload.message,
8988 percentage: payload.percentage.map(|p| p as usize),
8989 last_update_at: cx.background_executor().now(),
8990 },
8991 cx,
8992 );
8993 }
8994 proto::update_language_server::Variant::WorkProgress(payload) => {
8995 lsp_store.on_lsp_work_progress(
8996 language_server_id,
8997 ProgressToken::from_proto(payload.token.context("missing progress token")?)
8998 .context("invalid progress token value")?,
8999 LanguageServerProgress {
9000 title: None,
9001 is_disk_based_diagnostics_progress: false,
9002 is_cancellable: payload.is_cancellable.unwrap_or(false),
9003 message: payload.message,
9004 percentage: payload.percentage.map(|p| p as usize),
9005 last_update_at: cx.background_executor().now(),
9006 },
9007 cx,
9008 );
9009 }
9010
9011 proto::update_language_server::Variant::WorkEnd(payload) => {
9012 lsp_store.on_lsp_work_end(
9013 language_server_id,
9014 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9015 .context("invalid progress token value")?,
9016 cx,
9017 );
9018 }
9019
9020 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9021 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9022 }
9023
9024 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9025 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9026 }
9027
9028 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9029 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9030 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9031 cx.emit(LspStoreEvent::LanguageServerUpdate {
9032 language_server_id,
9033 name: envelope
9034 .payload
9035 .server_name
9036 .map(SharedString::new)
9037 .map(LanguageServerName),
9038 message: non_lsp,
9039 });
9040 }
9041 }
9042
9043 Ok(())
9044 })?
9045 }
9046
9047 async fn handle_language_server_log(
9048 this: Entity<Self>,
9049 envelope: TypedEnvelope<proto::LanguageServerLog>,
9050 mut cx: AsyncApp,
9051 ) -> Result<()> {
9052 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9053 let log_type = envelope
9054 .payload
9055 .log_type
9056 .map(LanguageServerLogType::from_proto)
9057 .context("invalid language server log type")?;
9058
9059 let message = envelope.payload.message;
9060
9061 this.update(&mut cx, |_, cx| {
9062 cx.emit(LspStoreEvent::LanguageServerLog(
9063 language_server_id,
9064 log_type,
9065 message,
9066 ));
9067 })
9068 }
9069
9070 async fn handle_lsp_ext_cancel_flycheck(
9071 lsp_store: Entity<Self>,
9072 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9073 cx: AsyncApp,
9074 ) -> Result<proto::Ack> {
9075 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9076 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9077 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9078 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9079 } else {
9080 None
9081 }
9082 })?;
9083 if let Some(task) = task {
9084 task.context("handling lsp ext cancel flycheck")?;
9085 }
9086
9087 Ok(proto::Ack {})
9088 }
9089
9090 async fn handle_lsp_ext_run_flycheck(
9091 lsp_store: Entity<Self>,
9092 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9093 mut cx: AsyncApp,
9094 ) -> Result<proto::Ack> {
9095 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9096 lsp_store.update(&mut cx, |lsp_store, cx| {
9097 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9098 let text_document = if envelope.payload.current_file_only {
9099 let buffer_id = envelope
9100 .payload
9101 .buffer_id
9102 .map(|id| BufferId::new(id))
9103 .transpose()?;
9104 buffer_id
9105 .and_then(|buffer_id| {
9106 lsp_store
9107 .buffer_store()
9108 .read(cx)
9109 .get(buffer_id)
9110 .and_then(|buffer| {
9111 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9112 })
9113 .map(|path| make_text_document_identifier(&path))
9114 })
9115 .transpose()?
9116 } else {
9117 None
9118 };
9119 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9120 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9121 )?;
9122 }
9123 anyhow::Ok(())
9124 })??;
9125
9126 Ok(proto::Ack {})
9127 }
9128
9129 async fn handle_lsp_ext_clear_flycheck(
9130 lsp_store: Entity<Self>,
9131 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9132 cx: AsyncApp,
9133 ) -> Result<proto::Ack> {
9134 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9135 lsp_store
9136 .read_with(&cx, |lsp_store, _| {
9137 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9138 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9139 } else {
9140 None
9141 }
9142 })
9143 .context("handling lsp ext clear flycheck")?;
9144
9145 Ok(proto::Ack {})
9146 }
9147
9148 pub fn disk_based_diagnostics_started(
9149 &mut self,
9150 language_server_id: LanguageServerId,
9151 cx: &mut Context<Self>,
9152 ) {
9153 if let Some(language_server_status) =
9154 self.language_server_statuses.get_mut(&language_server_id)
9155 {
9156 language_server_status.has_pending_diagnostic_updates = true;
9157 }
9158
9159 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9160 cx.emit(LspStoreEvent::LanguageServerUpdate {
9161 language_server_id,
9162 name: self
9163 .language_server_adapter_for_id(language_server_id)
9164 .map(|adapter| adapter.name()),
9165 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9166 Default::default(),
9167 ),
9168 })
9169 }
9170
9171 pub fn disk_based_diagnostics_finished(
9172 &mut self,
9173 language_server_id: LanguageServerId,
9174 cx: &mut Context<Self>,
9175 ) {
9176 if let Some(language_server_status) =
9177 self.language_server_statuses.get_mut(&language_server_id)
9178 {
9179 language_server_status.has_pending_diagnostic_updates = false;
9180 }
9181
9182 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9183 cx.emit(LspStoreEvent::LanguageServerUpdate {
9184 language_server_id,
9185 name: self
9186 .language_server_adapter_for_id(language_server_id)
9187 .map(|adapter| adapter.name()),
9188 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9189 Default::default(),
9190 ),
9191 })
9192 }
9193
9194 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9195 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9196 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9197 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9198 // the language server might take some time to publish diagnostics.
9199 fn simulate_disk_based_diagnostics_events_if_needed(
9200 &mut self,
9201 language_server_id: LanguageServerId,
9202 cx: &mut Context<Self>,
9203 ) {
9204 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9205
9206 let Some(LanguageServerState::Running {
9207 simulate_disk_based_diagnostics_completion,
9208 adapter,
9209 ..
9210 }) = self
9211 .as_local_mut()
9212 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9213 else {
9214 return;
9215 };
9216
9217 if adapter.disk_based_diagnostics_progress_token.is_some() {
9218 return;
9219 }
9220
9221 let prev_task =
9222 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9223 cx.background_executor()
9224 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9225 .await;
9226
9227 this.update(cx, |this, cx| {
9228 this.disk_based_diagnostics_finished(language_server_id, cx);
9229
9230 if let Some(LanguageServerState::Running {
9231 simulate_disk_based_diagnostics_completion,
9232 ..
9233 }) = this.as_local_mut().and_then(|local_store| {
9234 local_store.language_servers.get_mut(&language_server_id)
9235 }) {
9236 *simulate_disk_based_diagnostics_completion = None;
9237 }
9238 })
9239 .ok();
9240 }));
9241
9242 if prev_task.is_none() {
9243 self.disk_based_diagnostics_started(language_server_id, cx);
9244 }
9245 }
9246
9247 pub fn language_server_statuses(
9248 &self,
9249 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9250 self.language_server_statuses
9251 .iter()
9252 .map(|(key, value)| (*key, value))
9253 }
9254
9255 pub(super) fn did_rename_entry(
9256 &self,
9257 worktree_id: WorktreeId,
9258 old_path: &Path,
9259 new_path: &Path,
9260 is_dir: bool,
9261 ) {
9262 maybe!({
9263 let local_store = self.as_local()?;
9264
9265 let old_uri = lsp::Uri::from_file_path(old_path)
9266 .ok()
9267 .map(|uri| uri.to_string())?;
9268 let new_uri = lsp::Uri::from_file_path(new_path)
9269 .ok()
9270 .map(|uri| uri.to_string())?;
9271
9272 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9273 let Some(filter) = local_store
9274 .language_server_paths_watched_for_rename
9275 .get(&language_server.server_id())
9276 else {
9277 continue;
9278 };
9279
9280 if filter.should_send_did_rename(&old_uri, is_dir) {
9281 language_server
9282 .notify::<DidRenameFiles>(RenameFilesParams {
9283 files: vec![FileRename {
9284 old_uri: old_uri.clone(),
9285 new_uri: new_uri.clone(),
9286 }],
9287 })
9288 .ok();
9289 }
9290 }
9291 Some(())
9292 });
9293 }
9294
9295 pub(super) fn will_rename_entry(
9296 this: WeakEntity<Self>,
9297 worktree_id: WorktreeId,
9298 old_path: &Path,
9299 new_path: &Path,
9300 is_dir: bool,
9301 cx: AsyncApp,
9302 ) -> Task<ProjectTransaction> {
9303 let old_uri = lsp::Uri::from_file_path(old_path)
9304 .ok()
9305 .map(|uri| uri.to_string());
9306 let new_uri = lsp::Uri::from_file_path(new_path)
9307 .ok()
9308 .map(|uri| uri.to_string());
9309 cx.spawn(async move |cx| {
9310 let mut tasks = vec![];
9311 this.update(cx, |this, cx| {
9312 let local_store = this.as_local()?;
9313 let old_uri = old_uri?;
9314 let new_uri = new_uri?;
9315 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9316 let Some(filter) = local_store
9317 .language_server_paths_watched_for_rename
9318 .get(&language_server.server_id())
9319 else {
9320 continue;
9321 };
9322
9323 if filter.should_send_will_rename(&old_uri, is_dir) {
9324 let apply_edit = cx.spawn({
9325 let old_uri = old_uri.clone();
9326 let new_uri = new_uri.clone();
9327 let language_server = language_server.clone();
9328 async move |this, cx| {
9329 let edit = language_server
9330 .request::<WillRenameFiles>(RenameFilesParams {
9331 files: vec![FileRename { old_uri, new_uri }],
9332 })
9333 .await
9334 .into_response()
9335 .context("will rename files")
9336 .log_err()
9337 .flatten()?;
9338
9339 let transaction = LocalLspStore::deserialize_workspace_edit(
9340 this.upgrade()?,
9341 edit,
9342 false,
9343 language_server.clone(),
9344 cx,
9345 )
9346 .await
9347 .ok()?;
9348 Some(transaction)
9349 }
9350 });
9351 tasks.push(apply_edit);
9352 }
9353 }
9354 Some(())
9355 })
9356 .ok()
9357 .flatten();
9358 let mut merged_transaction = ProjectTransaction::default();
9359 for task in tasks {
9360 // Await on tasks sequentially so that the order of application of edits is deterministic
9361 // (at least with regards to the order of registration of language servers)
9362 if let Some(transaction) = task.await {
9363 for (buffer, buffer_transaction) in transaction.0 {
9364 merged_transaction.0.insert(buffer, buffer_transaction);
9365 }
9366 }
9367 }
9368 merged_transaction
9369 })
9370 }
9371
9372 fn lsp_notify_abs_paths_changed(
9373 &mut self,
9374 server_id: LanguageServerId,
9375 changes: Vec<PathEvent>,
9376 ) {
9377 maybe!({
9378 let server = self.language_server_for_id(server_id)?;
9379 let changes = changes
9380 .into_iter()
9381 .filter_map(|event| {
9382 let typ = match event.kind? {
9383 PathEventKind::Created => lsp::FileChangeType::CREATED,
9384 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9385 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9386 };
9387 Some(lsp::FileEvent {
9388 uri: file_path_to_lsp_url(&event.path).log_err()?,
9389 typ,
9390 })
9391 })
9392 .collect::<Vec<_>>();
9393 if !changes.is_empty() {
9394 server
9395 .notify::<lsp::notification::DidChangeWatchedFiles>(
9396 lsp::DidChangeWatchedFilesParams { changes },
9397 )
9398 .ok();
9399 }
9400 Some(())
9401 });
9402 }
9403
9404 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9405 self.as_local()?.language_server_for_id(id)
9406 }
9407
9408 fn on_lsp_progress(
9409 &mut self,
9410 progress_params: lsp::ProgressParams,
9411 language_server_id: LanguageServerId,
9412 disk_based_diagnostics_progress_token: Option<String>,
9413 cx: &mut Context<Self>,
9414 ) {
9415 match progress_params.value {
9416 lsp::ProgressParamsValue::WorkDone(progress) => {
9417 self.handle_work_done_progress(
9418 progress,
9419 language_server_id,
9420 disk_based_diagnostics_progress_token,
9421 ProgressToken::from_lsp(progress_params.token),
9422 cx,
9423 );
9424 }
9425 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9426 let identifier = match progress_params.token {
9427 lsp::NumberOrString::Number(_) => None,
9428 lsp::NumberOrString::String(token) => token
9429 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9430 .map(|(_, id)| id.to_owned()),
9431 };
9432 if let Some(LanguageServerState::Running {
9433 workspace_diagnostics_refresh_tasks,
9434 ..
9435 }) = self
9436 .as_local_mut()
9437 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9438 && let Some(workspace_diagnostics) =
9439 workspace_diagnostics_refresh_tasks.get_mut(&identifier)
9440 {
9441 workspace_diagnostics.progress_tx.try_send(()).ok();
9442 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9443 }
9444 }
9445 }
9446 }
9447
9448 fn handle_work_done_progress(
9449 &mut self,
9450 progress: lsp::WorkDoneProgress,
9451 language_server_id: LanguageServerId,
9452 disk_based_diagnostics_progress_token: Option<String>,
9453 token: ProgressToken,
9454 cx: &mut Context<Self>,
9455 ) {
9456 let language_server_status =
9457 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9458 status
9459 } else {
9460 return;
9461 };
9462
9463 if !language_server_status.progress_tokens.contains(&token) {
9464 return;
9465 }
9466
9467 let is_disk_based_diagnostics_progress =
9468 if let (Some(disk_based_token), ProgressToken::String(token)) =
9469 (&disk_based_diagnostics_progress_token, &token)
9470 {
9471 token.starts_with(disk_based_token)
9472 } else {
9473 false
9474 };
9475
9476 match progress {
9477 lsp::WorkDoneProgress::Begin(report) => {
9478 if is_disk_based_diagnostics_progress {
9479 self.disk_based_diagnostics_started(language_server_id, cx);
9480 }
9481 self.on_lsp_work_start(
9482 language_server_id,
9483 token.clone(),
9484 LanguageServerProgress {
9485 title: Some(report.title),
9486 is_disk_based_diagnostics_progress,
9487 is_cancellable: report.cancellable.unwrap_or(false),
9488 message: report.message.clone(),
9489 percentage: report.percentage.map(|p| p as usize),
9490 last_update_at: cx.background_executor().now(),
9491 },
9492 cx,
9493 );
9494 }
9495 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9496 language_server_id,
9497 token,
9498 LanguageServerProgress {
9499 title: None,
9500 is_disk_based_diagnostics_progress,
9501 is_cancellable: report.cancellable.unwrap_or(false),
9502 message: report.message,
9503 percentage: report.percentage.map(|p| p as usize),
9504 last_update_at: cx.background_executor().now(),
9505 },
9506 cx,
9507 ),
9508 lsp::WorkDoneProgress::End(_) => {
9509 language_server_status.progress_tokens.remove(&token);
9510 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9511 if is_disk_based_diagnostics_progress {
9512 self.disk_based_diagnostics_finished(language_server_id, cx);
9513 }
9514 }
9515 }
9516 }
9517
9518 fn on_lsp_work_start(
9519 &mut self,
9520 language_server_id: LanguageServerId,
9521 token: ProgressToken,
9522 progress: LanguageServerProgress,
9523 cx: &mut Context<Self>,
9524 ) {
9525 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9526 status.pending_work.insert(token.clone(), progress.clone());
9527 cx.notify();
9528 }
9529 cx.emit(LspStoreEvent::LanguageServerUpdate {
9530 language_server_id,
9531 name: self
9532 .language_server_adapter_for_id(language_server_id)
9533 .map(|adapter| adapter.name()),
9534 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9535 token: Some(token.to_proto()),
9536 title: progress.title,
9537 message: progress.message,
9538 percentage: progress.percentage.map(|p| p as u32),
9539 is_cancellable: Some(progress.is_cancellable),
9540 }),
9541 })
9542 }
9543
9544 fn on_lsp_work_progress(
9545 &mut self,
9546 language_server_id: LanguageServerId,
9547 token: ProgressToken,
9548 progress: LanguageServerProgress,
9549 cx: &mut Context<Self>,
9550 ) {
9551 let mut did_update = false;
9552 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9553 match status.pending_work.entry(token.clone()) {
9554 btree_map::Entry::Vacant(entry) => {
9555 entry.insert(progress.clone());
9556 did_update = true;
9557 }
9558 btree_map::Entry::Occupied(mut entry) => {
9559 let entry = entry.get_mut();
9560 if (progress.last_update_at - entry.last_update_at)
9561 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9562 {
9563 entry.last_update_at = progress.last_update_at;
9564 if progress.message.is_some() {
9565 entry.message = progress.message.clone();
9566 }
9567 if progress.percentage.is_some() {
9568 entry.percentage = progress.percentage;
9569 }
9570 if progress.is_cancellable != entry.is_cancellable {
9571 entry.is_cancellable = progress.is_cancellable;
9572 }
9573 did_update = true;
9574 }
9575 }
9576 }
9577 }
9578
9579 if did_update {
9580 cx.emit(LspStoreEvent::LanguageServerUpdate {
9581 language_server_id,
9582 name: self
9583 .language_server_adapter_for_id(language_server_id)
9584 .map(|adapter| adapter.name()),
9585 message: proto::update_language_server::Variant::WorkProgress(
9586 proto::LspWorkProgress {
9587 token: Some(token.to_proto()),
9588 message: progress.message,
9589 percentage: progress.percentage.map(|p| p as u32),
9590 is_cancellable: Some(progress.is_cancellable),
9591 },
9592 ),
9593 })
9594 }
9595 }
9596
9597 fn on_lsp_work_end(
9598 &mut self,
9599 language_server_id: LanguageServerId,
9600 token: ProgressToken,
9601 cx: &mut Context<Self>,
9602 ) {
9603 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9604 if let Some(work) = status.pending_work.remove(&token)
9605 && !work.is_disk_based_diagnostics_progress
9606 {
9607 cx.emit(LspStoreEvent::RefreshInlayHints(language_server_id));
9608 }
9609 cx.notify();
9610 }
9611
9612 cx.emit(LspStoreEvent::LanguageServerUpdate {
9613 language_server_id,
9614 name: self
9615 .language_server_adapter_for_id(language_server_id)
9616 .map(|adapter| adapter.name()),
9617 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
9618 token: Some(token.to_proto()),
9619 }),
9620 })
9621 }
9622
9623 pub async fn handle_resolve_completion_documentation(
9624 this: Entity<Self>,
9625 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9626 mut cx: AsyncApp,
9627 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9628 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9629
9630 let completion = this
9631 .read_with(&cx, |this, cx| {
9632 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9633 let server = this
9634 .language_server_for_id(id)
9635 .with_context(|| format!("No language server {id}"))?;
9636
9637 anyhow::Ok(cx.background_spawn(async move {
9638 let can_resolve = server
9639 .capabilities()
9640 .completion_provider
9641 .as_ref()
9642 .and_then(|options| options.resolve_provider)
9643 .unwrap_or(false);
9644 if can_resolve {
9645 server
9646 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9647 .await
9648 .into_response()
9649 .context("resolve completion item")
9650 } else {
9651 anyhow::Ok(lsp_completion)
9652 }
9653 }))
9654 })??
9655 .await?;
9656
9657 let mut documentation_is_markdown = false;
9658 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9659 let documentation = match completion.documentation {
9660 Some(lsp::Documentation::String(text)) => text,
9661
9662 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9663 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9664 value
9665 }
9666
9667 _ => String::new(),
9668 };
9669
9670 // If we have a new buffer_id, that means we're talking to a new client
9671 // and want to check for new text_edits in the completion too.
9672 let mut old_replace_start = None;
9673 let mut old_replace_end = None;
9674 let mut old_insert_start = None;
9675 let mut old_insert_end = None;
9676 let mut new_text = String::default();
9677 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9678 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9679 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9680 anyhow::Ok(buffer.read(cx).snapshot())
9681 })??;
9682
9683 if let Some(text_edit) = completion.text_edit.as_ref() {
9684 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9685
9686 if let Some(mut edit) = edit {
9687 LineEnding::normalize(&mut edit.new_text);
9688
9689 new_text = edit.new_text;
9690 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9691 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9692 if let Some(insert_range) = edit.insert_range {
9693 old_insert_start = Some(serialize_anchor(&insert_range.start));
9694 old_insert_end = Some(serialize_anchor(&insert_range.end));
9695 }
9696 }
9697 }
9698 }
9699
9700 Ok(proto::ResolveCompletionDocumentationResponse {
9701 documentation,
9702 documentation_is_markdown,
9703 old_replace_start,
9704 old_replace_end,
9705 new_text,
9706 lsp_completion,
9707 old_insert_start,
9708 old_insert_end,
9709 })
9710 }
9711
9712 async fn handle_on_type_formatting(
9713 this: Entity<Self>,
9714 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9715 mut cx: AsyncApp,
9716 ) -> Result<proto::OnTypeFormattingResponse> {
9717 let on_type_formatting = this.update(&mut cx, |this, cx| {
9718 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9719 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9720 let position = envelope
9721 .payload
9722 .position
9723 .and_then(deserialize_anchor)
9724 .context("invalid position")?;
9725 anyhow::Ok(this.apply_on_type_formatting(
9726 buffer,
9727 position,
9728 envelope.payload.trigger.clone(),
9729 cx,
9730 ))
9731 })??;
9732
9733 let transaction = on_type_formatting
9734 .await?
9735 .as_ref()
9736 .map(language::proto::serialize_transaction);
9737 Ok(proto::OnTypeFormattingResponse { transaction })
9738 }
9739
9740 async fn handle_refresh_inlay_hints(
9741 lsp_store: Entity<Self>,
9742 envelope: TypedEnvelope<proto::RefreshInlayHints>,
9743 mut cx: AsyncApp,
9744 ) -> Result<proto::Ack> {
9745 lsp_store.update(&mut cx, |_, cx| {
9746 cx.emit(LspStoreEvent::RefreshInlayHints(
9747 LanguageServerId::from_proto(envelope.payload.server_id),
9748 ));
9749 })?;
9750 Ok(proto::Ack {})
9751 }
9752
9753 async fn handle_pull_workspace_diagnostics(
9754 lsp_store: Entity<Self>,
9755 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9756 mut cx: AsyncApp,
9757 ) -> Result<proto::Ack> {
9758 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9759 lsp_store.update(&mut cx, |lsp_store, _| {
9760 lsp_store.pull_workspace_diagnostics(server_id);
9761 })?;
9762 Ok(proto::Ack {})
9763 }
9764
9765 async fn handle_get_color_presentation(
9766 lsp_store: Entity<Self>,
9767 envelope: TypedEnvelope<proto::GetColorPresentation>,
9768 mut cx: AsyncApp,
9769 ) -> Result<proto::GetColorPresentationResponse> {
9770 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9771 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9772 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9773 })??;
9774
9775 let color = envelope
9776 .payload
9777 .color
9778 .context("invalid color resolve request")?;
9779 let start = color
9780 .lsp_range_start
9781 .context("invalid color resolve request")?;
9782 let end = color
9783 .lsp_range_end
9784 .context("invalid color resolve request")?;
9785
9786 let color = DocumentColor {
9787 lsp_range: lsp::Range {
9788 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9789 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9790 },
9791 color: lsp::Color {
9792 red: color.red,
9793 green: color.green,
9794 blue: color.blue,
9795 alpha: color.alpha,
9796 },
9797 resolved: false,
9798 color_presentations: Vec::new(),
9799 };
9800 let resolved_color = lsp_store
9801 .update(&mut cx, |lsp_store, cx| {
9802 lsp_store.resolve_color_presentation(
9803 color,
9804 buffer.clone(),
9805 LanguageServerId(envelope.payload.server_id as usize),
9806 cx,
9807 )
9808 })?
9809 .await
9810 .context("resolving color presentation")?;
9811
9812 Ok(proto::GetColorPresentationResponse {
9813 presentations: resolved_color
9814 .color_presentations
9815 .into_iter()
9816 .map(|presentation| proto::ColorPresentation {
9817 label: presentation.label.to_string(),
9818 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9819 additional_text_edits: presentation
9820 .additional_text_edits
9821 .into_iter()
9822 .map(serialize_lsp_edit)
9823 .collect(),
9824 })
9825 .collect(),
9826 })
9827 }
9828
9829 async fn handle_resolve_inlay_hint(
9830 lsp_store: Entity<Self>,
9831 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9832 mut cx: AsyncApp,
9833 ) -> Result<proto::ResolveInlayHintResponse> {
9834 let proto_hint = envelope
9835 .payload
9836 .hint
9837 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9838 let hint = InlayHints::proto_to_project_hint(proto_hint)
9839 .context("resolved proto inlay hint conversion")?;
9840 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9841 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9842 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9843 })??;
9844 let response_hint = lsp_store
9845 .update(&mut cx, |lsp_store, cx| {
9846 lsp_store.resolve_inlay_hint(
9847 hint,
9848 buffer,
9849 LanguageServerId(envelope.payload.language_server_id as usize),
9850 cx,
9851 )
9852 })?
9853 .await
9854 .context("inlay hints fetch")?;
9855 Ok(proto::ResolveInlayHintResponse {
9856 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9857 })
9858 }
9859
9860 async fn handle_refresh_code_lens(
9861 this: Entity<Self>,
9862 _: TypedEnvelope<proto::RefreshCodeLens>,
9863 mut cx: AsyncApp,
9864 ) -> Result<proto::Ack> {
9865 this.update(&mut cx, |_, cx| {
9866 cx.emit(LspStoreEvent::RefreshCodeLens);
9867 })?;
9868 Ok(proto::Ack {})
9869 }
9870
9871 async fn handle_open_buffer_for_symbol(
9872 this: Entity<Self>,
9873 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9874 mut cx: AsyncApp,
9875 ) -> Result<proto::OpenBufferForSymbolResponse> {
9876 let peer_id = envelope.original_sender_id().unwrap_or_default();
9877 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9878 let symbol = Self::deserialize_symbol(symbol)?;
9879 this.read_with(&cx, |this, _| {
9880 if let SymbolLocation::OutsideProject {
9881 abs_path,
9882 signature,
9883 } = &symbol.path
9884 {
9885 let new_signature = this.symbol_signature(&abs_path);
9886 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
9887 }
9888 Ok(())
9889 })??;
9890 let buffer = this
9891 .update(&mut cx, |this, cx| {
9892 this.open_buffer_for_symbol(
9893 &Symbol {
9894 language_server_name: symbol.language_server_name,
9895 source_worktree_id: symbol.source_worktree_id,
9896 source_language_server_id: symbol.source_language_server_id,
9897 path: symbol.path,
9898 name: symbol.name,
9899 kind: symbol.kind,
9900 range: symbol.range,
9901 label: CodeLabel::default(),
9902 },
9903 cx,
9904 )
9905 })?
9906 .await?;
9907
9908 this.update(&mut cx, |this, cx| {
9909 let is_private = buffer
9910 .read(cx)
9911 .file()
9912 .map(|f| f.is_private())
9913 .unwrap_or_default();
9914 if is_private {
9915 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9916 } else {
9917 this.buffer_store
9918 .update(cx, |buffer_store, cx| {
9919 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9920 })
9921 .detach_and_log_err(cx);
9922 let buffer_id = buffer.read(cx).remote_id().to_proto();
9923 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9924 }
9925 })?
9926 }
9927
9928 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
9929 let mut hasher = Sha256::new();
9930 hasher.update(abs_path.to_string_lossy().as_bytes());
9931 hasher.update(self.nonce.to_be_bytes());
9932 hasher.finalize().as_slice().try_into().unwrap()
9933 }
9934
9935 pub async fn handle_get_project_symbols(
9936 this: Entity<Self>,
9937 envelope: TypedEnvelope<proto::GetProjectSymbols>,
9938 mut cx: AsyncApp,
9939 ) -> Result<proto::GetProjectSymbolsResponse> {
9940 let symbols = this
9941 .update(&mut cx, |this, cx| {
9942 this.symbols(&envelope.payload.query, cx)
9943 })?
9944 .await?;
9945
9946 Ok(proto::GetProjectSymbolsResponse {
9947 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
9948 })
9949 }
9950
9951 pub async fn handle_restart_language_servers(
9952 this: Entity<Self>,
9953 envelope: TypedEnvelope<proto::RestartLanguageServers>,
9954 mut cx: AsyncApp,
9955 ) -> Result<proto::Ack> {
9956 this.update(&mut cx, |lsp_store, cx| {
9957 let buffers =
9958 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9959 lsp_store.restart_language_servers_for_buffers(
9960 buffers,
9961 envelope
9962 .payload
9963 .only_servers
9964 .into_iter()
9965 .filter_map(|selector| {
9966 Some(match selector.selector? {
9967 proto::language_server_selector::Selector::ServerId(server_id) => {
9968 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9969 }
9970 proto::language_server_selector::Selector::Name(name) => {
9971 LanguageServerSelector::Name(LanguageServerName(
9972 SharedString::from(name),
9973 ))
9974 }
9975 })
9976 })
9977 .collect(),
9978 cx,
9979 );
9980 })?;
9981
9982 Ok(proto::Ack {})
9983 }
9984
9985 pub async fn handle_stop_language_servers(
9986 lsp_store: Entity<Self>,
9987 envelope: TypedEnvelope<proto::StopLanguageServers>,
9988 mut cx: AsyncApp,
9989 ) -> Result<proto::Ack> {
9990 lsp_store.update(&mut cx, |lsp_store, cx| {
9991 if envelope.payload.all
9992 && envelope.payload.also_servers.is_empty()
9993 && envelope.payload.buffer_ids.is_empty()
9994 {
9995 lsp_store.stop_all_language_servers(cx);
9996 } else {
9997 let buffers =
9998 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
9999 lsp_store
10000 .stop_language_servers_for_buffers(
10001 buffers,
10002 envelope
10003 .payload
10004 .also_servers
10005 .into_iter()
10006 .filter_map(|selector| {
10007 Some(match selector.selector? {
10008 proto::language_server_selector::Selector::ServerId(
10009 server_id,
10010 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10011 server_id,
10012 )),
10013 proto::language_server_selector::Selector::Name(name) => {
10014 LanguageServerSelector::Name(LanguageServerName(
10015 SharedString::from(name),
10016 ))
10017 }
10018 })
10019 })
10020 .collect(),
10021 cx,
10022 )
10023 .detach_and_log_err(cx);
10024 }
10025 })?;
10026
10027 Ok(proto::Ack {})
10028 }
10029
10030 pub async fn handle_cancel_language_server_work(
10031 lsp_store: Entity<Self>,
10032 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10033 mut cx: AsyncApp,
10034 ) -> Result<proto::Ack> {
10035 lsp_store.update(&mut cx, |lsp_store, cx| {
10036 if let Some(work) = envelope.payload.work {
10037 match work {
10038 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10039 let buffers =
10040 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10041 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10042 }
10043 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10044 let server_id = LanguageServerId::from_proto(work.language_server_id);
10045 let token = work
10046 .token
10047 .map(|token| {
10048 ProgressToken::from_proto(token)
10049 .context("invalid work progress token")
10050 })
10051 .transpose()?;
10052 lsp_store.cancel_language_server_work(server_id, token, cx);
10053 }
10054 }
10055 }
10056 anyhow::Ok(())
10057 })??;
10058
10059 Ok(proto::Ack {})
10060 }
10061
10062 fn buffer_ids_to_buffers(
10063 &mut self,
10064 buffer_ids: impl Iterator<Item = u64>,
10065 cx: &mut Context<Self>,
10066 ) -> Vec<Entity<Buffer>> {
10067 buffer_ids
10068 .into_iter()
10069 .flat_map(|buffer_id| {
10070 self.buffer_store
10071 .read(cx)
10072 .get(BufferId::new(buffer_id).log_err()?)
10073 })
10074 .collect::<Vec<_>>()
10075 }
10076
10077 async fn handle_apply_additional_edits_for_completion(
10078 this: Entity<Self>,
10079 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10080 mut cx: AsyncApp,
10081 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10082 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10083 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10084 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10085 let completion = Self::deserialize_completion(
10086 envelope.payload.completion.context("invalid completion")?,
10087 )?;
10088 anyhow::Ok((buffer, completion))
10089 })??;
10090
10091 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10092 this.apply_additional_edits_for_completion(
10093 buffer,
10094 Rc::new(RefCell::new(Box::new([Completion {
10095 replace_range: completion.replace_range,
10096 new_text: completion.new_text,
10097 source: completion.source,
10098 documentation: None,
10099 label: CodeLabel::default(),
10100 insert_text_mode: None,
10101 icon_path: None,
10102 confirm: None,
10103 }]))),
10104 0,
10105 false,
10106 cx,
10107 )
10108 })?;
10109
10110 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10111 transaction: apply_additional_edits
10112 .await?
10113 .as_ref()
10114 .map(language::proto::serialize_transaction),
10115 })
10116 }
10117
10118 pub fn last_formatting_failure(&self) -> Option<&str> {
10119 self.last_formatting_failure.as_deref()
10120 }
10121
10122 pub fn reset_last_formatting_failure(&mut self) {
10123 self.last_formatting_failure = None;
10124 }
10125
10126 pub fn environment_for_buffer(
10127 &self,
10128 buffer: &Entity<Buffer>,
10129 cx: &mut Context<Self>,
10130 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10131 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10132 environment.update(cx, |env, cx| {
10133 env.get_buffer_environment(buffer, &self.worktree_store, cx)
10134 })
10135 } else {
10136 Task::ready(None).shared()
10137 }
10138 }
10139
10140 pub fn format(
10141 &mut self,
10142 buffers: HashSet<Entity<Buffer>>,
10143 target: LspFormatTarget,
10144 push_to_history: bool,
10145 trigger: FormatTrigger,
10146 cx: &mut Context<Self>,
10147 ) -> Task<anyhow::Result<ProjectTransaction>> {
10148 let logger = zlog::scoped!("format");
10149 if self.as_local().is_some() {
10150 zlog::trace!(logger => "Formatting locally");
10151 let logger = zlog::scoped!(logger => "local");
10152 let buffers = buffers
10153 .into_iter()
10154 .map(|buffer_handle| {
10155 let buffer = buffer_handle.read(cx);
10156 let buffer_abs_path = File::from_dyn(buffer.file())
10157 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10158
10159 (buffer_handle, buffer_abs_path, buffer.remote_id())
10160 })
10161 .collect::<Vec<_>>();
10162
10163 cx.spawn(async move |lsp_store, cx| {
10164 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10165
10166 for (handle, abs_path, id) in buffers {
10167 let env = lsp_store
10168 .update(cx, |lsp_store, cx| {
10169 lsp_store.environment_for_buffer(&handle, cx)
10170 })?
10171 .await;
10172
10173 let ranges = match &target {
10174 LspFormatTarget::Buffers => None,
10175 LspFormatTarget::Ranges(ranges) => {
10176 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10177 }
10178 };
10179
10180 formattable_buffers.push(FormattableBuffer {
10181 handle,
10182 abs_path,
10183 env,
10184 ranges,
10185 });
10186 }
10187 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10188
10189 let format_timer = zlog::time!(logger => "Formatting buffers");
10190 let result = LocalLspStore::format_locally(
10191 lsp_store.clone(),
10192 formattable_buffers,
10193 push_to_history,
10194 trigger,
10195 logger,
10196 cx,
10197 )
10198 .await;
10199 format_timer.end();
10200
10201 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10202
10203 lsp_store.update(cx, |lsp_store, _| {
10204 lsp_store.update_last_formatting_failure(&result);
10205 })?;
10206
10207 result
10208 })
10209 } else if let Some((client, project_id)) = self.upstream_client() {
10210 zlog::trace!(logger => "Formatting remotely");
10211 let logger = zlog::scoped!(logger => "remote");
10212 // Don't support formatting ranges via remote
10213 match target {
10214 LspFormatTarget::Buffers => {}
10215 LspFormatTarget::Ranges(_) => {
10216 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10217 return Task::ready(Ok(ProjectTransaction::default()));
10218 }
10219 }
10220
10221 let buffer_store = self.buffer_store();
10222 cx.spawn(async move |lsp_store, cx| {
10223 zlog::trace!(logger => "Sending remote format request");
10224 let request_timer = zlog::time!(logger => "remote format request");
10225 let result = client
10226 .request(proto::FormatBuffers {
10227 project_id,
10228 trigger: trigger as i32,
10229 buffer_ids: buffers
10230 .iter()
10231 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10232 .collect::<Result<_>>()?,
10233 })
10234 .await
10235 .and_then(|result| result.transaction.context("missing transaction"));
10236 request_timer.end();
10237
10238 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10239
10240 lsp_store.update(cx, |lsp_store, _| {
10241 lsp_store.update_last_formatting_failure(&result);
10242 })?;
10243
10244 let transaction_response = result?;
10245 let _timer = zlog::time!(logger => "deserializing project transaction");
10246 buffer_store
10247 .update(cx, |buffer_store, cx| {
10248 buffer_store.deserialize_project_transaction(
10249 transaction_response,
10250 push_to_history,
10251 cx,
10252 )
10253 })?
10254 .await
10255 })
10256 } else {
10257 zlog::trace!(logger => "Not formatting");
10258 Task::ready(Ok(ProjectTransaction::default()))
10259 }
10260 }
10261
10262 async fn handle_format_buffers(
10263 this: Entity<Self>,
10264 envelope: TypedEnvelope<proto::FormatBuffers>,
10265 mut cx: AsyncApp,
10266 ) -> Result<proto::FormatBuffersResponse> {
10267 let sender_id = envelope.original_sender_id().unwrap_or_default();
10268 let format = this.update(&mut cx, |this, cx| {
10269 let mut buffers = HashSet::default();
10270 for buffer_id in &envelope.payload.buffer_ids {
10271 let buffer_id = BufferId::new(*buffer_id)?;
10272 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10273 }
10274 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10275 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10276 })??;
10277
10278 let project_transaction = format.await?;
10279 let project_transaction = this.update(&mut cx, |this, cx| {
10280 this.buffer_store.update(cx, |buffer_store, cx| {
10281 buffer_store.serialize_project_transaction_for_peer(
10282 project_transaction,
10283 sender_id,
10284 cx,
10285 )
10286 })
10287 })?;
10288 Ok(proto::FormatBuffersResponse {
10289 transaction: Some(project_transaction),
10290 })
10291 }
10292
10293 async fn handle_apply_code_action_kind(
10294 this: Entity<Self>,
10295 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10296 mut cx: AsyncApp,
10297 ) -> Result<proto::ApplyCodeActionKindResponse> {
10298 let sender_id = envelope.original_sender_id().unwrap_or_default();
10299 let format = this.update(&mut cx, |this, cx| {
10300 let mut buffers = HashSet::default();
10301 for buffer_id in &envelope.payload.buffer_ids {
10302 let buffer_id = BufferId::new(*buffer_id)?;
10303 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10304 }
10305 let kind = match envelope.payload.kind.as_str() {
10306 "" => CodeActionKind::EMPTY,
10307 "quickfix" => CodeActionKind::QUICKFIX,
10308 "refactor" => CodeActionKind::REFACTOR,
10309 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10310 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10311 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10312 "source" => CodeActionKind::SOURCE,
10313 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10314 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10315 _ => anyhow::bail!(
10316 "Invalid code action kind {}",
10317 envelope.payload.kind.as_str()
10318 ),
10319 };
10320 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10321 })??;
10322
10323 let project_transaction = format.await?;
10324 let project_transaction = this.update(&mut cx, |this, cx| {
10325 this.buffer_store.update(cx, |buffer_store, cx| {
10326 buffer_store.serialize_project_transaction_for_peer(
10327 project_transaction,
10328 sender_id,
10329 cx,
10330 )
10331 })
10332 })?;
10333 Ok(proto::ApplyCodeActionKindResponse {
10334 transaction: Some(project_transaction),
10335 })
10336 }
10337
10338 async fn shutdown_language_server(
10339 server_state: Option<LanguageServerState>,
10340 name: LanguageServerName,
10341 cx: &mut AsyncApp,
10342 ) {
10343 let server = match server_state {
10344 Some(LanguageServerState::Starting { startup, .. }) => {
10345 let mut timer = cx
10346 .background_executor()
10347 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10348 .fuse();
10349
10350 select! {
10351 server = startup.fuse() => server,
10352 () = timer => {
10353 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10354 None
10355 },
10356 }
10357 }
10358
10359 Some(LanguageServerState::Running { server, .. }) => Some(server),
10360
10361 None => None,
10362 };
10363
10364 if let Some(server) = server
10365 && let Some(shutdown) = server.shutdown()
10366 {
10367 shutdown.await;
10368 }
10369 }
10370
10371 // Returns a list of all of the worktrees which no longer have a language server and the root path
10372 // for the stopped server
10373 fn stop_local_language_server(
10374 &mut self,
10375 server_id: LanguageServerId,
10376 cx: &mut Context<Self>,
10377 ) -> Task<()> {
10378 let local = match &mut self.mode {
10379 LspStoreMode::Local(local) => local,
10380 _ => {
10381 return Task::ready(());
10382 }
10383 };
10384
10385 // Remove this server ID from all entries in the given worktree.
10386 local
10387 .language_server_ids
10388 .retain(|_, state| state.id != server_id);
10389 self.buffer_store.update(cx, |buffer_store, cx| {
10390 for buffer in buffer_store.buffers() {
10391 buffer.update(cx, |buffer, cx| {
10392 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10393 buffer.set_completion_triggers(server_id, Default::default(), cx);
10394 });
10395 }
10396 });
10397
10398 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10399 summaries.retain(|path, summaries_by_server_id| {
10400 if summaries_by_server_id.remove(&server_id).is_some() {
10401 if let Some((client, project_id)) = self.downstream_client.clone() {
10402 client
10403 .send(proto::UpdateDiagnosticSummary {
10404 project_id,
10405 worktree_id: worktree_id.to_proto(),
10406 summary: Some(proto::DiagnosticSummary {
10407 path: path.as_ref().to_proto(),
10408 language_server_id: server_id.0 as u64,
10409 error_count: 0,
10410 warning_count: 0,
10411 }),
10412 more_summaries: Vec::new(),
10413 })
10414 .log_err();
10415 }
10416 !summaries_by_server_id.is_empty()
10417 } else {
10418 true
10419 }
10420 });
10421 }
10422
10423 let local = self.as_local_mut().unwrap();
10424 for diagnostics in local.diagnostics.values_mut() {
10425 diagnostics.retain(|_, diagnostics_by_server_id| {
10426 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10427 diagnostics_by_server_id.remove(ix);
10428 !diagnostics_by_server_id.is_empty()
10429 } else {
10430 true
10431 }
10432 });
10433 }
10434 local.language_server_watched_paths.remove(&server_id);
10435
10436 let server_state = local.language_servers.remove(&server_id);
10437 self.cleanup_lsp_data(server_id);
10438 let name = self
10439 .language_server_statuses
10440 .remove(&server_id)
10441 .map(|status| status.name)
10442 .or_else(|| {
10443 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10444 Some(adapter.name())
10445 } else {
10446 None
10447 }
10448 });
10449
10450 if let Some(name) = name {
10451 log::info!("stopping language server {name}");
10452 self.languages
10453 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10454 cx.notify();
10455
10456 return cx.spawn(async move |lsp_store, cx| {
10457 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10458 lsp_store
10459 .update(cx, |lsp_store, cx| {
10460 lsp_store
10461 .languages
10462 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10463 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10464 cx.notify();
10465 })
10466 .ok();
10467 });
10468 }
10469
10470 if server_state.is_some() {
10471 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10472 }
10473 Task::ready(())
10474 }
10475
10476 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10477 if let Some((client, project_id)) = self.upstream_client() {
10478 let request = client.request(proto::StopLanguageServers {
10479 project_id,
10480 buffer_ids: Vec::new(),
10481 also_servers: Vec::new(),
10482 all: true,
10483 });
10484 cx.background_spawn(request).detach_and_log_err(cx);
10485 } else {
10486 let Some(local) = self.as_local_mut() else {
10487 return;
10488 };
10489 let language_servers_to_stop = local
10490 .language_server_ids
10491 .values()
10492 .map(|state| state.id)
10493 .collect();
10494 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10495 let tasks = language_servers_to_stop
10496 .into_iter()
10497 .map(|server| self.stop_local_language_server(server, cx))
10498 .collect::<Vec<_>>();
10499 cx.background_spawn(async move {
10500 futures::future::join_all(tasks).await;
10501 })
10502 .detach();
10503 }
10504 }
10505
10506 pub fn restart_language_servers_for_buffers(
10507 &mut self,
10508 buffers: Vec<Entity<Buffer>>,
10509 only_restart_servers: HashSet<LanguageServerSelector>,
10510 cx: &mut Context<Self>,
10511 ) {
10512 if let Some((client, project_id)) = self.upstream_client() {
10513 let request = client.request(proto::RestartLanguageServers {
10514 project_id,
10515 buffer_ids: buffers
10516 .into_iter()
10517 .map(|b| b.read(cx).remote_id().to_proto())
10518 .collect(),
10519 only_servers: only_restart_servers
10520 .into_iter()
10521 .map(|selector| {
10522 let selector = match selector {
10523 LanguageServerSelector::Id(language_server_id) => {
10524 proto::language_server_selector::Selector::ServerId(
10525 language_server_id.to_proto(),
10526 )
10527 }
10528 LanguageServerSelector::Name(language_server_name) => {
10529 proto::language_server_selector::Selector::Name(
10530 language_server_name.to_string(),
10531 )
10532 }
10533 };
10534 proto::LanguageServerSelector {
10535 selector: Some(selector),
10536 }
10537 })
10538 .collect(),
10539 all: false,
10540 });
10541 cx.background_spawn(request).detach_and_log_err(cx);
10542 } else {
10543 let stop_task = if only_restart_servers.is_empty() {
10544 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10545 } else {
10546 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10547 };
10548 cx.spawn(async move |lsp_store, cx| {
10549 stop_task.await;
10550 lsp_store
10551 .update(cx, |lsp_store, cx| {
10552 for buffer in buffers {
10553 lsp_store.register_buffer_with_language_servers(
10554 &buffer,
10555 only_restart_servers.clone(),
10556 true,
10557 cx,
10558 );
10559 }
10560 })
10561 .ok()
10562 })
10563 .detach();
10564 }
10565 }
10566
10567 pub fn stop_language_servers_for_buffers(
10568 &mut self,
10569 buffers: Vec<Entity<Buffer>>,
10570 also_stop_servers: HashSet<LanguageServerSelector>,
10571 cx: &mut Context<Self>,
10572 ) -> Task<Result<()>> {
10573 if let Some((client, project_id)) = self.upstream_client() {
10574 let request = client.request(proto::StopLanguageServers {
10575 project_id,
10576 buffer_ids: buffers
10577 .into_iter()
10578 .map(|b| b.read(cx).remote_id().to_proto())
10579 .collect(),
10580 also_servers: also_stop_servers
10581 .into_iter()
10582 .map(|selector| {
10583 let selector = match selector {
10584 LanguageServerSelector::Id(language_server_id) => {
10585 proto::language_server_selector::Selector::ServerId(
10586 language_server_id.to_proto(),
10587 )
10588 }
10589 LanguageServerSelector::Name(language_server_name) => {
10590 proto::language_server_selector::Selector::Name(
10591 language_server_name.to_string(),
10592 )
10593 }
10594 };
10595 proto::LanguageServerSelector {
10596 selector: Some(selector),
10597 }
10598 })
10599 .collect(),
10600 all: false,
10601 });
10602 cx.background_spawn(async move {
10603 let _ = request.await?;
10604 Ok(())
10605 })
10606 } else {
10607 let task =
10608 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10609 cx.background_spawn(async move {
10610 task.await;
10611 Ok(())
10612 })
10613 }
10614 }
10615
10616 fn stop_local_language_servers_for_buffers(
10617 &mut self,
10618 buffers: &[Entity<Buffer>],
10619 also_stop_servers: HashSet<LanguageServerSelector>,
10620 cx: &mut Context<Self>,
10621 ) -> Task<()> {
10622 let Some(local) = self.as_local_mut() else {
10623 return Task::ready(());
10624 };
10625 let mut language_server_names_to_stop = BTreeSet::default();
10626 let mut language_servers_to_stop = also_stop_servers
10627 .into_iter()
10628 .flat_map(|selector| match selector {
10629 LanguageServerSelector::Id(id) => Some(id),
10630 LanguageServerSelector::Name(name) => {
10631 language_server_names_to_stop.insert(name);
10632 None
10633 }
10634 })
10635 .collect::<BTreeSet<_>>();
10636
10637 let mut covered_worktrees = HashSet::default();
10638 for buffer in buffers {
10639 buffer.update(cx, |buffer, cx| {
10640 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10641 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10642 && covered_worktrees.insert(worktree_id)
10643 {
10644 language_server_names_to_stop.retain(|name| {
10645 let old_ids_count = language_servers_to_stop.len();
10646 let all_language_servers_with_this_name = local
10647 .language_server_ids
10648 .iter()
10649 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
10650 language_servers_to_stop.extend(all_language_servers_with_this_name);
10651 old_ids_count == language_servers_to_stop.len()
10652 });
10653 }
10654 });
10655 }
10656 for name in language_server_names_to_stop {
10657 language_servers_to_stop.extend(
10658 local
10659 .language_server_ids
10660 .iter()
10661 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
10662 );
10663 }
10664
10665 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10666 let tasks = language_servers_to_stop
10667 .into_iter()
10668 .map(|server| self.stop_local_language_server(server, cx))
10669 .collect::<Vec<_>>();
10670
10671 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10672 }
10673
10674 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10675 let (worktree, relative_path) =
10676 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10677
10678 let project_path = ProjectPath {
10679 worktree_id: worktree.read(cx).id(),
10680 path: relative_path,
10681 };
10682
10683 Some(
10684 self.buffer_store()
10685 .read(cx)
10686 .get_by_path(&project_path)?
10687 .read(cx),
10688 )
10689 }
10690
10691 #[cfg(any(test, feature = "test-support"))]
10692 pub fn update_diagnostics(
10693 &mut self,
10694 server_id: LanguageServerId,
10695 diagnostics: lsp::PublishDiagnosticsParams,
10696 result_id: Option<String>,
10697 source_kind: DiagnosticSourceKind,
10698 disk_based_sources: &[String],
10699 cx: &mut Context<Self>,
10700 ) -> Result<()> {
10701 self.merge_lsp_diagnostics(
10702 source_kind,
10703 vec![DocumentDiagnosticsUpdate {
10704 diagnostics,
10705 result_id,
10706 server_id,
10707 disk_based_sources: Cow::Borrowed(disk_based_sources),
10708 }],
10709 |_, _, _| false,
10710 cx,
10711 )
10712 }
10713
10714 pub fn merge_lsp_diagnostics(
10715 &mut self,
10716 source_kind: DiagnosticSourceKind,
10717 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10718 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10719 cx: &mut Context<Self>,
10720 ) -> Result<()> {
10721 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10722 let updates = lsp_diagnostics
10723 .into_iter()
10724 .filter_map(|update| {
10725 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10726 Some(DocumentDiagnosticsUpdate {
10727 diagnostics: self.lsp_to_document_diagnostics(
10728 abs_path,
10729 source_kind,
10730 update.server_id,
10731 update.diagnostics,
10732 &update.disk_based_sources,
10733 ),
10734 result_id: update.result_id,
10735 server_id: update.server_id,
10736 disk_based_sources: update.disk_based_sources,
10737 })
10738 })
10739 .collect();
10740 self.merge_diagnostic_entries(updates, merge, cx)?;
10741 Ok(())
10742 }
10743
10744 fn lsp_to_document_diagnostics(
10745 &mut self,
10746 document_abs_path: PathBuf,
10747 source_kind: DiagnosticSourceKind,
10748 server_id: LanguageServerId,
10749 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10750 disk_based_sources: &[String],
10751 ) -> DocumentDiagnostics {
10752 let mut diagnostics = Vec::default();
10753 let mut primary_diagnostic_group_ids = HashMap::default();
10754 let mut sources_by_group_id = HashMap::default();
10755 let mut supporting_diagnostics = HashMap::default();
10756
10757 let adapter = self.language_server_adapter_for_id(server_id);
10758
10759 // Ensure that primary diagnostics are always the most severe
10760 lsp_diagnostics
10761 .diagnostics
10762 .sort_by_key(|item| item.severity);
10763
10764 for diagnostic in &lsp_diagnostics.diagnostics {
10765 let source = diagnostic.source.as_ref();
10766 let range = range_from_lsp(diagnostic.range);
10767 let is_supporting = diagnostic
10768 .related_information
10769 .as_ref()
10770 .is_some_and(|infos| {
10771 infos.iter().any(|info| {
10772 primary_diagnostic_group_ids.contains_key(&(
10773 source,
10774 diagnostic.code.clone(),
10775 range_from_lsp(info.location.range),
10776 ))
10777 })
10778 });
10779
10780 let is_unnecessary = diagnostic
10781 .tags
10782 .as_ref()
10783 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10784
10785 let underline = self
10786 .language_server_adapter_for_id(server_id)
10787 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
10788
10789 if is_supporting {
10790 supporting_diagnostics.insert(
10791 (source, diagnostic.code.clone(), range),
10792 (diagnostic.severity, is_unnecessary),
10793 );
10794 } else {
10795 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10796 let is_disk_based =
10797 source.is_some_and(|source| disk_based_sources.contains(source));
10798
10799 sources_by_group_id.insert(group_id, source);
10800 primary_diagnostic_group_ids
10801 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10802
10803 diagnostics.push(DiagnosticEntry {
10804 range,
10805 diagnostic: Diagnostic {
10806 source: diagnostic.source.clone(),
10807 source_kind,
10808 code: diagnostic.code.clone(),
10809 code_description: diagnostic
10810 .code_description
10811 .as_ref()
10812 .and_then(|d| d.href.clone()),
10813 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10814 markdown: adapter.as_ref().and_then(|adapter| {
10815 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10816 }),
10817 message: diagnostic.message.trim().to_string(),
10818 group_id,
10819 is_primary: true,
10820 is_disk_based,
10821 is_unnecessary,
10822 underline,
10823 data: diagnostic.data.clone(),
10824 },
10825 });
10826 if let Some(infos) = &diagnostic.related_information {
10827 for info in infos {
10828 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10829 let range = range_from_lsp(info.location.range);
10830 diagnostics.push(DiagnosticEntry {
10831 range,
10832 diagnostic: Diagnostic {
10833 source: diagnostic.source.clone(),
10834 source_kind,
10835 code: diagnostic.code.clone(),
10836 code_description: diagnostic
10837 .code_description
10838 .as_ref()
10839 .and_then(|d| d.href.clone()),
10840 severity: DiagnosticSeverity::INFORMATION,
10841 markdown: adapter.as_ref().and_then(|adapter| {
10842 adapter.diagnostic_message_to_markdown(&info.message)
10843 }),
10844 message: info.message.trim().to_string(),
10845 group_id,
10846 is_primary: false,
10847 is_disk_based,
10848 is_unnecessary: false,
10849 underline,
10850 data: diagnostic.data.clone(),
10851 },
10852 });
10853 }
10854 }
10855 }
10856 }
10857 }
10858
10859 for entry in &mut diagnostics {
10860 let diagnostic = &mut entry.diagnostic;
10861 if !diagnostic.is_primary {
10862 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10863 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10864 source,
10865 diagnostic.code.clone(),
10866 entry.range.clone(),
10867 )) {
10868 if let Some(severity) = severity {
10869 diagnostic.severity = severity;
10870 }
10871 diagnostic.is_unnecessary = is_unnecessary;
10872 }
10873 }
10874 }
10875
10876 DocumentDiagnostics {
10877 diagnostics,
10878 document_abs_path,
10879 version: lsp_diagnostics.version,
10880 }
10881 }
10882
10883 fn insert_newly_running_language_server(
10884 &mut self,
10885 adapter: Arc<CachedLspAdapter>,
10886 language_server: Arc<LanguageServer>,
10887 server_id: LanguageServerId,
10888 key: LanguageServerSeed,
10889 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
10890 cx: &mut Context<Self>,
10891 ) {
10892 let Some(local) = self.as_local_mut() else {
10893 return;
10894 };
10895 // If the language server for this key doesn't match the server id, don't store the
10896 // server. Which will cause it to be dropped, killing the process
10897 if local
10898 .language_server_ids
10899 .get(&key)
10900 .map(|state| state.id != server_id)
10901 .unwrap_or(false)
10902 {
10903 return;
10904 }
10905
10906 // Update language_servers collection with Running variant of LanguageServerState
10907 // indicating that the server is up and running and ready
10908 let workspace_folders = workspace_folders.lock().clone();
10909 language_server.set_workspace_folders(workspace_folders);
10910
10911 let workspace_diagnostics_refresh_tasks = language_server
10912 .capabilities()
10913 .diagnostic_provider
10914 .and_then(|provider| {
10915 local
10916 .language_server_dynamic_registrations
10917 .entry(server_id)
10918 .or_default()
10919 .diagnostics
10920 .entry(None)
10921 .or_insert(provider.clone());
10922 let workspace_refresher =
10923 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
10924
10925 Some((None, workspace_refresher))
10926 })
10927 .into_iter()
10928 .collect();
10929 local.language_servers.insert(
10930 server_id,
10931 LanguageServerState::Running {
10932 workspace_diagnostics_refresh_tasks,
10933 adapter: adapter.clone(),
10934 server: language_server.clone(),
10935 simulate_disk_based_diagnostics_completion: None,
10936 },
10937 );
10938 local
10939 .languages
10940 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
10941 if let Some(file_ops_caps) = language_server
10942 .capabilities()
10943 .workspace
10944 .as_ref()
10945 .and_then(|ws| ws.file_operations.as_ref())
10946 {
10947 let did_rename_caps = file_ops_caps.did_rename.as_ref();
10948 let will_rename_caps = file_ops_caps.will_rename.as_ref();
10949 if did_rename_caps.or(will_rename_caps).is_some() {
10950 let watcher = RenamePathsWatchedForServer::default()
10951 .with_did_rename_patterns(did_rename_caps)
10952 .with_will_rename_patterns(will_rename_caps);
10953 local
10954 .language_server_paths_watched_for_rename
10955 .insert(server_id, watcher);
10956 }
10957 }
10958
10959 self.language_server_statuses.insert(
10960 server_id,
10961 LanguageServerStatus {
10962 name: language_server.name(),
10963 pending_work: Default::default(),
10964 has_pending_diagnostic_updates: false,
10965 progress_tokens: Default::default(),
10966 worktree: Some(key.worktree_id),
10967 },
10968 );
10969
10970 cx.emit(LspStoreEvent::LanguageServerAdded(
10971 server_id,
10972 language_server.name(),
10973 Some(key.worktree_id),
10974 ));
10975 cx.emit(LspStoreEvent::RefreshInlayHints(server_id));
10976
10977 let server_capabilities = language_server.capabilities();
10978 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
10979 downstream_client
10980 .send(proto::StartLanguageServer {
10981 project_id: *project_id,
10982 server: Some(proto::LanguageServer {
10983 id: server_id.to_proto(),
10984 name: language_server.name().to_string(),
10985 worktree_id: Some(key.worktree_id.to_proto()),
10986 }),
10987 capabilities: serde_json::to_string(&server_capabilities)
10988 .expect("serializing server LSP capabilities"),
10989 })
10990 .log_err();
10991 }
10992 self.lsp_server_capabilities
10993 .insert(server_id, server_capabilities);
10994
10995 // Tell the language server about every open buffer in the worktree that matches the language.
10996 // Also check for buffers in worktrees that reused this server
10997 let mut worktrees_using_server = vec![key.worktree_id];
10998 if let Some(local) = self.as_local() {
10999 // Find all worktrees that have this server in their language server tree
11000 for (worktree_id, servers) in &local.lsp_tree.instances {
11001 if *worktree_id != key.worktree_id {
11002 for server_map in servers.roots.values() {
11003 if server_map
11004 .values()
11005 .any(|(node, _)| node.id() == Some(server_id))
11006 {
11007 worktrees_using_server.push(*worktree_id);
11008 }
11009 }
11010 }
11011 }
11012 }
11013
11014 let mut buffer_paths_registered = Vec::new();
11015 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11016 let mut lsp_adapters = HashMap::default();
11017 for buffer_handle in buffer_store.buffers() {
11018 let buffer = buffer_handle.read(cx);
11019 let file = match File::from_dyn(buffer.file()) {
11020 Some(file) => file,
11021 None => continue,
11022 };
11023 let language = match buffer.language() {
11024 Some(language) => language,
11025 None => continue,
11026 };
11027
11028 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11029 || !lsp_adapters
11030 .entry(language.name())
11031 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11032 .iter()
11033 .any(|a| a.name == key.name)
11034 {
11035 continue;
11036 }
11037 // didOpen
11038 let file = match file.as_local() {
11039 Some(file) => file,
11040 None => continue,
11041 };
11042
11043 let local = self.as_local_mut().unwrap();
11044
11045 let buffer_id = buffer.remote_id();
11046 if local.registered_buffers.contains_key(&buffer_id) {
11047 let versions = local
11048 .buffer_snapshots
11049 .entry(buffer_id)
11050 .or_default()
11051 .entry(server_id)
11052 .and_modify(|_| {
11053 assert!(
11054 false,
11055 "There should not be an existing snapshot for a newly inserted buffer"
11056 )
11057 })
11058 .or_insert_with(|| {
11059 vec![LspBufferSnapshot {
11060 version: 0,
11061 snapshot: buffer.text_snapshot(),
11062 }]
11063 });
11064
11065 let snapshot = versions.last().unwrap();
11066 let version = snapshot.version;
11067 let initial_snapshot = &snapshot.snapshot;
11068 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11069 language_server.register_buffer(
11070 uri,
11071 adapter.language_id(&language.name()),
11072 version,
11073 initial_snapshot.text(),
11074 );
11075 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11076 local
11077 .buffers_opened_in_servers
11078 .entry(buffer_id)
11079 .or_default()
11080 .insert(server_id);
11081 }
11082 buffer_handle.update(cx, |buffer, cx| {
11083 buffer.set_completion_triggers(
11084 server_id,
11085 language_server
11086 .capabilities()
11087 .completion_provider
11088 .as_ref()
11089 .and_then(|provider| {
11090 provider
11091 .trigger_characters
11092 .as_ref()
11093 .map(|characters| characters.iter().cloned().collect())
11094 })
11095 .unwrap_or_default(),
11096 cx,
11097 )
11098 });
11099 }
11100 });
11101
11102 for (buffer_id, abs_path) in buffer_paths_registered {
11103 cx.emit(LspStoreEvent::LanguageServerUpdate {
11104 language_server_id: server_id,
11105 name: Some(adapter.name()),
11106 message: proto::update_language_server::Variant::RegisteredForBuffer(
11107 proto::RegisteredForBuffer {
11108 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11109 buffer_id: buffer_id.to_proto(),
11110 },
11111 ),
11112 });
11113 }
11114
11115 cx.notify();
11116 }
11117
11118 pub fn language_servers_running_disk_based_diagnostics(
11119 &self,
11120 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11121 self.language_server_statuses
11122 .iter()
11123 .filter_map(|(id, status)| {
11124 if status.has_pending_diagnostic_updates {
11125 Some(*id)
11126 } else {
11127 None
11128 }
11129 })
11130 }
11131
11132 pub(crate) fn cancel_language_server_work_for_buffers(
11133 &mut self,
11134 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11135 cx: &mut Context<Self>,
11136 ) {
11137 if let Some((client, project_id)) = self.upstream_client() {
11138 let request = client.request(proto::CancelLanguageServerWork {
11139 project_id,
11140 work: Some(proto::cancel_language_server_work::Work::Buffers(
11141 proto::cancel_language_server_work::Buffers {
11142 buffer_ids: buffers
11143 .into_iter()
11144 .map(|b| b.read(cx).remote_id().to_proto())
11145 .collect(),
11146 },
11147 )),
11148 });
11149 cx.background_spawn(request).detach_and_log_err(cx);
11150 } else if let Some(local) = self.as_local() {
11151 let servers = buffers
11152 .into_iter()
11153 .flat_map(|buffer| {
11154 buffer.update(cx, |buffer, cx| {
11155 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11156 })
11157 })
11158 .collect::<HashSet<_>>();
11159 for server_id in servers {
11160 self.cancel_language_server_work(server_id, None, cx);
11161 }
11162 }
11163 }
11164
11165 pub(crate) fn cancel_language_server_work(
11166 &mut self,
11167 server_id: LanguageServerId,
11168 token_to_cancel: Option<ProgressToken>,
11169 cx: &mut Context<Self>,
11170 ) {
11171 if let Some(local) = self.as_local() {
11172 let status = self.language_server_statuses.get(&server_id);
11173 let server = local.language_servers.get(&server_id);
11174 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11175 {
11176 for (token, progress) in &status.pending_work {
11177 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11178 && token != token_to_cancel
11179 {
11180 continue;
11181 }
11182 if progress.is_cancellable {
11183 server
11184 .notify::<lsp::notification::WorkDoneProgressCancel>(
11185 WorkDoneProgressCancelParams {
11186 token: token.to_lsp(),
11187 },
11188 )
11189 .ok();
11190 }
11191 }
11192 }
11193 } else if let Some((client, project_id)) = self.upstream_client() {
11194 let request = client.request(proto::CancelLanguageServerWork {
11195 project_id,
11196 work: Some(
11197 proto::cancel_language_server_work::Work::LanguageServerWork(
11198 proto::cancel_language_server_work::LanguageServerWork {
11199 language_server_id: server_id.to_proto(),
11200 token: token_to_cancel.map(|token| token.to_proto()),
11201 },
11202 ),
11203 ),
11204 });
11205 cx.background_spawn(request).detach_and_log_err(cx);
11206 }
11207 }
11208
11209 fn register_supplementary_language_server(
11210 &mut self,
11211 id: LanguageServerId,
11212 name: LanguageServerName,
11213 server: Arc<LanguageServer>,
11214 cx: &mut Context<Self>,
11215 ) {
11216 if let Some(local) = self.as_local_mut() {
11217 local
11218 .supplementary_language_servers
11219 .insert(id, (name.clone(), server));
11220 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11221 }
11222 }
11223
11224 fn unregister_supplementary_language_server(
11225 &mut self,
11226 id: LanguageServerId,
11227 cx: &mut Context<Self>,
11228 ) {
11229 if let Some(local) = self.as_local_mut() {
11230 local.supplementary_language_servers.remove(&id);
11231 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11232 }
11233 }
11234
11235 pub(crate) fn supplementary_language_servers(
11236 &self,
11237 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11238 self.as_local().into_iter().flat_map(|local| {
11239 local
11240 .supplementary_language_servers
11241 .iter()
11242 .map(|(id, (name, _))| (*id, name.clone()))
11243 })
11244 }
11245
11246 pub fn language_server_adapter_for_id(
11247 &self,
11248 id: LanguageServerId,
11249 ) -> Option<Arc<CachedLspAdapter>> {
11250 self.as_local()
11251 .and_then(|local| local.language_servers.get(&id))
11252 .and_then(|language_server_state| match language_server_state {
11253 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11254 _ => None,
11255 })
11256 }
11257
11258 pub(super) fn update_local_worktree_language_servers(
11259 &mut self,
11260 worktree_handle: &Entity<Worktree>,
11261 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11262 cx: &mut Context<Self>,
11263 ) {
11264 if changes.is_empty() {
11265 return;
11266 }
11267
11268 let Some(local) = self.as_local() else { return };
11269
11270 local.prettier_store.update(cx, |prettier_store, cx| {
11271 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11272 });
11273
11274 let worktree_id = worktree_handle.read(cx).id();
11275 let mut language_server_ids = local
11276 .language_server_ids
11277 .iter()
11278 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11279 .collect::<Vec<_>>();
11280 language_server_ids.sort();
11281 language_server_ids.dedup();
11282
11283 // let abs_path = worktree_handle.read(cx).abs_path();
11284 for server_id in &language_server_ids {
11285 if let Some(LanguageServerState::Running { server, .. }) =
11286 local.language_servers.get(server_id)
11287 && let Some(watched_paths) = local
11288 .language_server_watched_paths
11289 .get(server_id)
11290 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11291 {
11292 let params = lsp::DidChangeWatchedFilesParams {
11293 changes: changes
11294 .iter()
11295 .filter_map(|(path, _, change)| {
11296 if !watched_paths.is_match(path.as_std_path()) {
11297 return None;
11298 }
11299 let typ = match change {
11300 PathChange::Loaded => return None,
11301 PathChange::Added => lsp::FileChangeType::CREATED,
11302 PathChange::Removed => lsp::FileChangeType::DELETED,
11303 PathChange::Updated => lsp::FileChangeType::CHANGED,
11304 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11305 };
11306 let uri = lsp::Uri::from_file_path(
11307 worktree_handle.read(cx).absolutize(&path),
11308 )
11309 .ok()?;
11310 Some(lsp::FileEvent { uri, typ })
11311 })
11312 .collect(),
11313 };
11314 if !params.changes.is_empty() {
11315 server
11316 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11317 .ok();
11318 }
11319 }
11320 }
11321 for (path, _, _) in changes {
11322 if let Some(file_name) = path.file_name()
11323 && local.watched_manifest_filenames.contains(file_name)
11324 {
11325 self.request_workspace_config_refresh();
11326 break;
11327 }
11328 }
11329 }
11330
11331 pub fn wait_for_remote_buffer(
11332 &mut self,
11333 id: BufferId,
11334 cx: &mut Context<Self>,
11335 ) -> Task<Result<Entity<Buffer>>> {
11336 self.buffer_store.update(cx, |buffer_store, cx| {
11337 buffer_store.wait_for_remote_buffer(id, cx)
11338 })
11339 }
11340
11341 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11342 let mut result = proto::Symbol {
11343 language_server_name: symbol.language_server_name.0.to_string(),
11344 source_worktree_id: symbol.source_worktree_id.to_proto(),
11345 language_server_id: symbol.source_language_server_id.to_proto(),
11346 name: symbol.name.clone(),
11347 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11348 start: Some(proto::PointUtf16 {
11349 row: symbol.range.start.0.row,
11350 column: symbol.range.start.0.column,
11351 }),
11352 end: Some(proto::PointUtf16 {
11353 row: symbol.range.end.0.row,
11354 column: symbol.range.end.0.column,
11355 }),
11356 worktree_id: Default::default(),
11357 path: Default::default(),
11358 signature: Default::default(),
11359 };
11360 match &symbol.path {
11361 SymbolLocation::InProject(path) => {
11362 result.worktree_id = path.worktree_id.to_proto();
11363 result.path = path.path.to_proto();
11364 }
11365 SymbolLocation::OutsideProject {
11366 abs_path,
11367 signature,
11368 } => {
11369 result.path = abs_path.to_string_lossy().into_owned();
11370 result.signature = signature.to_vec();
11371 }
11372 }
11373 result
11374 }
11375
11376 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11377 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11378 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11379 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11380
11381 let path = if serialized_symbol.signature.is_empty() {
11382 SymbolLocation::InProject(ProjectPath {
11383 worktree_id,
11384 path: RelPath::from_proto(&serialized_symbol.path)
11385 .context("invalid symbol path")?,
11386 })
11387 } else {
11388 SymbolLocation::OutsideProject {
11389 abs_path: Path::new(&serialized_symbol.path).into(),
11390 signature: serialized_symbol
11391 .signature
11392 .try_into()
11393 .map_err(|_| anyhow!("invalid signature"))?,
11394 }
11395 };
11396
11397 let start = serialized_symbol.start.context("invalid start")?;
11398 let end = serialized_symbol.end.context("invalid end")?;
11399 Ok(CoreSymbol {
11400 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11401 source_worktree_id,
11402 source_language_server_id: LanguageServerId::from_proto(
11403 serialized_symbol.language_server_id,
11404 ),
11405 path,
11406 name: serialized_symbol.name,
11407 range: Unclipped(PointUtf16::new(start.row, start.column))
11408 ..Unclipped(PointUtf16::new(end.row, end.column)),
11409 kind,
11410 })
11411 }
11412
11413 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11414 let mut serialized_completion = proto::Completion {
11415 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11416 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11417 new_text: completion.new_text.clone(),
11418 ..proto::Completion::default()
11419 };
11420 match &completion.source {
11421 CompletionSource::Lsp {
11422 insert_range,
11423 server_id,
11424 lsp_completion,
11425 lsp_defaults,
11426 resolved,
11427 } => {
11428 let (old_insert_start, old_insert_end) = insert_range
11429 .as_ref()
11430 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11431 .unzip();
11432
11433 serialized_completion.old_insert_start = old_insert_start;
11434 serialized_completion.old_insert_end = old_insert_end;
11435 serialized_completion.source = proto::completion::Source::Lsp as i32;
11436 serialized_completion.server_id = server_id.0 as u64;
11437 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11438 serialized_completion.lsp_defaults = lsp_defaults
11439 .as_deref()
11440 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11441 serialized_completion.resolved = *resolved;
11442 }
11443 CompletionSource::BufferWord {
11444 word_range,
11445 resolved,
11446 } => {
11447 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11448 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11449 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11450 serialized_completion.resolved = *resolved;
11451 }
11452 CompletionSource::Custom => {
11453 serialized_completion.source = proto::completion::Source::Custom as i32;
11454 serialized_completion.resolved = true;
11455 }
11456 CompletionSource::Dap { sort_text } => {
11457 serialized_completion.source = proto::completion::Source::Dap as i32;
11458 serialized_completion.sort_text = Some(sort_text.clone());
11459 }
11460 }
11461
11462 serialized_completion
11463 }
11464
11465 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11466 let old_replace_start = completion
11467 .old_replace_start
11468 .and_then(deserialize_anchor)
11469 .context("invalid old start")?;
11470 let old_replace_end = completion
11471 .old_replace_end
11472 .and_then(deserialize_anchor)
11473 .context("invalid old end")?;
11474 let insert_range = {
11475 match completion.old_insert_start.zip(completion.old_insert_end) {
11476 Some((start, end)) => {
11477 let start = deserialize_anchor(start).context("invalid insert old start")?;
11478 let end = deserialize_anchor(end).context("invalid insert old end")?;
11479 Some(start..end)
11480 }
11481 None => None,
11482 }
11483 };
11484 Ok(CoreCompletion {
11485 replace_range: old_replace_start..old_replace_end,
11486 new_text: completion.new_text,
11487 source: match proto::completion::Source::from_i32(completion.source) {
11488 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11489 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11490 insert_range,
11491 server_id: LanguageServerId::from_proto(completion.server_id),
11492 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11493 lsp_defaults: completion
11494 .lsp_defaults
11495 .as_deref()
11496 .map(serde_json::from_slice)
11497 .transpose()?,
11498 resolved: completion.resolved,
11499 },
11500 Some(proto::completion::Source::BufferWord) => {
11501 let word_range = completion
11502 .buffer_word_start
11503 .and_then(deserialize_anchor)
11504 .context("invalid buffer word start")?
11505 ..completion
11506 .buffer_word_end
11507 .and_then(deserialize_anchor)
11508 .context("invalid buffer word end")?;
11509 CompletionSource::BufferWord {
11510 word_range,
11511 resolved: completion.resolved,
11512 }
11513 }
11514 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11515 sort_text: completion
11516 .sort_text
11517 .context("expected sort text to exist")?,
11518 },
11519 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11520 },
11521 })
11522 }
11523
11524 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11525 let (kind, lsp_action) = match &action.lsp_action {
11526 LspAction::Action(code_action) => (
11527 proto::code_action::Kind::Action as i32,
11528 serde_json::to_vec(code_action).unwrap(),
11529 ),
11530 LspAction::Command(command) => (
11531 proto::code_action::Kind::Command as i32,
11532 serde_json::to_vec(command).unwrap(),
11533 ),
11534 LspAction::CodeLens(code_lens) => (
11535 proto::code_action::Kind::CodeLens as i32,
11536 serde_json::to_vec(code_lens).unwrap(),
11537 ),
11538 };
11539
11540 proto::CodeAction {
11541 server_id: action.server_id.0 as u64,
11542 start: Some(serialize_anchor(&action.range.start)),
11543 end: Some(serialize_anchor(&action.range.end)),
11544 lsp_action,
11545 kind,
11546 resolved: action.resolved,
11547 }
11548 }
11549
11550 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11551 let start = action
11552 .start
11553 .and_then(deserialize_anchor)
11554 .context("invalid start")?;
11555 let end = action
11556 .end
11557 .and_then(deserialize_anchor)
11558 .context("invalid end")?;
11559 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11560 Some(proto::code_action::Kind::Action) => {
11561 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11562 }
11563 Some(proto::code_action::Kind::Command) => {
11564 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11565 }
11566 Some(proto::code_action::Kind::CodeLens) => {
11567 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11568 }
11569 None => anyhow::bail!("Unknown action kind {}", action.kind),
11570 };
11571 Ok(CodeAction {
11572 server_id: LanguageServerId(action.server_id as usize),
11573 range: start..end,
11574 resolved: action.resolved,
11575 lsp_action,
11576 })
11577 }
11578
11579 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11580 match &formatting_result {
11581 Ok(_) => self.last_formatting_failure = None,
11582 Err(error) => {
11583 let error_string = format!("{error:#}");
11584 log::error!("Formatting failed: {error_string}");
11585 self.last_formatting_failure
11586 .replace(error_string.lines().join(" "));
11587 }
11588 }
11589 }
11590
11591 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11592 self.lsp_server_capabilities.remove(&for_server);
11593 for lsp_data in self.lsp_data.values_mut() {
11594 lsp_data.remove_server_data(for_server);
11595 }
11596 if let Some(local) = self.as_local_mut() {
11597 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11598 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11599 buffer_servers.remove(&for_server);
11600 }
11601 }
11602 }
11603
11604 pub fn result_id(
11605 &self,
11606 server_id: LanguageServerId,
11607 buffer_id: BufferId,
11608 cx: &App,
11609 ) -> Option<String> {
11610 let abs_path = self
11611 .buffer_store
11612 .read(cx)
11613 .get(buffer_id)
11614 .and_then(|b| File::from_dyn(b.read(cx).file()))
11615 .map(|f| f.abs_path(cx))?;
11616 self.as_local()?
11617 .buffer_pull_diagnostics_result_ids
11618 .get(&server_id)?
11619 .get(&abs_path)?
11620 .clone()
11621 }
11622
11623 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11624 let Some(local) = self.as_local() else {
11625 return HashMap::default();
11626 };
11627 local
11628 .buffer_pull_diagnostics_result_ids
11629 .get(&server_id)
11630 .into_iter()
11631 .flatten()
11632 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11633 .collect()
11634 }
11635
11636 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11637 if let Some(LanguageServerState::Running {
11638 workspace_diagnostics_refresh_tasks,
11639 ..
11640 }) = self
11641 .as_local_mut()
11642 .and_then(|local| local.language_servers.get_mut(&server_id))
11643 {
11644 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11645 diagnostics.refresh_tx.try_send(()).ok();
11646 }
11647 }
11648 }
11649
11650 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11651 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11652 return;
11653 };
11654 let Some(local) = self.as_local_mut() else {
11655 return;
11656 };
11657
11658 for server_id in buffer.update(cx, |buffer, cx| {
11659 local.language_server_ids_for_buffer(buffer, cx)
11660 }) {
11661 if let Some(LanguageServerState::Running {
11662 workspace_diagnostics_refresh_tasks,
11663 ..
11664 }) = local.language_servers.get_mut(&server_id)
11665 {
11666 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
11667 diagnostics.refresh_tx.try_send(()).ok();
11668 }
11669 }
11670 }
11671 }
11672
11673 fn apply_workspace_diagnostic_report(
11674 &mut self,
11675 server_id: LanguageServerId,
11676 report: lsp::WorkspaceDiagnosticReportResult,
11677 cx: &mut Context<Self>,
11678 ) {
11679 let workspace_diagnostics =
11680 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11681 let mut unchanged_buffers = HashSet::default();
11682 let mut changed_buffers = HashSet::default();
11683 let workspace_diagnostics_updates = workspace_diagnostics
11684 .into_iter()
11685 .filter_map(
11686 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11687 LspPullDiagnostics::Response {
11688 server_id,
11689 uri,
11690 diagnostics,
11691 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11692 LspPullDiagnostics::Default => None,
11693 },
11694 )
11695 .fold(
11696 HashMap::default(),
11697 |mut acc, (server_id, uri, diagnostics, version)| {
11698 let (result_id, diagnostics) = match diagnostics {
11699 PulledDiagnostics::Unchanged { result_id } => {
11700 unchanged_buffers.insert(uri.clone());
11701 (Some(result_id), Vec::new())
11702 }
11703 PulledDiagnostics::Changed {
11704 result_id,
11705 diagnostics,
11706 } => {
11707 changed_buffers.insert(uri.clone());
11708 (result_id, diagnostics)
11709 }
11710 };
11711 let disk_based_sources = Cow::Owned(
11712 self.language_server_adapter_for_id(server_id)
11713 .as_ref()
11714 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11715 .unwrap_or(&[])
11716 .to_vec(),
11717 );
11718 acc.entry(server_id)
11719 .or_insert_with(Vec::new)
11720 .push(DocumentDiagnosticsUpdate {
11721 server_id,
11722 diagnostics: lsp::PublishDiagnosticsParams {
11723 uri,
11724 diagnostics,
11725 version,
11726 },
11727 result_id,
11728 disk_based_sources,
11729 });
11730 acc
11731 },
11732 );
11733
11734 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11735 self.merge_lsp_diagnostics(
11736 DiagnosticSourceKind::Pulled,
11737 diagnostic_updates,
11738 |buffer, old_diagnostic, cx| {
11739 File::from_dyn(buffer.file())
11740 .and_then(|file| {
11741 let abs_path = file.as_local()?.abs_path(cx);
11742 lsp::Uri::from_file_path(abs_path).ok()
11743 })
11744 .is_none_or(|buffer_uri| {
11745 unchanged_buffers.contains(&buffer_uri)
11746 || match old_diagnostic.source_kind {
11747 DiagnosticSourceKind::Pulled => {
11748 !changed_buffers.contains(&buffer_uri)
11749 }
11750 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11751 true
11752 }
11753 }
11754 })
11755 },
11756 cx,
11757 )
11758 .log_err();
11759 }
11760 }
11761
11762 fn register_server_capabilities(
11763 &mut self,
11764 server_id: LanguageServerId,
11765 params: lsp::RegistrationParams,
11766 cx: &mut Context<Self>,
11767 ) -> anyhow::Result<()> {
11768 let server = self
11769 .language_server_for_id(server_id)
11770 .with_context(|| format!("no server {server_id} found"))?;
11771 for reg in params.registrations {
11772 match reg.method.as_str() {
11773 "workspace/didChangeWatchedFiles" => {
11774 if let Some(options) = reg.register_options {
11775 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
11776 let caps = serde_json::from_value(options)?;
11777 local_lsp_store
11778 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
11779 true
11780 } else {
11781 false
11782 };
11783 if notify {
11784 notify_server_capabilities_updated(&server, cx);
11785 }
11786 }
11787 }
11788 "workspace/didChangeConfiguration" => {
11789 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
11790 }
11791 "workspace/didChangeWorkspaceFolders" => {
11792 // In this case register options is an empty object, we can ignore it
11793 let caps = lsp::WorkspaceFoldersServerCapabilities {
11794 supported: Some(true),
11795 change_notifications: Some(OneOf::Right(reg.id)),
11796 };
11797 server.update_capabilities(|capabilities| {
11798 capabilities
11799 .workspace
11800 .get_or_insert_default()
11801 .workspace_folders = Some(caps);
11802 });
11803 notify_server_capabilities_updated(&server, cx);
11804 }
11805 "workspace/symbol" => {
11806 let options = parse_register_capabilities(reg)?;
11807 server.update_capabilities(|capabilities| {
11808 capabilities.workspace_symbol_provider = Some(options);
11809 });
11810 notify_server_capabilities_updated(&server, cx);
11811 }
11812 "workspace/fileOperations" => {
11813 if let Some(options) = reg.register_options {
11814 let caps = serde_json::from_value(options)?;
11815 server.update_capabilities(|capabilities| {
11816 capabilities
11817 .workspace
11818 .get_or_insert_default()
11819 .file_operations = Some(caps);
11820 });
11821 notify_server_capabilities_updated(&server, cx);
11822 }
11823 }
11824 "workspace/executeCommand" => {
11825 if let Some(options) = reg.register_options {
11826 let options = serde_json::from_value(options)?;
11827 server.update_capabilities(|capabilities| {
11828 capabilities.execute_command_provider = Some(options);
11829 });
11830 notify_server_capabilities_updated(&server, cx);
11831 }
11832 }
11833 "textDocument/rangeFormatting" => {
11834 let options = parse_register_capabilities(reg)?;
11835 server.update_capabilities(|capabilities| {
11836 capabilities.document_range_formatting_provider = Some(options);
11837 });
11838 notify_server_capabilities_updated(&server, cx);
11839 }
11840 "textDocument/onTypeFormatting" => {
11841 if let Some(options) = reg
11842 .register_options
11843 .map(serde_json::from_value)
11844 .transpose()?
11845 {
11846 server.update_capabilities(|capabilities| {
11847 capabilities.document_on_type_formatting_provider = Some(options);
11848 });
11849 notify_server_capabilities_updated(&server, cx);
11850 }
11851 }
11852 "textDocument/formatting" => {
11853 let options = parse_register_capabilities(reg)?;
11854 server.update_capabilities(|capabilities| {
11855 capabilities.document_formatting_provider = Some(options);
11856 });
11857 notify_server_capabilities_updated(&server, cx);
11858 }
11859 "textDocument/rename" => {
11860 let options = parse_register_capabilities(reg)?;
11861 server.update_capabilities(|capabilities| {
11862 capabilities.rename_provider = Some(options);
11863 });
11864 notify_server_capabilities_updated(&server, cx);
11865 }
11866 "textDocument/inlayHint" => {
11867 let options = parse_register_capabilities(reg)?;
11868 server.update_capabilities(|capabilities| {
11869 capabilities.inlay_hint_provider = Some(options);
11870 });
11871 notify_server_capabilities_updated(&server, cx);
11872 }
11873 "textDocument/documentSymbol" => {
11874 let options = parse_register_capabilities(reg)?;
11875 server.update_capabilities(|capabilities| {
11876 capabilities.document_symbol_provider = Some(options);
11877 });
11878 notify_server_capabilities_updated(&server, cx);
11879 }
11880 "textDocument/codeAction" => {
11881 let options = parse_register_capabilities(reg)?;
11882 let provider = match options {
11883 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
11884 OneOf::Right(caps) => caps,
11885 };
11886 server.update_capabilities(|capabilities| {
11887 capabilities.code_action_provider = Some(provider);
11888 });
11889 notify_server_capabilities_updated(&server, cx);
11890 }
11891 "textDocument/definition" => {
11892 let options = parse_register_capabilities(reg)?;
11893 server.update_capabilities(|capabilities| {
11894 capabilities.definition_provider = Some(options);
11895 });
11896 notify_server_capabilities_updated(&server, cx);
11897 }
11898 "textDocument/completion" => {
11899 if let Some(caps) = reg
11900 .register_options
11901 .map(serde_json::from_value)
11902 .transpose()?
11903 {
11904 server.update_capabilities(|capabilities| {
11905 capabilities.completion_provider = Some(caps);
11906 });
11907 notify_server_capabilities_updated(&server, cx);
11908 }
11909 }
11910 "textDocument/hover" => {
11911 let options = parse_register_capabilities(reg)?;
11912 let provider = match options {
11913 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
11914 OneOf::Right(caps) => caps,
11915 };
11916 server.update_capabilities(|capabilities| {
11917 capabilities.hover_provider = Some(provider);
11918 });
11919 notify_server_capabilities_updated(&server, cx);
11920 }
11921 "textDocument/signatureHelp" => {
11922 if let Some(caps) = reg
11923 .register_options
11924 .map(serde_json::from_value)
11925 .transpose()?
11926 {
11927 server.update_capabilities(|capabilities| {
11928 capabilities.signature_help_provider = Some(caps);
11929 });
11930 notify_server_capabilities_updated(&server, cx);
11931 }
11932 }
11933 "textDocument/didChange" => {
11934 if let Some(sync_kind) = reg
11935 .register_options
11936 .and_then(|opts| opts.get("syncKind").cloned())
11937 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
11938 .transpose()?
11939 {
11940 server.update_capabilities(|capabilities| {
11941 let mut sync_options =
11942 Self::take_text_document_sync_options(capabilities);
11943 sync_options.change = Some(sync_kind);
11944 capabilities.text_document_sync =
11945 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11946 });
11947 notify_server_capabilities_updated(&server, cx);
11948 }
11949 }
11950 "textDocument/didSave" => {
11951 if let Some(include_text) = reg
11952 .register_options
11953 .map(|opts| {
11954 let transpose = opts
11955 .get("includeText")
11956 .cloned()
11957 .map(serde_json::from_value::<Option<bool>>)
11958 .transpose();
11959 match transpose {
11960 Ok(value) => Ok(value.flatten()),
11961 Err(e) => Err(e),
11962 }
11963 })
11964 .transpose()?
11965 {
11966 server.update_capabilities(|capabilities| {
11967 let mut sync_options =
11968 Self::take_text_document_sync_options(capabilities);
11969 sync_options.save =
11970 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
11971 include_text,
11972 }));
11973 capabilities.text_document_sync =
11974 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
11975 });
11976 notify_server_capabilities_updated(&server, cx);
11977 }
11978 }
11979 "textDocument/codeLens" => {
11980 if let Some(caps) = reg
11981 .register_options
11982 .map(serde_json::from_value)
11983 .transpose()?
11984 {
11985 server.update_capabilities(|capabilities| {
11986 capabilities.code_lens_provider = Some(caps);
11987 });
11988 notify_server_capabilities_updated(&server, cx);
11989 }
11990 }
11991 "textDocument/diagnostic" => {
11992 if let Some(caps) = reg
11993 .register_options
11994 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
11995 .transpose()?
11996 {
11997 let local = self
11998 .as_local_mut()
11999 .context("Expected LSP Store to be local")?;
12000 let state = local
12001 .language_servers
12002 .get_mut(&server_id)
12003 .context("Could not obtain Language Servers state")?;
12004 local
12005 .language_server_dynamic_registrations
12006 .get_mut(&server_id)
12007 .and_then(|registrations| {
12008 registrations
12009 .diagnostics
12010 .insert(Some(reg.id.clone()), caps.clone())
12011 });
12012
12013 let mut can_now_provide_diagnostics = false;
12014 if let LanguageServerState::Running {
12015 workspace_diagnostics_refresh_tasks,
12016 ..
12017 } = state
12018 && let Some(task) = lsp_workspace_diagnostics_refresh(
12019 Some(reg.id.clone()),
12020 caps.clone(),
12021 server.clone(),
12022 cx,
12023 )
12024 {
12025 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12026 can_now_provide_diagnostics = true;
12027 }
12028
12029 // We don't actually care about capabilities.diagnostic_provider, but it IS relevant for the remote peer
12030 // to know that there's at least one provider. Otherwise, it will never ask us to issue documentdiagnostic calls on their behalf,
12031 // as it'll think that they're not supported.
12032 if can_now_provide_diagnostics {
12033 server.update_capabilities(|capabilities| {
12034 debug_assert!(capabilities.diagnostic_provider.is_none());
12035 capabilities.diagnostic_provider = Some(caps);
12036 });
12037 }
12038
12039 notify_server_capabilities_updated(&server, cx);
12040 }
12041 }
12042 "textDocument/documentColor" => {
12043 let options = parse_register_capabilities(reg)?;
12044 let provider = match options {
12045 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12046 OneOf::Right(caps) => caps,
12047 };
12048 server.update_capabilities(|capabilities| {
12049 capabilities.color_provider = Some(provider);
12050 });
12051 notify_server_capabilities_updated(&server, cx);
12052 }
12053 _ => log::warn!("unhandled capability registration: {reg:?}"),
12054 }
12055 }
12056
12057 Ok(())
12058 }
12059
12060 fn unregister_server_capabilities(
12061 &mut self,
12062 server_id: LanguageServerId,
12063 params: lsp::UnregistrationParams,
12064 cx: &mut Context<Self>,
12065 ) -> anyhow::Result<()> {
12066 let server = self
12067 .language_server_for_id(server_id)
12068 .with_context(|| format!("no server {server_id} found"))?;
12069 for unreg in params.unregisterations.iter() {
12070 match unreg.method.as_str() {
12071 "workspace/didChangeWatchedFiles" => {
12072 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12073 local_lsp_store
12074 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12075 true
12076 } else {
12077 false
12078 };
12079 if notify {
12080 notify_server_capabilities_updated(&server, cx);
12081 }
12082 }
12083 "workspace/didChangeConfiguration" => {
12084 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12085 }
12086 "workspace/didChangeWorkspaceFolders" => {
12087 server.update_capabilities(|capabilities| {
12088 capabilities
12089 .workspace
12090 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12091 workspace_folders: None,
12092 file_operations: None,
12093 })
12094 .workspace_folders = None;
12095 });
12096 notify_server_capabilities_updated(&server, cx);
12097 }
12098 "workspace/symbol" => {
12099 server.update_capabilities(|capabilities| {
12100 capabilities.workspace_symbol_provider = None
12101 });
12102 notify_server_capabilities_updated(&server, cx);
12103 }
12104 "workspace/fileOperations" => {
12105 server.update_capabilities(|capabilities| {
12106 capabilities
12107 .workspace
12108 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12109 workspace_folders: None,
12110 file_operations: None,
12111 })
12112 .file_operations = None;
12113 });
12114 notify_server_capabilities_updated(&server, cx);
12115 }
12116 "workspace/executeCommand" => {
12117 server.update_capabilities(|capabilities| {
12118 capabilities.execute_command_provider = None;
12119 });
12120 notify_server_capabilities_updated(&server, cx);
12121 }
12122 "textDocument/rangeFormatting" => {
12123 server.update_capabilities(|capabilities| {
12124 capabilities.document_range_formatting_provider = None
12125 });
12126 notify_server_capabilities_updated(&server, cx);
12127 }
12128 "textDocument/onTypeFormatting" => {
12129 server.update_capabilities(|capabilities| {
12130 capabilities.document_on_type_formatting_provider = None;
12131 });
12132 notify_server_capabilities_updated(&server, cx);
12133 }
12134 "textDocument/formatting" => {
12135 server.update_capabilities(|capabilities| {
12136 capabilities.document_formatting_provider = None;
12137 });
12138 notify_server_capabilities_updated(&server, cx);
12139 }
12140 "textDocument/rename" => {
12141 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12142 notify_server_capabilities_updated(&server, cx);
12143 }
12144 "textDocument/codeAction" => {
12145 server.update_capabilities(|capabilities| {
12146 capabilities.code_action_provider = None;
12147 });
12148 notify_server_capabilities_updated(&server, cx);
12149 }
12150 "textDocument/definition" => {
12151 server.update_capabilities(|capabilities| {
12152 capabilities.definition_provider = None;
12153 });
12154 notify_server_capabilities_updated(&server, cx);
12155 }
12156 "textDocument/completion" => {
12157 server.update_capabilities(|capabilities| {
12158 capabilities.completion_provider = None;
12159 });
12160 notify_server_capabilities_updated(&server, cx);
12161 }
12162 "textDocument/hover" => {
12163 server.update_capabilities(|capabilities| {
12164 capabilities.hover_provider = None;
12165 });
12166 notify_server_capabilities_updated(&server, cx);
12167 }
12168 "textDocument/signatureHelp" => {
12169 server.update_capabilities(|capabilities| {
12170 capabilities.signature_help_provider = None;
12171 });
12172 notify_server_capabilities_updated(&server, cx);
12173 }
12174 "textDocument/didChange" => {
12175 server.update_capabilities(|capabilities| {
12176 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12177 sync_options.change = None;
12178 capabilities.text_document_sync =
12179 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12180 });
12181 notify_server_capabilities_updated(&server, cx);
12182 }
12183 "textDocument/didSave" => {
12184 server.update_capabilities(|capabilities| {
12185 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12186 sync_options.save = None;
12187 capabilities.text_document_sync =
12188 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12189 });
12190 notify_server_capabilities_updated(&server, cx);
12191 }
12192 "textDocument/codeLens" => {
12193 server.update_capabilities(|capabilities| {
12194 capabilities.code_lens_provider = None;
12195 });
12196 notify_server_capabilities_updated(&server, cx);
12197 }
12198 "textDocument/diagnostic" => {
12199 let local = self
12200 .as_local_mut()
12201 .context("Expected LSP Store to be local")?;
12202
12203 let state = local
12204 .language_servers
12205 .get_mut(&server_id)
12206 .context("Could not obtain Language Servers state")?;
12207 let options = local
12208 .language_server_dynamic_registrations
12209 .get_mut(&server_id)
12210 .with_context(|| {
12211 format!("Expected dynamic registration to exist for server {server_id}")
12212 })?.diagnostics
12213 .remove(&Some(unreg.id.clone()))
12214 .with_context(|| format!(
12215 "Attempted to unregister non-existent diagnostic registration with ID {}",
12216 unreg.id)
12217 )?;
12218
12219 let mut has_any_diagnostic_providers_still = true;
12220 if let Some(identifier) = diagnostic_identifier(&options)
12221 && let LanguageServerState::Running {
12222 workspace_diagnostics_refresh_tasks,
12223 ..
12224 } = state
12225 {
12226 workspace_diagnostics_refresh_tasks.remove(&identifier);
12227 has_any_diagnostic_providers_still =
12228 !workspace_diagnostics_refresh_tasks.is_empty();
12229 }
12230
12231 if !has_any_diagnostic_providers_still {
12232 server.update_capabilities(|capabilities| {
12233 debug_assert!(capabilities.diagnostic_provider.is_some());
12234 capabilities.diagnostic_provider = None;
12235 });
12236 }
12237
12238 notify_server_capabilities_updated(&server, cx);
12239 }
12240 "textDocument/documentColor" => {
12241 server.update_capabilities(|capabilities| {
12242 capabilities.color_provider = None;
12243 });
12244 notify_server_capabilities_updated(&server, cx);
12245 }
12246 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12247 }
12248 }
12249
12250 Ok(())
12251 }
12252
12253 async fn deduplicate_range_based_lsp_requests<T>(
12254 lsp_store: &Entity<Self>,
12255 server_id: Option<LanguageServerId>,
12256 lsp_request_id: LspRequestId,
12257 proto_request: &T::ProtoRequest,
12258 range: Range<Anchor>,
12259 cx: &mut AsyncApp,
12260 ) -> Result<()>
12261 where
12262 T: LspCommand,
12263 T::ProtoRequest: proto::LspRequestMessage,
12264 {
12265 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12266 let version = deserialize_version(proto_request.buffer_version());
12267 let buffer = lsp_store.update(cx, |this, cx| {
12268 this.buffer_store.read(cx).get_existing(buffer_id)
12269 })??;
12270 buffer
12271 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12272 .await?;
12273 lsp_store.update(cx, |lsp_store, cx| {
12274 let lsp_data = lsp_store
12275 .lsp_data
12276 .entry(buffer_id)
12277 .or_insert_with(|| BufferLspData::new(&buffer, cx));
12278 let chunks_queried_for = lsp_data
12279 .inlay_hints
12280 .applicable_chunks(&[range])
12281 .collect::<Vec<_>>();
12282 match chunks_queried_for.as_slice() {
12283 &[chunk] => {
12284 let key = LspKey {
12285 request_type: TypeId::of::<T>(),
12286 server_queried: server_id,
12287 };
12288 let previous_request = lsp_data
12289 .chunk_lsp_requests
12290 .entry(key)
12291 .or_default()
12292 .insert(chunk, lsp_request_id);
12293 if let Some((previous_request, running_requests)) =
12294 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12295 {
12296 running_requests.remove(&previous_request);
12297 }
12298 }
12299 _ambiguous_chunks => {
12300 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12301 // there, a buffer version-based check will be performed and outdated requests discarded.
12302 }
12303 }
12304 anyhow::Ok(())
12305 })??;
12306
12307 Ok(())
12308 }
12309
12310 async fn query_lsp_locally<T>(
12311 lsp_store: Entity<Self>,
12312 for_server_id: Option<LanguageServerId>,
12313 sender_id: proto::PeerId,
12314 lsp_request_id: LspRequestId,
12315 proto_request: T::ProtoRequest,
12316 position: Option<Anchor>,
12317 cx: &mut AsyncApp,
12318 ) -> Result<()>
12319 where
12320 T: LspCommand + Clone,
12321 T::ProtoRequest: proto::LspRequestMessage,
12322 <T::ProtoRequest as proto::RequestMessage>::Response:
12323 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12324 {
12325 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12326 let version = deserialize_version(proto_request.buffer_version());
12327 let buffer = lsp_store.update(cx, |this, cx| {
12328 this.buffer_store.read(cx).get_existing(buffer_id)
12329 })??;
12330 buffer
12331 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12332 .await?;
12333 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12334 let request =
12335 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12336 let key = LspKey {
12337 request_type: TypeId::of::<T>(),
12338 server_queried: for_server_id,
12339 };
12340 lsp_store.update(cx, |lsp_store, cx| {
12341 let request_task = match for_server_id {
12342 Some(server_id) => {
12343 let server_task = lsp_store.request_lsp(
12344 buffer.clone(),
12345 LanguageServerToQuery::Other(server_id),
12346 request.clone(),
12347 cx,
12348 );
12349 cx.background_spawn(async move {
12350 let mut responses = Vec::new();
12351 match server_task.await {
12352 Ok(response) => responses.push((server_id, response)),
12353 Err(e) => log::error!(
12354 "Error handling response for request {request:?}: {e:#}"
12355 ),
12356 }
12357 responses
12358 })
12359 }
12360 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12361 };
12362 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12363 if T::ProtoRequest::stop_previous_requests() {
12364 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12365 lsp_requests.clear();
12366 }
12367 }
12368 lsp_data.lsp_requests.entry(key).or_default().insert(
12369 lsp_request_id,
12370 cx.spawn(async move |lsp_store, cx| {
12371 let response = request_task.await;
12372 lsp_store
12373 .update(cx, |lsp_store, cx| {
12374 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12375 {
12376 let response = response
12377 .into_iter()
12378 .map(|(server_id, response)| {
12379 (
12380 server_id.to_proto(),
12381 T::response_to_proto(
12382 response,
12383 lsp_store,
12384 sender_id,
12385 &buffer_version,
12386 cx,
12387 )
12388 .into(),
12389 )
12390 })
12391 .collect::<HashMap<_, _>>();
12392 match client.send_lsp_response::<T::ProtoRequest>(
12393 project_id,
12394 lsp_request_id,
12395 response,
12396 ) {
12397 Ok(()) => {}
12398 Err(e) => {
12399 log::error!("Failed to send LSP response: {e:#}",)
12400 }
12401 }
12402 }
12403 })
12404 .ok();
12405 }),
12406 );
12407 })?;
12408 Ok(())
12409 }
12410
12411 fn take_text_document_sync_options(
12412 capabilities: &mut lsp::ServerCapabilities,
12413 ) -> lsp::TextDocumentSyncOptions {
12414 match capabilities.text_document_sync.take() {
12415 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12416 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12417 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12418 sync_options.change = Some(sync_kind);
12419 sync_options
12420 }
12421 None => lsp::TextDocumentSyncOptions::default(),
12422 }
12423 }
12424
12425 #[cfg(any(test, feature = "test-support"))]
12426 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12427 Some(
12428 self.lsp_data
12429 .get_mut(&buffer_id)?
12430 .code_lens
12431 .take()?
12432 .update
12433 .take()?
12434 .1,
12435 )
12436 }
12437
12438 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12439 self.downstream_client.clone()
12440 }
12441
12442 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12443 self.worktree_store.clone()
12444 }
12445
12446 /// Gets what's stored in the LSP data for the given buffer.
12447 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12448 self.lsp_data.get_mut(&buffer_id)
12449 }
12450
12451 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12452 /// new [`BufferLspData`] will be created to replace the previous state.
12453 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12454 let (buffer_id, buffer_version) =
12455 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12456 let lsp_data = self
12457 .lsp_data
12458 .entry(buffer_id)
12459 .or_insert_with(|| BufferLspData::new(buffer, cx));
12460 if buffer_version.changed_since(&lsp_data.buffer_version) {
12461 *lsp_data = BufferLspData::new(buffer, cx);
12462 }
12463 lsp_data
12464 }
12465}
12466
12467// Registration with registerOptions as null, should fallback to true.
12468// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12469fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12470 reg: lsp::Registration,
12471) -> Result<OneOf<bool, T>> {
12472 Ok(match reg.register_options {
12473 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
12474 None => OneOf::Left(true),
12475 })
12476}
12477
12478fn subscribe_to_binary_statuses(
12479 languages: &Arc<LanguageRegistry>,
12480 cx: &mut Context<'_, LspStore>,
12481) -> Task<()> {
12482 let mut server_statuses = languages.language_server_binary_statuses();
12483 cx.spawn(async move |lsp_store, cx| {
12484 while let Some((server_name, binary_status)) = server_statuses.next().await {
12485 if lsp_store
12486 .update(cx, |_, cx| {
12487 let mut message = None;
12488 let binary_status = match binary_status {
12489 BinaryStatus::None => proto::ServerBinaryStatus::None,
12490 BinaryStatus::CheckingForUpdate => {
12491 proto::ServerBinaryStatus::CheckingForUpdate
12492 }
12493 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
12494 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
12495 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
12496 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
12497 BinaryStatus::Failed { error } => {
12498 message = Some(error);
12499 proto::ServerBinaryStatus::Failed
12500 }
12501 };
12502 cx.emit(LspStoreEvent::LanguageServerUpdate {
12503 // Binary updates are about the binary that might not have any language server id at that point.
12504 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
12505 language_server_id: LanguageServerId(0),
12506 name: Some(server_name),
12507 message: proto::update_language_server::Variant::StatusUpdate(
12508 proto::StatusUpdate {
12509 message,
12510 status: Some(proto::status_update::Status::Binary(
12511 binary_status as i32,
12512 )),
12513 },
12514 ),
12515 });
12516 })
12517 .is_err()
12518 {
12519 break;
12520 }
12521 }
12522 })
12523}
12524
12525fn lsp_workspace_diagnostics_refresh(
12526 registration_id: Option<String>,
12527 options: DiagnosticServerCapabilities,
12528 server: Arc<LanguageServer>,
12529 cx: &mut Context<'_, LspStore>,
12530) -> Option<WorkspaceRefreshTask> {
12531 let identifier = diagnostic_identifier(&options)?;
12532
12533 let (progress_tx, mut progress_rx) = mpsc::channel(1);
12534 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
12535 refresh_tx.try_send(()).ok();
12536
12537 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
12538 let mut attempts = 0;
12539 let max_attempts = 50;
12540 let mut requests = 0;
12541
12542 loop {
12543 let Some(()) = refresh_rx.recv().await else {
12544 return;
12545 };
12546
12547 'request: loop {
12548 requests += 1;
12549 if attempts > max_attempts {
12550 log::error!(
12551 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
12552 );
12553 return;
12554 }
12555 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
12556 cx.background_executor()
12557 .timer(Duration::from_millis(backoff_millis))
12558 .await;
12559 attempts += 1;
12560
12561 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
12562 lsp_store
12563 .all_result_ids(server.server_id())
12564 .into_iter()
12565 .filter_map(|(abs_path, result_id)| {
12566 let uri = file_path_to_lsp_url(&abs_path).ok()?;
12567 Some(lsp::PreviousResultId {
12568 uri,
12569 value: result_id,
12570 })
12571 })
12572 .collect()
12573 }) else {
12574 return;
12575 };
12576
12577 let token = if let Some(identifier) = ®istration_id {
12578 format!(
12579 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{identifier}",
12580 server.server_id(),
12581 )
12582 } else {
12583 format!("workspace/diagnostic/{}/{requests}", server.server_id())
12584 };
12585
12586 progress_rx.try_recv().ok();
12587 let timer =
12588 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
12589 let progress = pin!(progress_rx.recv().fuse());
12590 let response_result = server
12591 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
12592 lsp::WorkspaceDiagnosticParams {
12593 previous_result_ids,
12594 identifier: identifier.clone(),
12595 work_done_progress_params: Default::default(),
12596 partial_result_params: lsp::PartialResultParams {
12597 partial_result_token: Some(lsp::ProgressToken::String(token)),
12598 },
12599 },
12600 select(timer, progress).then(|either| match either {
12601 Either::Left((message, ..)) => ready(message).left_future(),
12602 Either::Right(..) => pending::<String>().right_future(),
12603 }),
12604 )
12605 .await;
12606
12607 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
12608 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
12609 match response_result {
12610 ConnectionResult::Timeout => {
12611 log::error!("Timeout during workspace diagnostics pull");
12612 continue 'request;
12613 }
12614 ConnectionResult::ConnectionReset => {
12615 log::error!("Server closed a workspace diagnostics pull request");
12616 continue 'request;
12617 }
12618 ConnectionResult::Result(Err(e)) => {
12619 log::error!("Error during workspace diagnostics pull: {e:#}");
12620 break 'request;
12621 }
12622 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
12623 attempts = 0;
12624 if lsp_store
12625 .update(cx, |lsp_store, cx| {
12626 lsp_store.apply_workspace_diagnostic_report(
12627 server.server_id(),
12628 pulled_diagnostics,
12629 cx,
12630 )
12631 })
12632 .is_err()
12633 {
12634 return;
12635 }
12636 break 'request;
12637 }
12638 }
12639 }
12640 }
12641 });
12642
12643 Some(WorkspaceRefreshTask {
12644 refresh_tx,
12645 progress_tx,
12646 task: workspace_query_language_server,
12647 })
12648}
12649
12650fn diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<Option<String>> {
12651 match &options {
12652 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
12653 if !diagnostic_options.workspace_diagnostics {
12654 return None;
12655 }
12656 Some(diagnostic_options.identifier.clone())
12657 }
12658 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
12659 let diagnostic_options = ®istration_options.diagnostic_options;
12660 if !diagnostic_options.workspace_diagnostics {
12661 return None;
12662 }
12663 Some(diagnostic_options.identifier.clone())
12664 }
12665 }
12666}
12667
12668fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
12669 let CompletionSource::BufferWord {
12670 word_range,
12671 resolved,
12672 } = &mut completion.source
12673 else {
12674 return;
12675 };
12676 if *resolved {
12677 return;
12678 }
12679
12680 if completion.new_text
12681 != snapshot
12682 .text_for_range(word_range.clone())
12683 .collect::<String>()
12684 {
12685 return;
12686 }
12687
12688 let mut offset = 0;
12689 for chunk in snapshot.chunks(word_range.clone(), true) {
12690 let end_offset = offset + chunk.text.len();
12691 if let Some(highlight_id) = chunk.syntax_highlight_id {
12692 completion
12693 .label
12694 .runs
12695 .push((offset..end_offset, highlight_id));
12696 }
12697 offset = end_offset;
12698 }
12699 *resolved = true;
12700}
12701
12702impl EventEmitter<LspStoreEvent> for LspStore {}
12703
12704fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12705 hover
12706 .contents
12707 .retain(|hover_block| !hover_block.text.trim().is_empty());
12708 if hover.contents.is_empty() {
12709 None
12710 } else {
12711 Some(hover)
12712 }
12713}
12714
12715async fn populate_labels_for_completions(
12716 new_completions: Vec<CoreCompletion>,
12717 language: Option<Arc<Language>>,
12718 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12719) -> Vec<Completion> {
12720 let lsp_completions = new_completions
12721 .iter()
12722 .filter_map(|new_completion| {
12723 new_completion
12724 .source
12725 .lsp_completion(true)
12726 .map(|lsp_completion| lsp_completion.into_owned())
12727 })
12728 .collect::<Vec<_>>();
12729
12730 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12731 lsp_adapter
12732 .labels_for_completions(&lsp_completions, language)
12733 .await
12734 .log_err()
12735 .unwrap_or_default()
12736 } else {
12737 Vec::new()
12738 }
12739 .into_iter()
12740 .fuse();
12741
12742 let mut completions = Vec::new();
12743 for completion in new_completions {
12744 match completion.source.lsp_completion(true) {
12745 Some(lsp_completion) => {
12746 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
12747
12748 let mut label = labels.next().flatten().unwrap_or_else(|| {
12749 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12750 });
12751 ensure_uniform_list_compatible_label(&mut label);
12752 completions.push(Completion {
12753 label,
12754 documentation,
12755 replace_range: completion.replace_range,
12756 new_text: completion.new_text,
12757 insert_text_mode: lsp_completion.insert_text_mode,
12758 source: completion.source,
12759 icon_path: None,
12760 confirm: None,
12761 });
12762 }
12763 None => {
12764 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12765 ensure_uniform_list_compatible_label(&mut label);
12766 completions.push(Completion {
12767 label,
12768 documentation: None,
12769 replace_range: completion.replace_range,
12770 new_text: completion.new_text,
12771 source: completion.source,
12772 insert_text_mode: None,
12773 icon_path: None,
12774 confirm: None,
12775 });
12776 }
12777 }
12778 }
12779 completions
12780}
12781
12782#[derive(Debug)]
12783pub enum LanguageServerToQuery {
12784 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12785 FirstCapable,
12786 /// Query a specific language server.
12787 Other(LanguageServerId),
12788}
12789
12790#[derive(Default)]
12791struct RenamePathsWatchedForServer {
12792 did_rename: Vec<RenameActionPredicate>,
12793 will_rename: Vec<RenameActionPredicate>,
12794}
12795
12796impl RenamePathsWatchedForServer {
12797 fn with_did_rename_patterns(
12798 mut self,
12799 did_rename: Option<&FileOperationRegistrationOptions>,
12800 ) -> Self {
12801 if let Some(did_rename) = did_rename {
12802 self.did_rename = did_rename
12803 .filters
12804 .iter()
12805 .filter_map(|filter| filter.try_into().log_err())
12806 .collect();
12807 }
12808 self
12809 }
12810 fn with_will_rename_patterns(
12811 mut self,
12812 will_rename: Option<&FileOperationRegistrationOptions>,
12813 ) -> Self {
12814 if let Some(will_rename) = will_rename {
12815 self.will_rename = will_rename
12816 .filters
12817 .iter()
12818 .filter_map(|filter| filter.try_into().log_err())
12819 .collect();
12820 }
12821 self
12822 }
12823
12824 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12825 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12826 }
12827 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12828 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12829 }
12830}
12831
12832impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12833 type Error = globset::Error;
12834 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12835 Ok(Self {
12836 kind: ops.pattern.matches.clone(),
12837 glob: GlobBuilder::new(&ops.pattern.glob)
12838 .case_insensitive(
12839 ops.pattern
12840 .options
12841 .as_ref()
12842 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
12843 )
12844 .build()?
12845 .compile_matcher(),
12846 })
12847 }
12848}
12849struct RenameActionPredicate {
12850 glob: GlobMatcher,
12851 kind: Option<FileOperationPatternKind>,
12852}
12853
12854impl RenameActionPredicate {
12855 // Returns true if language server should be notified
12856 fn eval(&self, path: &str, is_dir: bool) -> bool {
12857 self.kind.as_ref().is_none_or(|kind| {
12858 let expected_kind = if is_dir {
12859 FileOperationPatternKind::Folder
12860 } else {
12861 FileOperationPatternKind::File
12862 };
12863 kind == &expected_kind
12864 }) && self.glob.is_match(path)
12865 }
12866}
12867
12868#[derive(Default)]
12869struct LanguageServerWatchedPaths {
12870 worktree_paths: HashMap<WorktreeId, GlobSet>,
12871 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12872}
12873
12874#[derive(Default)]
12875struct LanguageServerWatchedPathsBuilder {
12876 worktree_paths: HashMap<WorktreeId, GlobSet>,
12877 abs_paths: HashMap<Arc<Path>, GlobSet>,
12878}
12879
12880impl LanguageServerWatchedPathsBuilder {
12881 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12882 self.worktree_paths.insert(worktree_id, glob_set);
12883 }
12884 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12885 self.abs_paths.insert(path, glob_set);
12886 }
12887 fn build(
12888 self,
12889 fs: Arc<dyn Fs>,
12890 language_server_id: LanguageServerId,
12891 cx: &mut Context<LspStore>,
12892 ) -> LanguageServerWatchedPaths {
12893 let project = cx.weak_entity();
12894
12895 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12896 let abs_paths = self
12897 .abs_paths
12898 .into_iter()
12899 .map(|(abs_path, globset)| {
12900 let task = cx.spawn({
12901 let abs_path = abs_path.clone();
12902 let fs = fs.clone();
12903
12904 let lsp_store = project.clone();
12905 async move |_, cx| {
12906 maybe!(async move {
12907 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12908 while let Some(update) = push_updates.0.next().await {
12909 let action = lsp_store
12910 .update(cx, |this, _| {
12911 let Some(local) = this.as_local() else {
12912 return ControlFlow::Break(());
12913 };
12914 let Some(watcher) = local
12915 .language_server_watched_paths
12916 .get(&language_server_id)
12917 else {
12918 return ControlFlow::Break(());
12919 };
12920 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12921 "Watched abs path is not registered with a watcher",
12922 );
12923 let matching_entries = update
12924 .into_iter()
12925 .filter(|event| globs.is_match(&event.path))
12926 .collect::<Vec<_>>();
12927 this.lsp_notify_abs_paths_changed(
12928 language_server_id,
12929 matching_entries,
12930 );
12931 ControlFlow::Continue(())
12932 })
12933 .ok()?;
12934
12935 if action.is_break() {
12936 break;
12937 }
12938 }
12939 Some(())
12940 })
12941 .await;
12942 }
12943 });
12944 (abs_path, (globset, task))
12945 })
12946 .collect();
12947 LanguageServerWatchedPaths {
12948 worktree_paths: self.worktree_paths,
12949 abs_paths,
12950 }
12951 }
12952}
12953
12954struct LspBufferSnapshot {
12955 version: i32,
12956 snapshot: TextBufferSnapshot,
12957}
12958
12959/// A prompt requested by LSP server.
12960#[derive(Clone, Debug)]
12961pub struct LanguageServerPromptRequest {
12962 pub level: PromptLevel,
12963 pub message: String,
12964 pub actions: Vec<MessageActionItem>,
12965 pub lsp_name: String,
12966 pub(crate) response_channel: Sender<MessageActionItem>,
12967}
12968
12969impl LanguageServerPromptRequest {
12970 pub async fn respond(self, index: usize) -> Option<()> {
12971 if let Some(response) = self.actions.into_iter().nth(index) {
12972 self.response_channel.send(response).await.ok()
12973 } else {
12974 None
12975 }
12976 }
12977}
12978impl PartialEq for LanguageServerPromptRequest {
12979 fn eq(&self, other: &Self) -> bool {
12980 self.message == other.message && self.actions == other.actions
12981 }
12982}
12983
12984#[derive(Clone, Debug, PartialEq)]
12985pub enum LanguageServerLogType {
12986 Log(MessageType),
12987 Trace { verbose_info: Option<String> },
12988 Rpc { received: bool },
12989}
12990
12991impl LanguageServerLogType {
12992 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12993 match self {
12994 Self::Log(log_type) => {
12995 use proto::log_message::LogLevel;
12996 let level = match *log_type {
12997 MessageType::ERROR => LogLevel::Error,
12998 MessageType::WARNING => LogLevel::Warning,
12999 MessageType::INFO => LogLevel::Info,
13000 MessageType::LOG => LogLevel::Log,
13001 other => {
13002 log::warn!("Unknown lsp log message type: {other:?}");
13003 LogLevel::Log
13004 }
13005 };
13006 proto::language_server_log::LogType::Log(proto::LogMessage {
13007 level: level as i32,
13008 })
13009 }
13010 Self::Trace { verbose_info } => {
13011 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13012 verbose_info: verbose_info.to_owned(),
13013 })
13014 }
13015 Self::Rpc { received } => {
13016 let kind = if *received {
13017 proto::rpc_message::Kind::Received
13018 } else {
13019 proto::rpc_message::Kind::Sent
13020 };
13021 let kind = kind as i32;
13022 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13023 }
13024 }
13025 }
13026
13027 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13028 use proto::log_message::LogLevel;
13029 use proto::rpc_message;
13030 match log_type {
13031 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13032 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13033 LogLevel::Error => MessageType::ERROR,
13034 LogLevel::Warning => MessageType::WARNING,
13035 LogLevel::Info => MessageType::INFO,
13036 LogLevel::Log => MessageType::LOG,
13037 },
13038 ),
13039 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13040 verbose_info: trace_message.verbose_info,
13041 },
13042 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13043 received: match rpc_message::Kind::from_i32(message.kind)
13044 .unwrap_or(rpc_message::Kind::Received)
13045 {
13046 rpc_message::Kind::Received => true,
13047 rpc_message::Kind::Sent => false,
13048 },
13049 },
13050 }
13051 }
13052}
13053
13054pub struct WorkspaceRefreshTask {
13055 refresh_tx: mpsc::Sender<()>,
13056 progress_tx: mpsc::Sender<()>,
13057 #[allow(dead_code)]
13058 task: Task<()>,
13059}
13060
13061pub enum LanguageServerState {
13062 Starting {
13063 startup: Task<Option<Arc<LanguageServer>>>,
13064 /// List of language servers that will be added to the workspace once it's initialization completes.
13065 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13066 },
13067
13068 Running {
13069 adapter: Arc<CachedLspAdapter>,
13070 server: Arc<LanguageServer>,
13071 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13072 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13073 },
13074}
13075
13076impl LanguageServerState {
13077 fn add_workspace_folder(&self, uri: Uri) {
13078 match self {
13079 LanguageServerState::Starting {
13080 pending_workspace_folders,
13081 ..
13082 } => {
13083 pending_workspace_folders.lock().insert(uri);
13084 }
13085 LanguageServerState::Running { server, .. } => {
13086 server.add_workspace_folder(uri);
13087 }
13088 }
13089 }
13090 fn _remove_workspace_folder(&self, uri: Uri) {
13091 match self {
13092 LanguageServerState::Starting {
13093 pending_workspace_folders,
13094 ..
13095 } => {
13096 pending_workspace_folders.lock().remove(&uri);
13097 }
13098 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13099 }
13100 }
13101}
13102
13103impl std::fmt::Debug for LanguageServerState {
13104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13105 match self {
13106 LanguageServerState::Starting { .. } => {
13107 f.debug_struct("LanguageServerState::Starting").finish()
13108 }
13109 LanguageServerState::Running { .. } => {
13110 f.debug_struct("LanguageServerState::Running").finish()
13111 }
13112 }
13113 }
13114}
13115
13116#[derive(Clone, Debug, Serialize)]
13117pub struct LanguageServerProgress {
13118 pub is_disk_based_diagnostics_progress: bool,
13119 pub is_cancellable: bool,
13120 pub title: Option<String>,
13121 pub message: Option<String>,
13122 pub percentage: Option<usize>,
13123 #[serde(skip_serializing)]
13124 pub last_update_at: Instant,
13125}
13126
13127#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13128pub struct DiagnosticSummary {
13129 pub error_count: usize,
13130 pub warning_count: usize,
13131}
13132
13133impl DiagnosticSummary {
13134 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13135 let mut this = Self {
13136 error_count: 0,
13137 warning_count: 0,
13138 };
13139
13140 for entry in diagnostics {
13141 if entry.diagnostic.is_primary {
13142 match entry.diagnostic.severity {
13143 DiagnosticSeverity::ERROR => this.error_count += 1,
13144 DiagnosticSeverity::WARNING => this.warning_count += 1,
13145 _ => {}
13146 }
13147 }
13148 }
13149
13150 this
13151 }
13152
13153 pub fn is_empty(&self) -> bool {
13154 self.error_count == 0 && self.warning_count == 0
13155 }
13156
13157 pub fn to_proto(
13158 self,
13159 language_server_id: LanguageServerId,
13160 path: &RelPath,
13161 ) -> proto::DiagnosticSummary {
13162 proto::DiagnosticSummary {
13163 path: path.to_proto(),
13164 language_server_id: language_server_id.0 as u64,
13165 error_count: self.error_count as u32,
13166 warning_count: self.warning_count as u32,
13167 }
13168 }
13169}
13170
13171#[derive(Clone, Debug)]
13172pub enum CompletionDocumentation {
13173 /// There is no documentation for this completion.
13174 Undocumented,
13175 /// A single line of documentation.
13176 SingleLine(SharedString),
13177 /// Multiple lines of plain text documentation.
13178 MultiLinePlainText(SharedString),
13179 /// Markdown documentation.
13180 MultiLineMarkdown(SharedString),
13181 /// Both single line and multiple lines of plain text documentation.
13182 SingleLineAndMultiLinePlainText {
13183 single_line: SharedString,
13184 plain_text: Option<SharedString>,
13185 },
13186}
13187
13188impl CompletionDocumentation {
13189 #[cfg(any(test, feature = "test-support"))]
13190 pub fn text(&self) -> SharedString {
13191 match self {
13192 CompletionDocumentation::Undocumented => "".into(),
13193 CompletionDocumentation::SingleLine(s) => s.clone(),
13194 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13195 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13196 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13197 single_line.clone()
13198 }
13199 }
13200 }
13201}
13202
13203impl From<lsp::Documentation> for CompletionDocumentation {
13204 fn from(docs: lsp::Documentation) -> Self {
13205 match docs {
13206 lsp::Documentation::String(text) => {
13207 if text.lines().count() <= 1 {
13208 CompletionDocumentation::SingleLine(text.into())
13209 } else {
13210 CompletionDocumentation::MultiLinePlainText(text.into())
13211 }
13212 }
13213
13214 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13215 lsp::MarkupKind::PlainText => {
13216 if value.lines().count() <= 1 {
13217 CompletionDocumentation::SingleLine(value.into())
13218 } else {
13219 CompletionDocumentation::MultiLinePlainText(value.into())
13220 }
13221 }
13222
13223 lsp::MarkupKind::Markdown => {
13224 CompletionDocumentation::MultiLineMarkdown(value.into())
13225 }
13226 },
13227 }
13228 }
13229}
13230
13231pub enum ResolvedHint {
13232 Resolved(InlayHint),
13233 Resolving(Shared<Task<()>>),
13234}
13235
13236fn glob_literal_prefix(glob: &Path) -> PathBuf {
13237 glob.components()
13238 .take_while(|component| match component {
13239 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13240 _ => true,
13241 })
13242 .collect()
13243}
13244
13245pub struct SshLspAdapter {
13246 name: LanguageServerName,
13247 binary: LanguageServerBinary,
13248 initialization_options: Option<String>,
13249 code_action_kinds: Option<Vec<CodeActionKind>>,
13250}
13251
13252impl SshLspAdapter {
13253 pub fn new(
13254 name: LanguageServerName,
13255 binary: LanguageServerBinary,
13256 initialization_options: Option<String>,
13257 code_action_kinds: Option<String>,
13258 ) -> Self {
13259 Self {
13260 name,
13261 binary,
13262 initialization_options,
13263 code_action_kinds: code_action_kinds
13264 .as_ref()
13265 .and_then(|c| serde_json::from_str(c).ok()),
13266 }
13267 }
13268}
13269
13270impl LspInstaller for SshLspAdapter {
13271 type BinaryVersion = ();
13272 async fn check_if_user_installed(
13273 &self,
13274 _: &dyn LspAdapterDelegate,
13275 _: Option<Toolchain>,
13276 _: &AsyncApp,
13277 ) -> Option<LanguageServerBinary> {
13278 Some(self.binary.clone())
13279 }
13280
13281 async fn cached_server_binary(
13282 &self,
13283 _: PathBuf,
13284 _: &dyn LspAdapterDelegate,
13285 ) -> Option<LanguageServerBinary> {
13286 None
13287 }
13288
13289 async fn fetch_latest_server_version(
13290 &self,
13291 _: &dyn LspAdapterDelegate,
13292 _: bool,
13293 _: &mut AsyncApp,
13294 ) -> Result<()> {
13295 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13296 }
13297
13298 async fn fetch_server_binary(
13299 &self,
13300 _: (),
13301 _: PathBuf,
13302 _: &dyn LspAdapterDelegate,
13303 ) -> Result<LanguageServerBinary> {
13304 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13305 }
13306}
13307
13308#[async_trait(?Send)]
13309impl LspAdapter for SshLspAdapter {
13310 fn name(&self) -> LanguageServerName {
13311 self.name.clone()
13312 }
13313
13314 async fn initialization_options(
13315 self: Arc<Self>,
13316 _: &Arc<dyn LspAdapterDelegate>,
13317 ) -> Result<Option<serde_json::Value>> {
13318 let Some(options) = &self.initialization_options else {
13319 return Ok(None);
13320 };
13321 let result = serde_json::from_str(options)?;
13322 Ok(result)
13323 }
13324
13325 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13326 self.code_action_kinds.clone()
13327 }
13328}
13329
13330pub fn language_server_settings<'a>(
13331 delegate: &'a dyn LspAdapterDelegate,
13332 language: &LanguageServerName,
13333 cx: &'a App,
13334) -> Option<&'a LspSettings> {
13335 language_server_settings_for(
13336 SettingsLocation {
13337 worktree_id: delegate.worktree_id(),
13338 path: RelPath::empty(),
13339 },
13340 language,
13341 cx,
13342 )
13343}
13344
13345pub(crate) fn language_server_settings_for<'a>(
13346 location: SettingsLocation<'a>,
13347 language: &LanguageServerName,
13348 cx: &'a App,
13349) -> Option<&'a LspSettings> {
13350 ProjectSettings::get(Some(location), cx).lsp.get(language)
13351}
13352
13353pub struct LocalLspAdapterDelegate {
13354 lsp_store: WeakEntity<LspStore>,
13355 worktree: worktree::Snapshot,
13356 fs: Arc<dyn Fs>,
13357 http_client: Arc<dyn HttpClient>,
13358 language_registry: Arc<LanguageRegistry>,
13359 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13360}
13361
13362impl LocalLspAdapterDelegate {
13363 pub fn new(
13364 language_registry: Arc<LanguageRegistry>,
13365 environment: &Entity<ProjectEnvironment>,
13366 lsp_store: WeakEntity<LspStore>,
13367 worktree: &Entity<Worktree>,
13368 http_client: Arc<dyn HttpClient>,
13369 fs: Arc<dyn Fs>,
13370 cx: &mut App,
13371 ) -> Arc<Self> {
13372 let load_shell_env_task = environment.update(cx, |env, cx| {
13373 env.get_worktree_environment(worktree.clone(), cx)
13374 });
13375
13376 Arc::new(Self {
13377 lsp_store,
13378 worktree: worktree.read(cx).snapshot(),
13379 fs,
13380 http_client,
13381 language_registry,
13382 load_shell_env_task,
13383 })
13384 }
13385
13386 fn from_local_lsp(
13387 local: &LocalLspStore,
13388 worktree: &Entity<Worktree>,
13389 cx: &mut App,
13390 ) -> Arc<Self> {
13391 Self::new(
13392 local.languages.clone(),
13393 &local.environment,
13394 local.weak.clone(),
13395 worktree,
13396 local.http_client.clone(),
13397 local.fs.clone(),
13398 cx,
13399 )
13400 }
13401}
13402
13403#[async_trait]
13404impl LspAdapterDelegate for LocalLspAdapterDelegate {
13405 fn show_notification(&self, message: &str, cx: &mut App) {
13406 self.lsp_store
13407 .update(cx, |_, cx| {
13408 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13409 })
13410 .ok();
13411 }
13412
13413 fn http_client(&self) -> Arc<dyn HttpClient> {
13414 self.http_client.clone()
13415 }
13416
13417 fn worktree_id(&self) -> WorktreeId {
13418 self.worktree.id()
13419 }
13420
13421 fn worktree_root_path(&self) -> &Path {
13422 self.worktree.abs_path().as_ref()
13423 }
13424
13425 async fn shell_env(&self) -> HashMap<String, String> {
13426 let task = self.load_shell_env_task.clone();
13427 task.await.unwrap_or_default()
13428 }
13429
13430 async fn npm_package_installed_version(
13431 &self,
13432 package_name: &str,
13433 ) -> Result<Option<(PathBuf, String)>> {
13434 let local_package_directory = self.worktree_root_path();
13435 let node_modules_directory = local_package_directory.join("node_modules");
13436
13437 if let Some(version) =
13438 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13439 {
13440 return Ok(Some((node_modules_directory, version)));
13441 }
13442 let Some(npm) = self.which("npm".as_ref()).await else {
13443 log::warn!(
13444 "Failed to find npm executable for {:?}",
13445 local_package_directory
13446 );
13447 return Ok(None);
13448 };
13449
13450 let env = self.shell_env().await;
13451 let output = util::command::new_smol_command(&npm)
13452 .args(["root", "-g"])
13453 .envs(env)
13454 .current_dir(local_package_directory)
13455 .output()
13456 .await?;
13457 let global_node_modules =
13458 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
13459
13460 if let Some(version) =
13461 read_package_installed_version(global_node_modules.clone(), package_name).await?
13462 {
13463 return Ok(Some((global_node_modules, version)));
13464 }
13465 return Ok(None);
13466 }
13467
13468 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
13469 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
13470 if self.fs.is_file(&worktree_abs_path).await {
13471 worktree_abs_path.pop();
13472 }
13473
13474 let env = self.shell_env().await;
13475
13476 let shell_path = env.get("PATH").cloned();
13477
13478 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
13479 }
13480
13481 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
13482 let mut working_dir = self.worktree_root_path().to_path_buf();
13483 if self.fs.is_file(&working_dir).await {
13484 working_dir.pop();
13485 }
13486 let output = util::command::new_smol_command(&command.path)
13487 .args(command.arguments)
13488 .envs(command.env.clone().unwrap_or_default())
13489 .current_dir(working_dir)
13490 .output()
13491 .await?;
13492
13493 anyhow::ensure!(
13494 output.status.success(),
13495 "{}, stdout: {:?}, stderr: {:?}",
13496 output.status,
13497 String::from_utf8_lossy(&output.stdout),
13498 String::from_utf8_lossy(&output.stderr)
13499 );
13500 Ok(())
13501 }
13502
13503 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
13504 self.language_registry
13505 .update_lsp_binary_status(server_name, status);
13506 }
13507
13508 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
13509 self.language_registry
13510 .all_lsp_adapters()
13511 .into_iter()
13512 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
13513 .collect()
13514 }
13515
13516 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
13517 let dir = self.language_registry.language_server_download_dir(name)?;
13518
13519 if !dir.exists() {
13520 smol::fs::create_dir_all(&dir)
13521 .await
13522 .context("failed to create container directory")
13523 .log_err()?;
13524 }
13525
13526 Some(dir)
13527 }
13528
13529 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
13530 let entry = self
13531 .worktree
13532 .entry_for_path(path)
13533 .with_context(|| format!("no worktree entry for path {path:?}"))?;
13534 let abs_path = self.worktree.absolutize(&entry.path);
13535 self.fs.load(&abs_path).await
13536 }
13537}
13538
13539async fn populate_labels_for_symbols(
13540 symbols: Vec<CoreSymbol>,
13541 language_registry: &Arc<LanguageRegistry>,
13542 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13543 output: &mut Vec<Symbol>,
13544) {
13545 #[allow(clippy::mutable_key_type)]
13546 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
13547
13548 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
13549 for symbol in symbols {
13550 let Some(file_name) = symbol.path.file_name() else {
13551 continue;
13552 };
13553 let language = language_registry
13554 .load_language_for_file_path(Path::new(file_name))
13555 .await
13556 .ok()
13557 .or_else(|| {
13558 unknown_paths.insert(file_name.into());
13559 None
13560 });
13561 symbols_by_language
13562 .entry(language)
13563 .or_default()
13564 .push(symbol);
13565 }
13566
13567 for unknown_path in unknown_paths {
13568 log::info!("no language found for symbol in file {unknown_path:?}");
13569 }
13570
13571 let mut label_params = Vec::new();
13572 for (language, mut symbols) in symbols_by_language {
13573 label_params.clear();
13574 label_params.extend(
13575 symbols
13576 .iter_mut()
13577 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
13578 );
13579
13580 let mut labels = Vec::new();
13581 if let Some(language) = language {
13582 let lsp_adapter = lsp_adapter.clone().or_else(|| {
13583 language_registry
13584 .lsp_adapters(&language.name())
13585 .first()
13586 .cloned()
13587 });
13588 if let Some(lsp_adapter) = lsp_adapter {
13589 labels = lsp_adapter
13590 .labels_for_symbols(&label_params, &language)
13591 .await
13592 .log_err()
13593 .unwrap_or_default();
13594 }
13595 }
13596
13597 for ((symbol, (name, _)), label) in symbols
13598 .into_iter()
13599 .zip(label_params.drain(..))
13600 .zip(labels.into_iter().chain(iter::repeat(None)))
13601 {
13602 output.push(Symbol {
13603 language_server_name: symbol.language_server_name,
13604 source_worktree_id: symbol.source_worktree_id,
13605 source_language_server_id: symbol.source_language_server_id,
13606 path: symbol.path,
13607 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
13608 name,
13609 kind: symbol.kind,
13610 range: symbol.range,
13611 });
13612 }
13613 }
13614}
13615
13616fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
13617 match server.capabilities().text_document_sync.as_ref()? {
13618 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
13619 // Server wants didSave but didn't specify includeText.
13620 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
13621 // Server doesn't want didSave at all.
13622 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
13623 // Server provided SaveOptions.
13624 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
13625 Some(save_options.include_text.unwrap_or(false))
13626 }
13627 },
13628 // We do not have any save info. Kind affects didChange only.
13629 lsp::TextDocumentSyncCapability::Kind(_) => None,
13630 }
13631}
13632
13633/// Completion items are displayed in a `UniformList`.
13634/// Usually, those items are single-line strings, but in LSP responses,
13635/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
13636/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
13637/// 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,
13638/// breaking the completions menu presentation.
13639///
13640/// 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.
13641fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
13642 let mut new_text = String::with_capacity(label.text.len());
13643 let mut offset_map = vec![0; label.text.len() + 1];
13644 let mut last_char_was_space = false;
13645 let mut new_idx = 0;
13646 let chars = label.text.char_indices().fuse();
13647 let mut newlines_removed = false;
13648
13649 for (idx, c) in chars {
13650 offset_map[idx] = new_idx;
13651
13652 match c {
13653 '\n' if last_char_was_space => {
13654 newlines_removed = true;
13655 }
13656 '\t' | ' ' if last_char_was_space => {}
13657 '\n' if !last_char_was_space => {
13658 new_text.push(' ');
13659 new_idx += 1;
13660 last_char_was_space = true;
13661 newlines_removed = true;
13662 }
13663 ' ' | '\t' => {
13664 new_text.push(' ');
13665 new_idx += 1;
13666 last_char_was_space = true;
13667 }
13668 _ => {
13669 new_text.push(c);
13670 new_idx += c.len_utf8();
13671 last_char_was_space = false;
13672 }
13673 }
13674 }
13675 offset_map[label.text.len()] = new_idx;
13676
13677 // Only modify the label if newlines were removed.
13678 if !newlines_removed {
13679 return;
13680 }
13681
13682 let last_index = new_idx;
13683 let mut run_ranges_errors = Vec::new();
13684 label.runs.retain_mut(|(range, _)| {
13685 match offset_map.get(range.start) {
13686 Some(&start) => range.start = start,
13687 None => {
13688 run_ranges_errors.push(range.clone());
13689 return false;
13690 }
13691 }
13692
13693 match offset_map.get(range.end) {
13694 Some(&end) => range.end = end,
13695 None => {
13696 run_ranges_errors.push(range.clone());
13697 range.end = last_index;
13698 }
13699 }
13700 true
13701 });
13702 if !run_ranges_errors.is_empty() {
13703 log::error!(
13704 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
13705 label.text
13706 );
13707 }
13708
13709 let mut wrong_filter_range = None;
13710 if label.filter_range == (0..label.text.len()) {
13711 label.filter_range = 0..new_text.len();
13712 } else {
13713 let mut original_filter_range = Some(label.filter_range.clone());
13714 match offset_map.get(label.filter_range.start) {
13715 Some(&start) => label.filter_range.start = start,
13716 None => {
13717 wrong_filter_range = original_filter_range.take();
13718 label.filter_range.start = last_index;
13719 }
13720 }
13721
13722 match offset_map.get(label.filter_range.end) {
13723 Some(&end) => label.filter_range.end = end,
13724 None => {
13725 wrong_filter_range = original_filter_range.take();
13726 label.filter_range.end = last_index;
13727 }
13728 }
13729 }
13730 if let Some(wrong_filter_range) = wrong_filter_range {
13731 log::error!(
13732 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13733 label.text
13734 );
13735 }
13736
13737 label.text = new_text;
13738}
13739
13740#[cfg(test)]
13741mod tests {
13742 use language::HighlightId;
13743
13744 use super::*;
13745
13746 #[test]
13747 fn test_glob_literal_prefix() {
13748 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13749 assert_eq!(
13750 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13751 Path::new("node_modules")
13752 );
13753 assert_eq!(
13754 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13755 Path::new("foo")
13756 );
13757 assert_eq!(
13758 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13759 Path::new("foo/bar/baz.js")
13760 );
13761
13762 #[cfg(target_os = "windows")]
13763 {
13764 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13765 assert_eq!(
13766 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13767 Path::new("node_modules")
13768 );
13769 assert_eq!(
13770 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13771 Path::new("foo")
13772 );
13773 assert_eq!(
13774 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13775 Path::new("foo/bar/baz.js")
13776 );
13777 }
13778 }
13779
13780 #[test]
13781 fn test_multi_len_chars_normalization() {
13782 let mut label = CodeLabel::new(
13783 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13784 0..6,
13785 vec![(0..6, HighlightId(1))],
13786 );
13787 ensure_uniform_list_compatible_label(&mut label);
13788 assert_eq!(
13789 label,
13790 CodeLabel::new(
13791 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13792 0..6,
13793 vec![(0..6, HighlightId(1))],
13794 )
13795 );
13796 }
13797}