code_moniker_workspace/snapshot/view/
symbols.rs1use rustc_hash::FxHashMap;
4
5use super::model::{SymbolDetail, SymbolSummary};
6use crate::snapshot::model::{ChangeStatus, SymbolId, SymbolRecord, WorkspaceSnapshot};
7
8pub struct SymbolView<'a> {
9 snapshot: &'a WorkspaceSnapshot,
10}
11
12impl<'a> SymbolView<'a> {
13 pub(super) fn new(snapshot: &'a WorkspaceSnapshot) -> Self {
14 Self { snapshot }
15 }
16
17 pub fn all(&self) -> Vec<SymbolSummary> {
18 let counts = self.navigable_child_counts();
19 let mut symbols = self
20 .snapshot
21 .index
22 .symbols
23 .iter()
24 .filter(|symbol| symbol.navigable)
25 .map(|symbol| self.summary_with_children(symbol, &counts))
26 .collect::<Vec<_>>();
27 symbols.sort_by(|left, right| {
28 left.source
29 .cmp(&right.source)
30 .then_with(|| left.identity.cmp(&right.identity))
31 });
32 symbols
33 }
34
35 fn navigable_child_counts(&self) -> FxHashMap<&SymbolId, usize> {
36 let mut counts = FxHashMap::default();
37 for symbol in self.snapshot.index.symbols.iter() {
38 if symbol.navigable
39 && let Some(parent) = symbol.parent.as_ref()
40 {
41 *counts.entry(parent).or_default() += 1;
42 }
43 }
44 counts
45 }
46
47 fn summary_with_children(
48 &self,
49 symbol: &SymbolRecord,
50 counts: &FxHashMap<&SymbolId, usize>,
51 ) -> SymbolSummary {
52 SymbolSummary {
53 id: symbol.id,
54 source: symbol.source,
55 identity: symbol.identity.clone(),
56 name: symbol.name.clone(),
57 kind: symbol.kind.clone(),
58 line_range: symbol.line_range,
59 child_count: counts.get(&symbol.id).copied().unwrap_or(0),
60 change: self.change_status_for_symbol(&symbol.id),
61 }
62 }
63
64 pub fn roots_for_source(&self, source: &crate::snapshot::SourceId) -> Vec<SymbolSummary> {
65 self.snapshot
66 .index
67 .symbols
68 .iter()
69 .filter(|symbol| {
70 symbol.navigable && &symbol.source == source && symbol.parent.is_none()
71 })
72 .map(|symbol| self.summary(symbol))
73 .collect()
74 }
75
76 pub fn children(&self, parent: &SymbolId) -> Vec<SymbolSummary> {
77 self.snapshot
78 .index
79 .symbols
80 .iter()
81 .filter(|symbol| symbol.navigable && symbol.parent.as_ref() == Some(parent))
82 .map(|symbol| self.summary(symbol))
83 .collect()
84 }
85
86 pub fn detail(&self, symbol: &SymbolId) -> Option<SymbolDetail> {
87 let record = self.find(symbol)?;
88 Some(SymbolDetail {
89 symbol: self.summary(record),
90 children: self.children(symbol),
91 })
92 }
93
94 pub fn find(&self, id: &SymbolId) -> Option<&'a SymbolRecord> {
95 let record = self
96 .snapshot
97 .index
98 .symbols
99 .file_records(id.file())
100 .get(id.def());
101 if let Some(record) = record
102 && &record.id == id
103 {
104 return Some(record);
105 }
106 self.snapshot
107 .index
108 .symbols
109 .iter()
110 .find(|symbol| &symbol.id == id)
111 }
112
113 pub(super) fn summary(&self, symbol: &SymbolRecord) -> SymbolSummary {
114 SymbolSummary {
115 id: symbol.id,
116 source: symbol.source,
117 identity: symbol.identity.clone(),
118 name: symbol.name.clone(),
119 kind: symbol.kind.clone(),
120 line_range: symbol.line_range,
121 child_count: self
122 .snapshot
123 .index
124 .symbols
125 .iter()
126 .filter(|child| child.navigable && child.parent.as_ref() == Some(&symbol.id))
127 .count(),
128 change: self.change_status_for_symbol(&symbol.id),
129 }
130 }
131
132 fn change_status_for_symbol(&self, symbol: &SymbolId) -> Option<ChangeStatus> {
133 self.snapshot
134 .changes
135 .changes
136 .iter()
137 .find(|change| change.symbol.as_ref() == Some(symbol))
138 .map(|change| change.status)
139 }
140}