1use crate::disk_cache::DiskDiagnosticsCacheSessionV0;
2use crate::lsp_output::DiagnosticsPublishDigestRegistryV0;
3use crate::workspace_runtime_registry::WorkspaceRuntimeRegistry;
4use omena_incremental::IncrementalCancellationRegistryV0;
5#[cfg(feature = "salsa-style-diagnostics")]
6use omena_query::ReverseDependencyIndexV0;
7use omena_query::{
8 AnalyzedGraphV0, OmenaQueryExternalSifInputV0, OmenaQuerySourceSelectorOccurrenceIndexV0,
9 OmenaQuerySourceSelectorReferenceFactV0 as SourceSelectorReferenceFact,
10 OmenaQuerySourceSyntaxIndexV0 as SourceSyntaxIndex,
11 OmenaQuerySourceTypeFactLexicalAttemptV0 as SourceTypeFactLexicalAttempt,
12 OmenaQueryStyleCascadeNarrowingSubstrateV0, OmenaQueryStylePackageManifestV0,
13 OmenaQueryStyleResolutionInputsV0, OmenaQueryStyleSelectorDefinitionV0,
14 OmenaQueryStyleSourceInputV0, OmenaWorkspaceOccurrenceFamilyV0,
15 OmenaWorkspaceOccurrenceIndexV0, OmenaWorkspaceOccurrenceKindV0,
16 OmenaWorkspaceOccurrenceRoleV0, OmenaWorkspaceOccurrenceV0, ParserPositionV0, ParserRangeV0,
17};
18#[cfg(feature = "parallel-style-diagnostics")]
19use omena_query::{
20 OmenaResolverStyleModuleConfirmationIdentityIndexV0,
21 OmenaResolverStyleModuleDiskCandidateIdentityV0,
22};
23use omena_syntax::ident::{
24 AuthoredPropertyTextV0, CanonicalClassKeyV0, CanonicalCustomPropertyNameV0, PropertyNameV0,
25};
26use omena_tsgo_client::{TsgoTypeFactResultEntryV0, TsgoWorkspaceProcessPoolV0};
27use serde::Serialize;
28use std::cell::RefCell;
29use std::cmp::Ordering as CmpOrdering;
30use std::collections::{BTreeMap, BTreeSet};
31use std::path::PathBuf;
32use std::sync::{
33 Arc, Mutex, MutexGuard,
34 atomic::{AtomicU8, AtomicU64, Ordering},
35};
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
38#[serde(rename_all = "camelCase")]
39pub enum LspDocumentOrigin {
40 Local,
41 Foreign,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
45#[serde(rename_all = "camelCase")]
46pub struct LspTextDocumentState {
47 pub uri: String,
48 #[serde(skip)]
49 pub origin: LspDocumentOrigin,
50 pub workspace_folder_uri: Option<String>,
51 pub language_id: String,
52 pub version: i64,
53 pub text: String,
54 #[serde(skip)]
55 pub(crate) text_hash: String,
56 pub style_summary: Option<LspStyleDocumentSummary>,
57 pub diagnostics_schedule_count: usize,
58 pub optimizing_tier_feedback: Option<LspOptimizingTierFeedback>,
59 #[serde(skip)]
60 pub style_candidates: Vec<LspStyleHoverCandidate>,
61 #[serde(skip)]
62 pub(crate) source_syntax_index: SourceSyntaxIndex,
63 #[serde(skip)]
64 pub(crate) source_module_specifiers: Vec<String>,
65 #[serde(skip)]
66 pub(crate) source_module_specifier_index_complete: bool,
67 #[serde(skip)]
68 pub(crate) source_type_fact_lexical_attempts: Vec<SourceTypeFactLexicalAttempt>,
69 #[serde(skip)]
70 pub(crate) source_type_fact_tier_attempts: Vec<LspSourceTypeFactTierAttemptV0>,
71 #[serde(skip)]
72 pub(crate) has_unresolved_style_import: bool,
73 #[serde(skip)]
74 pub source_selector_candidates: Vec<LspStyleHoverCandidate>,
75 #[serde(skip)]
76 pub(crate) source_type_fact_selector_references: Vec<SourceSelectorReferenceFact>,
77 #[serde(skip)]
78 pub(crate) source_type_fact_retired_prefix_references: Vec<SourceSelectorReferenceFact>,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
82#[non_exhaustive]
83#[serde(rename_all = "camelCase")]
84pub struct LspSourceTypeFactTierAttemptV0 {
85 pub expression_id: String,
86 pub tier: &'static str,
87 pub outcome: &'static str,
88 pub reason: Option<&'static str>,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
92#[serde(rename_all = "camelCase")]
93pub struct LspOptimizingTierFeedback {
94 pub schema_version: &'static str,
95 pub product: &'static str,
96 pub document_version: i64,
97 pub policy: &'static str,
98 pub consumer: &'static str,
99 pub analyzed_graph: AnalyzedGraphV0,
100}
101
102#[derive(Debug, Clone, Serialize)]
103#[serde(rename_all = "camelCase")]
104pub struct LspStyleDocumentSummary {
105 pub language: &'static str,
106 pub selector_names: Vec<String>,
107 pub custom_property_decl_names: Vec<AuthoredPropertyTextV0>,
108 pub custom_property_ref_names: Vec<AuthoredPropertyTextV0>,
109 pub sass_module_use_sources: Vec<String>,
110 pub sass_module_forward_sources: Vec<String>,
111 pub diagnostic_count: usize,
112}
113
114impl PartialEq for LspStyleDocumentSummary {
115 fn eq(&self, other: &Self) -> bool {
116 self.language == other.language
117 && self.selector_names == other.selector_names
118 && authored_custom_property_sequences_same(
119 &self.custom_property_decl_names,
120 &other.custom_property_decl_names,
121 )
122 && authored_custom_property_sequences_same(
123 &self.custom_property_ref_names,
124 &other.custom_property_ref_names,
125 )
126 && self.sass_module_use_sources == other.sass_module_use_sources
127 && self.sass_module_forward_sources == other.sass_module_forward_sources
128 && self.diagnostic_count == other.diagnostic_count
129 }
130}
131
132impl Eq for LspStyleDocumentSummary {}
133
134fn authored_custom_property_sequences_same(
135 left: &[AuthoredPropertyTextV0],
136 right: &[AuthoredPropertyTextV0],
137) -> bool {
138 left.len() == right.len()
139 && left
140 .iter()
141 .zip(right)
142 .all(|(left, right)| left.to_custom_key() == right.to_custom_key())
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
146#[serde(rename_all = "camelCase")]
147pub struct LspStyleHoverCandidatesResult {
148 pub schema_version: &'static str,
149 pub product: &'static str,
150 pub document_uri: String,
151 pub workspace_folder_uri: Option<String>,
152 pub language: Option<&'static str>,
153 pub query_position: Option<ParserPositionV0>,
154 pub candidate_count: usize,
155 pub candidates: Vec<LspStyleHoverCandidate>,
156}
157
158#[derive(Debug, Clone, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct LspStyleHoverCandidate {
161 pub kind: &'static str,
162 pub name: AuthoredPropertyTextV0,
163 #[serde(skip)]
164 pub selector_key: Option<CanonicalClassKeyV0>,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub property_key: Option<CanonicalCustomPropertyNameV0>,
167 pub range: ParserRangeV0,
168 pub source: &'static str,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub target_style_uri: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub namespace: Option<String>,
173}
174
175#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
176pub(crate) enum LspStyleHoverCandidateIdentityRefV0<'candidate> {
177 Selector(Option<&'candidate CanonicalClassKeyV0>),
178 CustomProperty(Option<&'candidate CanonicalCustomPropertyNameV0>),
179 Other,
180}
181
182impl LspStyleHoverCandidate {
183 pub(crate) fn identity_name(&self) -> String {
184 if matches!(
185 self.kind,
186 "customPropertyDeclaration" | "customPropertyReference"
187 ) {
188 self.property_key
189 .as_ref()
190 .map(CanonicalCustomPropertyNameV0::as_str)
191 .unwrap_or_default()
192 .to_string()
193 } else {
194 let mut name = String::new();
195 let _ = omena_syntax::ident::render_authored(&self.name, &mut name);
196 name
197 }
198 }
199
200 pub(crate) fn identity(&self) -> LspStyleHoverCandidateIdentityRefV0<'_> {
201 if matches!(
202 self.kind,
203 "selector" | "sourceSelectorReference" | "sourceSelectorPrefixReference"
204 ) {
205 LspStyleHoverCandidateIdentityRefV0::Selector(self.selector_key.as_ref())
206 } else if matches!(
207 self.kind,
208 "customPropertyDeclaration" | "customPropertyReference"
209 ) {
210 LspStyleHoverCandidateIdentityRefV0::CustomProperty(self.property_key.as_ref())
211 } else {
212 LspStyleHoverCandidateIdentityRefV0::Other
213 }
214 }
215}
216
217impl PartialEq for LspStyleHoverCandidate {
218 fn eq(&self, other: &Self) -> bool {
219 self.kind == other.kind
220 && self.identity() == other.identity()
221 && self.range == other.range
222 && self.source == other.source
223 && self.target_style_uri == other.target_style_uri
224 && self.namespace == other.namespace
225 }
226}
227
228impl Eq for LspStyleHoverCandidate {}
229
230impl Ord for LspStyleHoverCandidate {
231 fn cmp(&self, other: &Self) -> CmpOrdering {
232 (
233 self.kind,
234 self.identity(),
235 self.range,
236 self.source,
237 &self.target_style_uri,
238 &self.namespace,
239 )
240 .cmp(&(
241 other.kind,
242 other.identity(),
243 other.range,
244 other.source,
245 &other.target_style_uri,
246 &other.namespace,
247 ))
248 }
249}
250
251impl PartialOrd for LspStyleHoverCandidate {
252 fn partial_cmp(&self, other: &Self) -> Option<CmpOrdering> {
253 Some(self.cmp(other))
254 }
255}
256
257#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
258#[serde(rename_all = "camelCase")]
259pub struct LspWorkspaceFolderState {
260 pub uri: String,
261 pub name: String,
262}
263
264#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
265#[serde(rename_all = "camelCase")]
266pub struct LspWatchedFileChangeState {
267 pub uri: String,
268 pub change_type: u64,
269}
270
271#[derive(Debug, Clone)]
272pub(crate) struct LspSourceTypeFactCacheEntryV0 {
273 pub(crate) entries: Vec<TsgoTypeFactResultEntryV0>,
274 pub(crate) last_used: u64,
275}
276
277#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
278#[serde(rename_all = "camelCase")]
279pub struct LspSourceTypeFactCacheTelemetryV0 {
280 pub hit_count: u64,
281 pub miss_count: u64,
282 pub sidecar_hit_count: u64,
283 pub sidecar_refused_by_reason: BTreeMap<String, u64>,
284 pub closure_incomplete_by_reason: BTreeMap<String, u64>,
285}
286
287#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
288pub struct LspFileId(u32);
289
290impl LspFileId {
291 #[cfg(test)]
292 pub(crate) fn incremental_key(self) -> u32 {
293 self.0
294 }
295
296 #[cfg(test)]
297 pub(crate) const fn fixture(value: u32) -> Self {
298 Self(value)
299 }
300}
301
302#[derive(Debug, Clone, Default)]
303pub(crate) struct LspFileIdentityInterner {
304 next_id: u32,
305 ids_by_uri_alias: BTreeMap<String, LspFileId>,
306 ids_by_storage_uri: BTreeMap<String, LspFileId>,
307 storage_uris_by_id: BTreeMap<LspFileId, String>,
308}
309
310impl LspFileIdentityInterner {
311 fn intern_uri(&mut self, uri: &str) -> (LspFileId, String) {
312 if let Some(file_id) = self.ids_by_uri_alias.get(uri) {
313 let storage_uri = self
314 .storage_uris_by_id
315 .get(file_id)
316 .cloned()
317 .unwrap_or_else(|| uri.to_string());
318 return (*file_id, storage_uri);
319 }
320 let storage_uri = Self::storage_uri(uri);
321 if let Some(file_id) = self.ids_by_storage_uri.get(storage_uri.as_str()) {
322 self.ids_by_uri_alias.insert(uri.to_string(), *file_id);
323 return (*file_id, storage_uri);
324 }
325 let file_id = LspFileId(self.next_id);
326 self.next_id = self.next_id.saturating_add(1);
327 self.ids_by_uri_alias.insert(uri.to_string(), file_id);
328 self.ids_by_uri_alias.insert(storage_uri.clone(), file_id);
329 self.ids_by_storage_uri.insert(storage_uri.clone(), file_id);
330 self.storage_uris_by_id.insert(file_id, storage_uri.clone());
331 (file_id, storage_uri)
332 }
333
334 fn file_id_for_uri(&self, uri: &str) -> Option<LspFileId> {
335 if let Some(file_id) = self.ids_by_uri_alias.get(uri) {
336 return Some(*file_id);
337 }
338 let storage_uri = Self::storage_uri(uri);
339 self.ids_by_storage_uri.get(storage_uri.as_str()).copied()
340 }
341
342 pub(crate) fn storage_uri_for_file_id(&self, file_id: LspFileId) -> Option<&str> {
343 self.storage_uris_by_id.get(&file_id).map(String::as_str)
344 }
345
346 fn storage_uri(uri: &str) -> String {
347 crate::protocol::canonical_file_uri(uri).unwrap_or_else(|| uri.to_string())
348 }
349}
350
351#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
352#[serde(rename_all = "camelCase")]
353pub struct LspShellStateSnapshot {
354 pub shutdown_requested: bool,
355 pub should_exit: bool,
356 pub features: LspFeatureSettings,
357 pub diagnostics: LspDiagnosticSettings,
358 pub resolution: LspResolutionSettings,
359 pub cancelled_request_count: usize,
360 pub suppressed_dispatched_result_count: u64,
361 pub workspace_style_index_exhausted_count: usize,
362 pub workspace_index_pending_file_count: usize,
363 pub external_sif_lock_read_count: usize,
366 pub external_sif_bridge_generation_count: usize,
367 pub document_count: usize,
368 pub workspace_folder_count: usize,
369 pub configuration_change_count: usize,
370 pub watched_file_event_count: usize,
371 pub cached_workspace_resolution_input_count: usize,
372 pub source_type_fact_cache_telemetry: LspSourceTypeFactCacheTelemetryV0,
373 pub tide_epoch: u64,
377 pub tide_sif_lane_generation: u64,
378 pub tide_sif_lane_in_flight: bool,
379 pub tide_sif_lane_has_demand: bool,
380 pub tide_republish_lane_generation: u64,
381 pub tide_republish_lane_in_flight: bool,
382 pub tide_republish_lane_has_demand: bool,
383 pub tide_starvation_alarm_count: u64,
384 pub tide_disowns_total: BTreeMap<String, u64>,
387 pub tide_disowns_out_of_cone: BTreeMap<String, u64>,
390 pub tide_sif_lane_oldest_deposit_age_ticks: Option<u64>,
394 pub tide_republish_lane_oldest_deposit_age_ticks: Option<u64>,
395 pub documents: Vec<LspTextDocumentState>,
396 pub workspace_folders: Vec<LspWorkspaceFolderState>,
397 pub watched_file_changes: Vec<LspWatchedFileChangeState>,
398}
399
400fn tide_disown_counts_by_driver(
401 counts: &[u64; crate::tide::ledger::TIDE_INPUT_KIND_COUNT],
402) -> BTreeMap<String, u64> {
403 crate::tide::TideInputKindV0::ALL
404 .into_iter()
405 .map(|kind| (kind.wire_name().to_string(), counts[kind as usize]))
406 .collect()
407}
408
409const DISPATCHED_REQUEST_PENDING: u8 = 0;
410const DISPATCHED_REQUEST_CANCELLED: u8 = 1;
411const DISPATCHED_REQUEST_COMPLETED: u8 = 2;
412
413#[derive(Debug, Default)]
414struct LspInFlightRequestRegistryInner {
415 next_generation: u64,
416 requests: BTreeMap<String, LspInFlightRequestEntry>,
417}
418
419#[derive(Debug, Clone)]
420struct LspInFlightRequestEntry {
421 generation: u64,
422 status: Arc<AtomicU8>,
423}
424
425#[derive(Debug, Clone, Default)]
430pub(crate) struct LspInFlightRequestRegistry {
431 inner: Arc<Mutex<LspInFlightRequestRegistryInner>>,
432 suppressed_result_count: Arc<AtomicU64>,
433}
434
435#[derive(Debug, Clone)]
436pub(crate) struct LspDispatchedRequestToken {
437 request_key: String,
438 generation: u64,
439 status: Arc<AtomicU8>,
440 registry: LspInFlightRequestRegistry,
441}
442
443#[derive(Debug, Clone, Copy, PartialEq, Eq)]
444pub(crate) enum LspDispatchedRequestCompletion {
445 Result,
446 Cancelled,
447 AlreadyCompleted,
448}
449
450impl LspInFlightRequestRegistry {
451 pub(crate) fn register(&self, request_key: String) -> LspDispatchedRequestToken {
452 let mut inner = self.inner.lock().unwrap_or_else(|error| error.into_inner());
453 inner.next_generation = inner.next_generation.saturating_add(1).max(1);
454 let generation = inner.next_generation;
455 let status = Arc::new(AtomicU8::new(DISPATCHED_REQUEST_PENDING));
456 inner.requests.insert(
457 request_key.clone(),
458 LspInFlightRequestEntry {
459 generation,
460 status: Arc::clone(&status),
461 },
462 );
463 LspDispatchedRequestToken {
464 request_key,
465 generation,
466 status,
467 registry: self.clone(),
468 }
469 }
470
471 pub(crate) fn cancel(&self, request_key: &str) -> bool {
472 let inner = self.inner.lock().unwrap_or_else(|error| error.into_inner());
473 let Some(entry) = inner.requests.get(request_key) else {
474 return false;
475 };
476 let _ = entry.status.compare_exchange(
477 DISPATCHED_REQUEST_PENDING,
478 DISPATCHED_REQUEST_CANCELLED,
479 Ordering::AcqRel,
480 Ordering::Acquire,
481 );
482 true
483 }
484
485 pub(crate) fn suppressed_result_count(&self) -> u64 {
486 self.suppressed_result_count.load(Ordering::Acquire)
487 }
488
489 fn remove_if_current(&self, request_key: &str, generation: u64, status: &Arc<AtomicU8>) {
490 let mut inner = self.inner.lock().unwrap_or_else(|error| error.into_inner());
491 let is_current = inner.requests.get(request_key).is_some_and(|entry| {
492 entry.generation == generation && Arc::ptr_eq(&entry.status, status)
493 });
494 if is_current {
495 inner.requests.remove(request_key);
496 }
497 }
498}
499
500impl LspDispatchedRequestToken {
501 pub(crate) fn complete(&self) -> LspDispatchedRequestCompletion {
502 let completion = match self.status.compare_exchange(
503 DISPATCHED_REQUEST_PENDING,
504 DISPATCHED_REQUEST_COMPLETED,
505 Ordering::AcqRel,
506 Ordering::Acquire,
507 ) {
508 Ok(_) => LspDispatchedRequestCompletion::Result,
509 Err(DISPATCHED_REQUEST_CANCELLED) => {
510 if self
511 .status
512 .compare_exchange(
513 DISPATCHED_REQUEST_CANCELLED,
514 DISPATCHED_REQUEST_COMPLETED,
515 Ordering::AcqRel,
516 Ordering::Acquire,
517 )
518 .is_ok()
519 {
520 self.registry
521 .suppressed_result_count
522 .fetch_add(1, Ordering::AcqRel);
523 LspDispatchedRequestCompletion::Cancelled
524 } else {
525 LspDispatchedRequestCompletion::AlreadyCompleted
526 }
527 }
528 Err(_) => LspDispatchedRequestCompletion::AlreadyCompleted,
529 };
530 self.registry
531 .remove_if_current(self.request_key.as_str(), self.generation, &self.status);
532 completion
533 }
534}
535
536#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
537#[serde(rename_all = "camelCase")]
538pub struct LspFeatureSettings {
539 pub definition: bool,
540 pub hover: bool,
541 pub completion: bool,
542 pub references: bool,
543 pub rename: bool,
544}
545
546impl Default for LspFeatureSettings {
547 fn default() -> Self {
548 Self {
549 definition: true,
550 hover: true,
551 completion: true,
552 references: true,
553 rename: true,
554 }
555 }
556}
557
558#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
559#[serde(rename_all = "camelCase")]
560pub struct LspDiagnosticSettings {
561 pub severity: u8,
562 pub deep_analysis: bool,
563}
564
565impl Default for LspDiagnosticSettings {
566 fn default() -> Self {
567 Self {
568 severity: 2,
569 deep_analysis: false,
570 }
571 }
572}
573
574#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
575#[serde(rename_all = "camelCase")]
576pub struct LspResolutionSettings {
577 pub package_manifest_paths: Vec<String>,
578 #[serde(skip)]
579 pub package_manifests: Vec<OmenaQueryStylePackageManifestV0>,
580 #[serde(skip)]
581 pub workspace_style_resolution_inputs: BTreeMap<String, OmenaQueryStyleResolutionInputsV0>,
582 #[serde(skip)]
586 pub external_sifs: Vec<OmenaQueryExternalSifInputV0>,
587 #[serde(skip)]
588 pub(crate) external_sif_trust_records:
589 BTreeMap<String, omena_query::OmenaQueryExternalSifTrustV1>,
590 #[serde(skip)]
591 pub(crate) bridge_external_sif_urls: BTreeSet<String>,
592 #[serde(skip)]
593 pub(crate) cache_storage: crate::cache_root::LspCacheStorageConfigV0,
594}
595
596#[derive(Debug)]
602pub(crate) struct LspCascadeNarrowingSubstrateMemo {
603 pub(crate) style_sources: Vec<OmenaQueryStyleSourceInputV0>,
604 pub(crate) package_manifests: Vec<OmenaQueryStylePackageManifestV0>,
605 pub(crate) external_sifs: Vec<OmenaQueryExternalSifInputV0>,
606 pub(crate) resolution_inputs: OmenaQueryStyleResolutionInputsV0,
607 pub(crate) substrate: Arc<OmenaQueryStyleCascadeNarrowingSubstrateV0>,
608}
609
610#[cfg(feature = "parallel-style-diagnostics")]
611#[derive(Debug, Clone)]
612pub(crate) struct LspResolverIdentityIndexMemo {
613 pub(crate) available_style_paths: Vec<String>,
614 pub(crate) disk_style_path_identities: Vec<OmenaResolverStyleModuleDiskCandidateIdentityV0>,
615 pub(crate) index: Arc<OmenaResolverStyleModuleConfirmationIdentityIndexV0>,
616}
617
618#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
619#[serde(rename_all = "camelCase")]
620pub(crate) struct LspSourceSelectorOccurrenceDocumentKey {
621 pub(crate) uri: String,
622 pub(crate) workspace_folder_uri: Option<String>,
623 pub(crate) language_id: String,
624 pub(crate) version: i64,
625 pub(crate) text_hash: String,
626}
627
628#[derive(Debug, Clone)]
629pub(crate) struct LspWorkspaceOccurrenceIndexMemo {
630 pub(crate) workspace_folder_uri: Option<String>,
631 pub(crate) environment_digest: Option<String>,
638 pub(crate) source_document_keys: Vec<LspSourceSelectorOccurrenceDocumentKey>,
639 pub(crate) style_document_keys: Vec<LspSourceSelectorOccurrenceDocumentKey>,
640 pub(crate) document_entries: BTreeMap<LspFileId, LspWorkspaceOccurrenceDocumentMemoEntry>,
641 pub(crate) shadow_verified_revision_digest: Option<String>,
646 pub(crate) definitions: Vec<OmenaQueryStyleSelectorDefinitionV0>,
647 pub(crate) source_selector_index: Arc<OmenaQuerySourceSelectorOccurrenceIndexV0>,
648 pub(crate) workspace_index: Arc<OmenaWorkspaceOccurrenceIndexV0>,
649 pub(crate) shadow_mismatch_count: Arc<AtomicU64>,
653}
654
655#[derive(Debug, Clone)]
656pub(crate) struct LspWorkspaceOccurrenceDocumentMemoEntry {
657 pub(crate) document_key: LspSourceSelectorOccurrenceDocumentKey,
658 pub(crate) dependency_document_uris: BTreeSet<String>,
659 pub(crate) dependency_digest: Option<String>,
660 pub(crate) occurrences: Vec<OmenaWorkspaceOccurrenceV0>,
661}
662
663pub(crate) type LspDocumentColorCacheV0 = BTreeMap<String, ((i64, u64, u64), serde_json::Value)>;
665
666#[cfg(feature = "salsa-style-diagnostics")]
667#[derive(Debug, Clone, PartialEq, Eq)]
668pub(crate) struct LspReverseDependencyIndexMemo {
669 pub(crate) revision: u64,
670 pub(crate) summary_hash: String,
671 pub(crate) ledger_epoch: u64,
675 pub(crate) index: ReverseDependencyIndexV0,
676 pub(crate) file_id_rev: BTreeMap<LspFileId, BTreeSet<LspFileId>>,
680}
681
682#[derive(Debug, Clone, Serialize)]
683#[serde(rename_all = "camelCase")]
684pub(crate) struct LspStyleSymbolOccurrenceV0 {
685 pub(crate) moniker: String,
686 pub(crate) uri: String,
687 pub(crate) kind: OmenaWorkspaceOccurrenceKindV0,
688 pub(crate) family: OmenaWorkspaceOccurrenceFamilyV0,
689 pub(crate) name: String,
690 pub(crate) range: ParserRangeV0,
691 pub(crate) role: OmenaWorkspaceOccurrenceRoleV0,
692 #[serde(skip_serializing_if = "Option::is_none")]
693 pub(crate) namespace: Option<String>,
694}
695
696impl PartialEq for LspStyleSymbolOccurrenceV0 {
697 fn eq(&self, other: &Self) -> bool {
698 self.cmp(other) == CmpOrdering::Equal
699 }
700}
701
702impl Eq for LspStyleSymbolOccurrenceV0 {}
703
704impl Ord for LspStyleSymbolOccurrenceV0 {
705 fn cmp(&self, other: &Self) -> CmpOrdering {
706 self.moniker
707 .cmp(&other.moniker)
708 .then_with(|| self.uri.cmp(&other.uri))
709 .then_with(|| self.kind.cmp(&other.kind))
710 .then_with(|| self.family.cmp(&other.family))
711 .then_with(|| style_symbol_occurrence_name_cmp(self, other))
712 .then_with(|| self.range.cmp(&other.range))
713 .then_with(|| self.role.cmp(&other.role))
714 .then_with(|| self.namespace.cmp(&other.namespace))
715 }
716}
717
718impl PartialOrd for LspStyleSymbolOccurrenceV0 {
719 fn partial_cmp(&self, other: &Self) -> Option<CmpOrdering> {
720 Some(self.cmp(other))
721 }
722}
723
724fn style_symbol_occurrence_name_cmp(
725 left: &LspStyleSymbolOccurrenceV0,
726 right: &LspStyleSymbolOccurrenceV0,
727) -> CmpOrdering {
728 if left.kind.family() == OmenaWorkspaceOccurrenceFamilyV0::CustomProperty
729 && right.kind.family() == OmenaWorkspaceOccurrenceFamilyV0::CustomProperty
730 {
731 return PropertyNameV0::canonical_custom_key(left.name.clone())
732 .cmp(&PropertyNameV0::canonical_custom_key(right.name.clone()));
733 }
734 left.name.cmp(&right.name)
735}
736
737#[allow(private_interfaces)]
749pub trait LspQueryReadView {
750 #[doc(hidden)]
751 fn query_features(&self) -> &LspFeatureSettings;
752
753 #[doc(hidden)]
754 fn query_diagnostics(&self) -> &LspDiagnosticSettings;
755
756 #[doc(hidden)]
757 fn query_resolution(&self) -> &LspResolutionSettings;
758
759 #[doc(hidden)]
760 fn query_file_identity(&self) -> &LspFileIdentityInterner;
761
762 #[doc(hidden)]
763 fn query_documents(&self) -> &BTreeMap<LspFileId, Arc<LspTextDocumentState>>;
764
765 #[doc(hidden)]
766 fn query_open_document_uris(&self) -> &BTreeSet<LspFileId>;
767
768 #[doc(hidden)]
769 fn query_workspace_runtime_registry(&self) -> &WorkspaceRuntimeRegistry;
770
771 #[doc(hidden)]
772 fn query_tide_ledger(&self) -> &crate::tide::TideEpochLedgerV0;
773
774 #[cfg(feature = "salsa-style-diagnostics")]
775 #[doc(hidden)]
776 fn query_style_workspace_snapshot_revision_hint(&self) -> u64;
777
778 #[doc(hidden)]
779 fn query_document_color_cache(&self) -> &Arc<Mutex<LspDocumentColorCacheV0>>;
780
781 #[doc(hidden)]
782 fn query_cascade_narrowing_substrate_memo(
783 &self,
784 ) -> &Arc<Mutex<Option<LspCascadeNarrowingSubstrateMemo>>>;
785
786 #[doc(hidden)]
787 fn query_workspace_occurrence_index_memo(
788 &self,
789 ) -> &Arc<Mutex<Option<LspWorkspaceOccurrenceIndexMemo>>>;
790
791 #[cfg(feature = "parallel-style-diagnostics")]
792 #[doc(hidden)]
793 fn query_resolver_identity_index_memo(
794 &self,
795 ) -> &Arc<Mutex<Option<LspResolverIdentityIndexMemo>>>;
796
797 fn document(&self, uri: &str) -> Option<&LspTextDocumentState> {
798 let file_id = self.query_file_identity().file_id_for_uri(uri)?;
799 self.query_documents().get(&file_id).map(Arc::as_ref)
800 }
801
802 fn document_for_file_id(&self, file_id: LspFileId) -> Option<&LspTextDocumentState> {
803 self.query_documents().get(&file_id).map(Arc::as_ref)
804 }
805
806 fn workspace_folder(&self, uri: &str) -> Option<&LspWorkspaceFolderState> {
807 self.query_workspace_runtime_registry().get(uri)
808 }
809
810 fn cascade_narrowing_substrate_memo_lock(
811 &self,
812 ) -> MutexGuard<'_, Option<LspCascadeNarrowingSubstrateMemo>> {
813 self.query_cascade_narrowing_substrate_memo()
814 .lock()
815 .unwrap_or_else(|error| error.into_inner())
816 }
817
818 fn workspace_occurrence_index_memo_lock(
819 &self,
820 ) -> MutexGuard<'_, Option<LspWorkspaceOccurrenceIndexMemo>> {
821 self.query_workspace_occurrence_index_memo()
822 .lock()
823 .unwrap_or_else(|error| error.into_inner())
824 }
825
826 #[cfg(feature = "parallel-style-diagnostics")]
827 fn resolver_identity_index_memo_lock(
828 &self,
829 ) -> MutexGuard<'_, Option<LspResolverIdentityIndexMemo>> {
830 self.query_resolver_identity_index_memo()
831 .lock()
832 .unwrap_or_else(|error| error.into_inner())
833 }
834
835 #[cfg(feature = "salsa-style-diagnostics")]
836 fn style_workspace_snapshot_revision_hint(&self) -> omena_query::IncrementalRevisionV0 {
837 omena_query::IncrementalRevisionV0 {
838 value: self.query_style_workspace_snapshot_revision_hint().max(1),
839 }
840 }
841}
842
843#[derive(Debug, Default)]
844pub struct LspShellState {
845 pub shutdown_requested: bool,
846 pub should_exit: bool,
847 pub(crate) features: LspFeatureSettings,
848 pub(crate) diagnostics: LspDiagnosticSettings,
849 pub(crate) resolution: LspResolutionSettings,
850 pub(crate) cancelled_request_ids: IncrementalCancellationRegistryV0,
851 pub(crate) in_flight_requests: LspInFlightRequestRegistry,
852 pub(crate) workspace_style_index_exhausted_count: usize,
853 pub(crate) source_type_fact_workspace_index_incomplete: bool,
854 pub(crate) source_type_fact_watched_files_observed: bool,
855 pub(crate) workspace_index_pending_file_count: usize,
856 pub(crate) external_sif_bridge_generation_count: usize,
857 pub(crate) external_sif_refresh_deferred: bool,
858 pub(crate) tide_ledger: crate::tide::TideEpochLedgerV0,
863 pub(crate) tide_sif_lane: crate::tide::TideLaneV0<crate::tide::TideSifDemandV0>,
864 pub(crate) tide_republish_lane: crate::tide::TideLaneV0<crate::tide::TideRepublishDemandV0>,
865 pub(crate) tide_disowns_total: [u64; crate::tide::ledger::TIDE_INPUT_KIND_COUNT],
866 pub(crate) tide_disowns_out_of_cone: [u64; crate::tide::ledger::TIDE_INPUT_KIND_COUNT],
867 pub(crate) tide_republish_gen_watch: std::sync::Arc<std::sync::atomic::AtomicU64>,
871 pub(crate) tide_tick: u64,
874 pub(crate) workspace_index_revision: u64,
875 #[cfg(feature = "salsa-style-diagnostics")]
876 pub(crate) style_workspace_snapshot_revision_hint: u64,
877 pub(crate) configuration_change_count: usize,
878 pub(crate) file_identity: LspFileIdentityInterner,
884 pub(crate) documents: BTreeMap<LspFileId, Arc<LspTextDocumentState>>,
885 pub(crate) open_document_uris: BTreeSet<LspFileId>,
886 pub(crate) workspace_runtime_registry: WorkspaceRuntimeRegistry,
887 pub(crate) tsgo_workspace_process_pool: TsgoWorkspaceProcessPoolV0,
888 pub(crate) watched_file_changes: Vec<LspWatchedFileChangeState>,
889 pub(crate) swept_legacy_cache_roots: BTreeSet<PathBuf>,
890 pub(crate) client_supports_work_done_progress: bool,
891 pub(crate) next_server_progress_request_id: u64,
892 pub(crate) pending_server_progress_request_tokens: BTreeMap<String, String>,
893 pub(crate) cascade_narrowing_substrate_memo:
899 Arc<Mutex<Option<LspCascadeNarrowingSubstrateMemo>>>,
900 #[cfg(feature = "parallel-style-diagnostics")]
901 pub(crate) resolver_identity_index_memo: Arc<Mutex<Option<LspResolverIdentityIndexMemo>>>,
902 pub(crate) workspace_occurrence_index_memo: Arc<Mutex<Option<LspWorkspaceOccurrenceIndexMemo>>>,
908 pub(crate) document_color_cache: Arc<Mutex<LspDocumentColorCacheV0>>,
912 #[cfg(feature = "salsa-style-diagnostics")]
913 pub(crate) reverse_dependency_index_memo: RefCell<Option<LspReverseDependencyIndexMemo>>,
914 pub(crate) style_module_interface_memo:
921 RefCell<BTreeMap<String, omena_query::OmenaQueryModuleInterfaceChangeProjectionV0>>,
922 pub(crate) diagnostics_publish_digest_registry: DiagnosticsPublishDigestRegistryV0,
925 pub(crate) source_type_fact_cache: BTreeMap<String, LspSourceTypeFactCacheEntryV0>,
926 pub(crate) source_type_fact_cache_next_use: u64,
927 pub(crate) source_type_fact_cache_telemetry: LspSourceTypeFactCacheTelemetryV0,
928 pub(crate) disk_diagnostics_cache_session: RefCell<DiskDiagnosticsCacheSessionV0>,
932 #[cfg(feature = "salsa-style-diagnostics")]
936 pub(crate) style_memo_host: RefCell<Option<omena_query::OmenaQueryStyleMemoHostV0>>,
937}
938
939impl LspShellState {
940 pub fn configure_standalone_cache_storage(&mut self, cache_dir: Option<PathBuf>) {
941 self.resolution.cache_storage =
942 crate::cache_root::LspCacheStorageConfigV0::standalone(cache_dir);
943 }
944
945 pub fn document_count(&self) -> usize {
946 self.documents.len()
947 }
948
949 pub fn workspace_folder_count(&self) -> usize {
950 self.workspace_runtime_registry.len()
951 }
952
953 pub(crate) fn allocate_work_done_progress_request(&mut self) -> (String, String) {
954 self.next_server_progress_request_id += 1;
955 let id = format!(
956 "omena-work-done-progress-create-{}",
957 self.next_server_progress_request_id
958 );
959 let token = format!(
960 "omena-workspace-index-{}",
961 self.next_server_progress_request_id
962 );
963 self.pending_server_progress_request_tokens
964 .insert(id.clone(), token.clone());
965 (id, token)
966 }
967
968 pub(crate) fn take_server_progress_response(&mut self, id: &str) -> bool {
969 self.pending_server_progress_request_tokens
970 .remove(id)
971 .is_some()
972 }
973
974 pub fn document(&self, uri: &str) -> Option<&LspTextDocumentState> {
975 let file_id = self.file_identity.file_id_for_uri(uri)?;
976 self.documents.get(&file_id).map(Arc::as_ref)
977 }
978
979 #[cfg(feature = "test-support")]
980 pub fn evict_document_for_test(&mut self, uri: &str) -> Option<LspTextDocumentState> {
981 self.remove_document_uri(uri)
982 }
983
984 #[cfg(feature = "test-support")]
985 pub fn clear_workspace_occurrence_index_memo_for_test(&self) {
986 *self.workspace_occurrence_index_memo_lock() = None;
987 }
988
989 pub(crate) fn workspace_occurrence_index_memo_lock(
990 &self,
991 ) -> MutexGuard<'_, Option<LspWorkspaceOccurrenceIndexMemo>> {
992 self.workspace_occurrence_index_memo
993 .lock()
994 .unwrap_or_else(|error| error.into_inner())
995 }
996
997 pub(crate) fn document_mut(&mut self, uri: &str) -> Option<&mut LspTextDocumentState> {
998 let file_id = self.file_identity.file_id_for_uri(uri)?;
999 let document = self.documents.get_mut(&file_id)?;
1000 if document.origin == LspDocumentOrigin::Foreign {
1001 return None;
1002 }
1003 Some(Arc::make_mut(document))
1004 }
1005
1006 #[cfg(test)]
1007 pub(crate) fn document_storage_uri(uri: &str) -> String {
1008 LspFileIdentityInterner::storage_uri(uri)
1009 }
1010
1011 pub(crate) fn document_file_id(&self, uri: &str) -> Option<LspFileId> {
1012 self.file_identity.file_id_for_uri(uri)
1013 }
1014
1015 #[cfg(test)]
1016 pub(crate) fn intern_file_uri(&mut self, uri: &str) -> LspFileId {
1017 self.file_identity.intern_uri(uri).0
1018 }
1019
1020 pub(crate) fn document_storage_uri_for_file_id(&self, file_id: LspFileId) -> Option<&str> {
1021 self.file_identity.storage_uri_for_file_id(file_id)
1022 }
1023
1024 pub(crate) fn document_for_file_id(&self, file_id: LspFileId) -> Option<&LspTextDocumentState> {
1025 self.documents.get(&file_id).map(Arc::as_ref)
1026 }
1027
1028 pub(crate) fn insert_open_document_uri(&mut self, uri: &str) -> String {
1029 let (file_id, storage_uri) = self.file_identity.intern_uri(uri);
1030 self.open_document_uris.insert(file_id);
1031 storage_uri
1032 }
1033
1034 pub(crate) fn remove_open_document_uri(&mut self, uri: &str) {
1035 if let Some(file_id) = self.file_identity.file_id_for_uri(uri) {
1036 self.open_document_uris.remove(&file_id);
1037 }
1038 }
1039
1040 pub(crate) fn has_open_document_uri(&self, uri: &str) -> bool {
1041 self.file_identity
1042 .file_id_for_uri(uri)
1043 .is_some_and(|file_id| self.open_document_uris.contains(&file_id))
1044 }
1045
1046 pub(crate) fn insert_document(&mut self, uri: &str, document: LspTextDocumentState) {
1047 let (file_id, _) = self.file_identity.intern_uri(uri);
1048 self.documents.insert(file_id, Arc::new(document));
1049 }
1050
1051 pub(crate) fn remove_document_uri(&mut self, uri: &str) -> Option<LspTextDocumentState> {
1052 let file_id = self.file_identity.file_id_for_uri(uri)?;
1053 let document = self.documents.remove(&file_id).map(Arc::unwrap_or_clone)?;
1054 let memo = self.style_module_interface_memo.get_mut();
1055 memo.remove(uri);
1056 memo.remove(document.uri.as_str());
1057 self.diagnostics_publish_digest_registry
1058 .forget_reactive_shadow_module_interface(uri);
1059 self.diagnostics_publish_digest_registry
1060 .forget_reactive_shadow_module_interface(document.uri.as_str());
1061 Some(document)
1062 }
1063
1064 pub(crate) fn contains_document_uri(&self, uri: &str) -> bool {
1065 self.document(uri).is_some()
1066 }
1067
1068 pub fn workspace_folder(&self, uri: &str) -> Option<&LspWorkspaceFolderState> {
1069 self.workspace_runtime_registry.get(uri)
1070 }
1071
1072 pub fn snapshot(&self) -> LspShellStateSnapshot {
1073 LspShellStateSnapshot {
1074 shutdown_requested: self.shutdown_requested,
1075 should_exit: self.should_exit,
1076 features: self.features.clone(),
1077 diagnostics: self.diagnostics.clone(),
1078 resolution: self.resolution.clone(),
1079 cancelled_request_count: self.cancelled_request_ids.len(),
1080 suppressed_dispatched_result_count: self.in_flight_requests.suppressed_result_count(),
1081 workspace_style_index_exhausted_count: self.workspace_style_index_exhausted_count,
1082 workspace_index_pending_file_count: self.workspace_index_pending_file_count,
1083 external_sif_lock_read_count: 0,
1084 external_sif_bridge_generation_count: self.external_sif_bridge_generation_count,
1085 document_count: self.document_count(),
1086 workspace_folder_count: self.workspace_folder_count(),
1087 configuration_change_count: self.configuration_change_count,
1088 watched_file_event_count: self.watched_file_changes.len(),
1089 cached_workspace_resolution_input_count: self
1090 .resolution
1091 .workspace_style_resolution_inputs
1092 .len(),
1093 source_type_fact_cache_telemetry: self.source_type_fact_cache_telemetry.clone(),
1094 tide_epoch: self.tide_ledger.epoch(),
1095 tide_sif_lane_generation: self.tide_sif_lane.generation(),
1096 tide_sif_lane_in_flight: self.tide_sif_lane.in_flight(),
1097 tide_sif_lane_has_demand: self.tide_sif_lane.has_demand(),
1098 tide_republish_lane_generation: self.tide_republish_lane.generation(),
1099 tide_republish_lane_in_flight: self.tide_republish_lane.in_flight(),
1100 tide_republish_lane_has_demand: self.tide_republish_lane.has_demand(),
1101 tide_starvation_alarm_count: self.tide_sif_lane.starvation_alarm_count()
1102 + self.tide_republish_lane.starvation_alarm_count(),
1103 tide_disowns_total: tide_disown_counts_by_driver(&self.tide_disowns_total),
1104 tide_disowns_out_of_cone: tide_disown_counts_by_driver(&self.tide_disowns_out_of_cone),
1105 tide_sif_lane_oldest_deposit_age_ticks: self
1106 .tide_sif_lane
1107 .oldest_deposit_age_ticks(self.tide_tick),
1108 tide_republish_lane_oldest_deposit_age_ticks: self
1109 .tide_republish_lane
1110 .oldest_deposit_age_ticks(self.tide_tick),
1111 documents: {
1112 let mut documents = self
1113 .documents
1114 .values()
1115 .map(|document| (**document).clone())
1116 .collect::<Vec<_>>();
1117 documents.sort_by(|left, right| left.uri.cmp(&right.uri));
1118 documents
1119 },
1120 workspace_folders: self.workspace_runtime_registry.folder_snapshots(),
1121 watched_file_changes: self.watched_file_changes.clone(),
1122 }
1123 }
1124
1125 #[cfg(feature = "parallel-style-diagnostics")]
1126 pub(crate) fn resolver_identity_index_memo_lock(
1127 &self,
1128 ) -> MutexGuard<'_, Option<LspResolverIdentityIndexMemo>> {
1129 self.resolver_identity_index_memo
1130 .lock()
1131 .unwrap_or_else(|error| error.into_inner())
1132 }
1133
1134 pub fn tide_republish_lane_generation(&self) -> u64 {
1137 self.tide_republish_lane.generation()
1138 }
1139
1140 pub fn tide_republish_lane_in_flight(&self) -> bool {
1144 self.tide_republish_lane.in_flight()
1145 }
1146
1147 pub fn advance_tide_tick(&mut self) {
1150 self.tide_tick = self.tide_tick.saturating_add(1);
1151 }
1152
1153 pub(crate) fn tide_reopen_republish_window(&mut self, cause: crate::tide::TideDisownCauseV0) {
1156 let in_flight_demand = self.tide_republish_lane.in_flight_demand().cloned();
1157 let out_of_cone = in_flight_demand
1158 .as_ref()
1159 .is_some_and(|demand| self.tide_disown_cause_is_out_of_cone(demand, &cause));
1160 let reopened = self.tide_republish_lane.reopen_window_for_cause(cause);
1161 if let Some(disowned_cause) = reopened.disowned_cause {
1162 let index = disowned_cause.kind as usize;
1163 self.tide_disowns_total[index] = self.tide_disowns_total[index].saturating_add(1);
1164 if out_of_cone {
1165 self.tide_disowns_out_of_cone[index] =
1166 self.tide_disowns_out_of_cone[index].saturating_add(1);
1167 }
1168 crate::loop_trace!(
1169 "republish-tide disowned kind={} disposition={}",
1170 disowned_cause.kind.wire_name(),
1171 if out_of_cone {
1172 "out-of-cone"
1173 } else {
1174 "in-cone"
1175 }
1176 );
1177 }
1178 self.tide_republish_gen_watch
1179 .store(reopened.generation, std::sync::atomic::Ordering::Relaxed);
1180 }
1181
1182 fn tide_disown_cause_is_out_of_cone(
1183 &self,
1184 in_flight: &crate::tide::TideRepublishDemandV0,
1185 cause: &crate::tide::TideDisownCauseV0,
1186 ) -> bool {
1187 use crate::tide::TideRepublishDemandV0;
1188
1189 match (&cause.affected, in_flight) {
1190 (TideRepublishDemandV0::All, _)
1191 | (_, TideRepublishDemandV0::All)
1192 | (_, TideRepublishDemandV0::None) => false,
1193 (TideRepublishDemandV0::None, TideRepublishDemandV0::Cone(_)) => true,
1194 (TideRepublishDemandV0::Cone(affected), TideRepublishDemandV0::Cone(_)) => {
1195 let targets =
1196 crate::diagnostics_follow_up::tide_republish_target_file_ids(self, in_flight);
1197 !targets
1198 .iter()
1199 .any(|target| affected.members.contains(target))
1200 }
1201 }
1202 }
1203
1204 #[cfg(feature = "salsa-style-diagnostics")]
1205 pub(crate) fn mark_style_workspace_snapshot_changed(
1206 &mut self,
1207 ) -> omena_query::IncrementalRevisionV0 {
1208 let committed = self
1209 .style_memo_host
1210 .borrow()
1211 .as_ref()
1212 .map(|host| host.committed_revision().value)
1213 .unwrap_or_default();
1214 let next = self
1215 .style_workspace_snapshot_revision_hint
1216 .max(committed)
1217 .saturating_add(1)
1218 .max(1);
1219 self.style_workspace_snapshot_revision_hint = next;
1220 omena_query::IncrementalRevisionV0 { value: next }
1221 }
1222
1223 pub fn query_snapshot(&self) -> LspQuerySnapshotV0 {
1230 LspQuerySnapshotV0 {
1231 state: LspShellState {
1232 features: self.features.clone(),
1233 diagnostics: self.diagnostics.clone(),
1234 resolution: self.resolution.clone(),
1235 file_identity: self.file_identity.clone(),
1236 documents: self.documents.clone(),
1237 open_document_uris: self.open_document_uris.clone(),
1238 workspace_runtime_registry: self.workspace_runtime_registry.clone(),
1239 tide_ledger: self.tide_ledger.clone(),
1240 #[cfg(feature = "salsa-style-diagnostics")]
1241 style_workspace_snapshot_revision_hint: self.style_workspace_snapshot_revision_hint,
1242 document_color_cache: Arc::clone(&self.document_color_cache),
1243 cascade_narrowing_substrate_memo: Arc::clone(
1244 &self.cascade_narrowing_substrate_memo,
1245 ),
1246 workspace_occurrence_index_memo: Arc::clone(&self.workspace_occurrence_index_memo),
1247 #[cfg(feature = "parallel-style-diagnostics")]
1248 resolver_identity_index_memo: Arc::clone(&self.resolver_identity_index_memo),
1249 ..LspShellState::default()
1250 },
1251 }
1252 }
1253}
1254
1255#[allow(private_interfaces)]
1256impl LspQueryReadView for LspShellState {
1257 fn query_features(&self) -> &LspFeatureSettings {
1258 &self.features
1259 }
1260
1261 fn query_diagnostics(&self) -> &LspDiagnosticSettings {
1262 &self.diagnostics
1263 }
1264
1265 fn query_resolution(&self) -> &LspResolutionSettings {
1266 &self.resolution
1267 }
1268
1269 fn query_file_identity(&self) -> &LspFileIdentityInterner {
1270 &self.file_identity
1271 }
1272
1273 fn query_documents(&self) -> &BTreeMap<LspFileId, Arc<LspTextDocumentState>> {
1274 &self.documents
1275 }
1276
1277 fn query_open_document_uris(&self) -> &BTreeSet<LspFileId> {
1278 &self.open_document_uris
1279 }
1280
1281 fn query_workspace_runtime_registry(&self) -> &WorkspaceRuntimeRegistry {
1282 &self.workspace_runtime_registry
1283 }
1284
1285 fn query_tide_ledger(&self) -> &crate::tide::TideEpochLedgerV0 {
1286 &self.tide_ledger
1287 }
1288
1289 #[cfg(feature = "salsa-style-diagnostics")]
1290 fn query_style_workspace_snapshot_revision_hint(&self) -> u64 {
1291 self.style_workspace_snapshot_revision_hint
1292 }
1293
1294 fn query_document_color_cache(&self) -> &Arc<Mutex<LspDocumentColorCacheV0>> {
1295 &self.document_color_cache
1296 }
1297
1298 fn query_cascade_narrowing_substrate_memo(
1299 &self,
1300 ) -> &Arc<Mutex<Option<LspCascadeNarrowingSubstrateMemo>>> {
1301 &self.cascade_narrowing_substrate_memo
1302 }
1303
1304 fn query_workspace_occurrence_index_memo(
1305 &self,
1306 ) -> &Arc<Mutex<Option<LspWorkspaceOccurrenceIndexMemo>>> {
1307 &self.workspace_occurrence_index_memo
1308 }
1309
1310 #[cfg(feature = "parallel-style-diagnostics")]
1311 fn query_resolver_identity_index_memo(
1312 &self,
1313 ) -> &Arc<Mutex<Option<LspResolverIdentityIndexMemo>>> {
1314 &self.resolver_identity_index_memo
1315 }
1316}
1317
1318#[derive(Debug)]
1325pub struct LspQuerySnapshotV0 {
1326 pub(crate) state: LspShellState,
1327}
1328
1329impl LspQuerySnapshotV0 {
1330 #[cfg(test)]
1331 pub(crate) fn shell_state_for_test(&self) -> &LspShellState {
1332 &self.state
1333 }
1334}
1335
1336#[allow(private_interfaces)]
1337impl LspQueryReadView for LspQuerySnapshotV0 {
1338 fn query_features(&self) -> &LspFeatureSettings {
1339 &self.state.features
1340 }
1341
1342 fn query_diagnostics(&self) -> &LspDiagnosticSettings {
1343 &self.state.diagnostics
1344 }
1345
1346 fn query_resolution(&self) -> &LspResolutionSettings {
1347 &self.state.resolution
1348 }
1349
1350 fn query_file_identity(&self) -> &LspFileIdentityInterner {
1351 &self.state.file_identity
1352 }
1353
1354 fn query_documents(&self) -> &BTreeMap<LspFileId, Arc<LspTextDocumentState>> {
1355 &self.state.documents
1356 }
1357
1358 fn query_open_document_uris(&self) -> &BTreeSet<LspFileId> {
1359 &self.state.open_document_uris
1360 }
1361
1362 fn query_workspace_runtime_registry(&self) -> &WorkspaceRuntimeRegistry {
1363 &self.state.workspace_runtime_registry
1364 }
1365
1366 fn query_tide_ledger(&self) -> &crate::tide::TideEpochLedgerV0 {
1367 &self.state.tide_ledger
1368 }
1369
1370 #[cfg(feature = "salsa-style-diagnostics")]
1371 fn query_style_workspace_snapshot_revision_hint(&self) -> u64 {
1372 self.state.style_workspace_snapshot_revision_hint
1373 }
1374
1375 fn query_document_color_cache(&self) -> &Arc<Mutex<LspDocumentColorCacheV0>> {
1376 &self.state.document_color_cache
1377 }
1378
1379 fn query_cascade_narrowing_substrate_memo(
1380 &self,
1381 ) -> &Arc<Mutex<Option<LspCascadeNarrowingSubstrateMemo>>> {
1382 &self.state.cascade_narrowing_substrate_memo
1383 }
1384
1385 fn query_workspace_occurrence_index_memo(
1386 &self,
1387 ) -> &Arc<Mutex<Option<LspWorkspaceOccurrenceIndexMemo>>> {
1388 &self.state.workspace_occurrence_index_memo
1389 }
1390
1391 #[cfg(feature = "parallel-style-diagnostics")]
1392 fn query_resolver_identity_index_memo(
1393 &self,
1394 ) -> &Arc<Mutex<Option<LspResolverIdentityIndexMemo>>> {
1395 &self.state.resolver_identity_index_memo
1396 }
1397}
1398
1399const _: () = {
1402 const fn assert_send<T: Send>() {}
1403 assert_send::<LspQuerySnapshotV0>();
1404};