code_moniker_workspace/changes/
overlay.rs1use 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}