Skip to main content

code_moniker_workspace/changes/
overlay.rs

1use crate::code::CodeIndexSymbolProvider;
2use crate::snapshot::{
3	ChangeOverlay, ChangeOverlayReport, ChangeResource, CodeIndex, SourceCatalog, WorkspaceFailure,
4	WorkspaceResource, WorkspaceResult,
5};
6use crate::source::{CodeIndexMaterial, LocalResourceCache};
7
8use super::analyzer::ChangeAnalyzer;
9use super::diff::{self, ChangeFile, ChangeRoot, ChangeScan};
10
11pub trait ChangeOverlayPort {
12	fn build_change_overlay(
13		&mut self,
14		catalog: &SourceCatalog,
15		index: &CodeIndex,
16	) -> WorkspaceResult<ChangeOverlay>;
17}
18
19pub struct LocalChangeOverlay {
20	cache: LocalResourceCache,
21}
22
23impl LocalChangeOverlay {
24	pub fn new(cache: LocalResourceCache) -> Self {
25		Self { cache }
26	}
27}
28
29impl ChangeOverlayPort for LocalChangeOverlay {
30	fn build_change_overlay(
31		&mut self,
32		catalog: &SourceCatalog,
33		index: &CodeIndex,
34	) -> WorkspaceResult<ChangeOverlay> {
35		let material = self.cache.index_material(index.generation).ok_or_else(|| {
36			WorkspaceFailure::new(
37				WorkspaceResource::ChangeOverlay,
38				"code index material is unavailable",
39			)
40		})?;
41		let generation = self.cache.next_generation();
42		let change_index_span = tracing::info_span!("workspace.change_overlay.change_index");
43		let change_index =
44			change_index_span.in_scope(|| diff::build_change_index(change_scan(&material)));
45		let report_span = tracing::info_span!("workspace.change_overlay.report");
46		let overlay = report_span.in_scope(|| {
47			ChangeOverlay::from_report(change_report(
48				generation,
49				catalog.generation,
50				index.generation,
51				change_index,
52				&material,
53			))
54		});
55		Ok(overlay)
56	}
57}
58
59pub fn build_semantic_review(
60	material: &CodeIndexMaterial,
61) -> super::semantic::review::SemanticReview {
62	super::semantic::review::build_semantic_review(&change_scan(material))
63}
64
65fn change_scan(material: &CodeIndexMaterial) -> ChangeScan<'_> {
66	ChangeScan {
67		roots: material
68			.source_catalog
69			.sources
70			.roots
71			.iter()
72			.map(|root| ChangeRoot {
73				label: &root.label,
74				path: &root.path,
75				ctx: &root.ctx,
76				source_groups: &root.source_groups,
77			})
78			.collect(),
79		files: material
80			.files
81			.iter()
82			.enumerate()
83			.map(|(file_idx, file)| ChangeFile {
84				file_idx,
85				source_root: file.source_root,
86				path: &file.path,
87				rel_path: &file.rel_path,
88				anchor: &file.anchor,
89				lang: file.lang,
90				srcset: material
91					.source_catalog
92					.sources
93					.files
94					.get(file_idx)
95					.and_then(|source| source.srcset.as_deref()),
96				graph: &file.graph,
97				source: &file.source,
98			})
99			.collect(),
100	}
101}
102
103fn change_report(
104	generation: crate::snapshot::ResourceGeneration,
105	catalog_generation: crate::snapshot::ResourceGeneration,
106	index_generation: crate::snapshot::ResourceGeneration,
107	change_index: diff::ChangeIndex,
108	material: &CodeIndexMaterial,
109) -> ChangeOverlayReport {
110	let provider = CodeIndexSymbolProvider::new(material);
111	let changes = ChangeAnalyzer::new(&provider).analyze(&change_index.entries);
112	ChangeOverlayReport {
113		generation,
114		catalog_generation,
115		index_generation,
116		scope: change_index.scope,
117		resources: change_index
118			.resources
119			.into_iter()
120			.map(|resource| ChangeResource {
121				available: resource.available(),
122				label: resource.label,
123				message: resource.message,
124			})
125			.collect(),
126		diagnostics: change_index.diagnostics,
127		changes,
128	}
129}