1use crate::{
11 Application, BinaryOp, Binding, ComponentDef, Expr, ExprKind, IfNode, LayoutConfig, Node,
12};
13use bern_protocol::{Type, Value};
14use std::collections::BTreeSet;
15
16pub const TELEVISION_SCREEN: (f64, f64) = (1920.0, 1080.0);
18
19impl Application {
20 pub fn on_television(&self) -> Application {
22 let window = Known {
23 layouts: self.layouts,
24 television: true,
25 webview: None,
26 menu_bar: Some(false),
27 };
28 self.pruned(&window)
29 }
30
31 pub fn with_webview(&self, enabled: bool) -> Application {
34 self.pruned(&Known {
35 layouts: self.layouts,
36 television: false,
37 webview: Some(enabled),
38 menu_bar: None,
39 })
40 }
41
42 pub fn with_menu_bar(&self, shown: bool) -> Application {
46 self.pruned(&Known {
47 layouts: self.layouts,
48 television: false,
49 webview: None,
50 menu_bar: Some(shown),
51 })
52 }
53
54 fn pruned(&self, window: &Known) -> Application {
55 let mut app = self.clone();
56 for component in &mut app.components {
57 component.body = single(window.prune_node(&component.body));
58 }
59 for content in app.windows.windows.iter_mut().map(|w| &mut w.content) {
60 *content = single(window.prune_node(content));
61 }
62 for menu in [&mut app.windows.menu_bar, &mut app.windows.status_item]
63 .into_iter()
64 .flatten()
65 {
66 if let [Node::Element(pruned)] =
67 window.prune_node(&Node::Element(menu.clone())).as_slice()
68 {
69 *menu = pruned.clone();
70 }
71 }
72 let mut reached = BTreeSet::new();
74 let mut pending: Vec<String> = Vec::new();
75 let collect = |node: &Node, pending: &mut Vec<String>| {
76 node.walk(&mut |node| {
77 if let Node::Component(call) = node {
78 pending.push(call.component.clone());
79 }
80 });
81 };
82 for window in &app.windows.windows {
83 collect(&window.content, &mut pending);
84 }
85 while let Some(name) = pending.pop() {
86 if !reached.insert(name.clone()) {
87 continue;
88 }
89 if let Some(component) = app.components.iter().find(|c| c.name == name) {
90 collect(&component.body, &mut pending);
91 }
92 }
93 app.components
94 .retain(|component: &ComponentDef| reached.contains(&component.name));
95 app
96 }
97}
98
99struct Known {
101 layouts: Option<LayoutConfig>,
102 television: bool,
103 webview: Option<bool>,
104 menu_bar: Option<bool>,
106}
107
108impl Known {
109 fn known(&self, expr: &Expr) -> Option<bool> {
113 match &expr.kind {
114 ExprKind::Binding {
115 binding: Binding::Window { field },
116 } => match field.as_str() {
117 "webview" => self.webview,
118 "menu_bar" => self.menu_bar,
119 _ if !self.television => None,
120 "tv" => Some(true),
121 "landscape" => Some(true),
122 "idle" => None,
123 "keyboard" => None,
125 "short" => self
126 .layouts
127 .map(|layouts| TELEVISION_SCREEN.1 < layouts.compact_below),
128 size => self
129 .layouts
130 .map(|layouts| layouts.size(TELEVISION_SCREEN.0).name() == size),
131 },
132 ExprKind::Literal {
133 value: Value::Bool(value),
134 } => Some(*value),
135 ExprKind::Not { expr } => self.known(expr).map(|value| !value),
136 ExprKind::Binary {
137 op: BinaryOp::And,
138 lhs,
139 rhs,
140 } => match (self.known(lhs), self.known(rhs)) {
141 (Some(false), _) | (_, Some(false)) => Some(false),
142 (Some(true), Some(true)) => Some(true),
143 _ => None,
144 },
145 ExprKind::Binary {
146 op: BinaryOp::Or,
147 lhs,
148 rhs,
149 } => match (self.known(lhs), self.known(rhs)) {
150 (Some(true), _) | (_, Some(true)) => Some(true),
151 (Some(false), Some(false)) => Some(false),
152 _ => None,
153 },
154 _ => None,
155 }
156 }
157}
158
159fn single(mut nodes: Vec<Node>) -> Node {
162 if nodes.len() == 1 {
163 return nodes.pop().expect("one node");
164 }
165 Node::If(IfNode {
166 branches: vec![(
167 Expr {
168 kind: ExprKind::Literal {
169 value: Value::Bool(true),
170 },
171 ty: Type::Bool,
172 },
173 nodes,
174 )],
175 otherwise: Vec::new(),
176 })
177}
178
179impl Known {
180 fn prune_nodes(&self, nodes: &[Node]) -> Vec<Node> {
181 nodes
182 .iter()
183 .flat_map(|node| self.prune_node(node))
184 .collect()
185 }
186
187 fn prune_node(&self, node: &Node) -> Vec<Node> {
190 match node {
191 Node::Element(element) => {
192 let mut element = element.clone();
193 let tv = self.television && element.kind == "Adaptive"
194 && element.children.iter().any(|child| {
195 matches!(child, Node::Element(layout) if layout.keyword("size") == Some("tv"))
196 });
197 if tv {
198 element.children.retain(|child| {
199 matches!(child, Node::Element(layout) if layout.keyword("size") == Some("tv"))
200 });
201 }
202 element.children = self.prune_nodes(&element.children);
203 for prop in element.props.values_mut() {
204 match prop {
205 crate::Prop::Expr { expr } => self.resolve_expr(expr),
206 crate::Prop::Text {
207 text: crate::Text::Dynamic { expr },
208 } => self.resolve_expr(expr),
209 crate::Prop::Text {
210 text: crate::Text::Localized { args, .. },
211 } => {
212 for (_, expr) in args {
213 self.resolve_expr(expr);
214 }
215 }
216 crate::Prop::Query { query } => {
217 for expr in &mut query.args {
218 self.resolve_expr(expr);
219 }
220 }
221 _ => {}
222 }
223 }
224 if let Some(action) = &mut element.action {
225 match action {
226 crate::Action::Engine { args, .. } | crate::Action::Media { args, .. } => {
227 for expr in args {
228 self.resolve_expr(expr);
229 }
230 }
231 crate::Action::Session {
232 op:
233 crate::SessionOp::Set { value } | crate::SessionOp::PushStr { value },
234 ..
235 } => self.resolve_expr(value),
236 _ => {}
237 }
238 }
239 vec![Node::Element(element)]
240 }
241 Node::Component(call) => {
242 let mut call = call.clone();
243 for (_, arg) in &mut call.args {
244 if let crate::ComponentArg::Value { expr } = arg {
245 self.resolve_expr(expr);
246 }
247 }
248 vec![Node::Component(call)]
249 }
250 Node::If(condition) => {
251 let mut branches = Vec::new();
252 for (expr, body) in &condition.branches {
253 match self.known(expr) {
254 Some(true) => {
255 let body = self.prune_nodes(body);
258 if branches.is_empty() {
259 return body;
260 }
261 return vec![Node::If(IfNode {
262 branches,
263 otherwise: body,
264 })];
265 }
266 Some(false) => {}
267 None => {
268 let mut expr = expr.clone();
269 self.resolve_expr(&mut expr);
270 branches.push((expr, self.prune_nodes(body)));
271 }
272 }
273 }
274 let otherwise = self.prune_nodes(&condition.otherwise);
275 if branches.is_empty() {
276 return otherwise;
277 }
278 vec![Node::If(IfNode {
279 branches,
280 otherwise,
281 })]
282 }
283 Node::IfLet(node) => {
284 let mut node = node.clone();
285 self.resolve_expr(&mut node.value);
286 node.then = self.prune_nodes(&node.then);
287 node.otherwise = self.prune_nodes(&node.otherwise);
288 vec![Node::IfLet(node)]
289 }
290 Node::Match(node) => {
291 let mut node = node.clone();
292 self.resolve_expr(&mut node.value);
293 for arm in &mut node.arms {
294 arm.body = self.prune_nodes(&arm.body);
295 }
296 vec![Node::Match(node)]
297 }
298 }
299 }
300
301 fn resolve_expr(&self, expr: &mut Expr) {
302 if let Some(value) = self.known(expr) {
303 expr.kind = ExprKind::Literal {
304 value: Value::Bool(value),
305 };
306 return;
307 }
308 match &mut expr.kind {
309 ExprKind::If {
310 cond,
311 then,
312 otherwise,
313 } => {
314 if let Some(value) = self.known(cond) {
315 *expr = if value {
316 (**then).clone()
317 } else {
318 (**otherwise).clone()
319 };
320 self.resolve_expr(expr);
321 } else {
322 self.resolve_expr(cond);
323 self.resolve_expr(then);
324 self.resolve_expr(otherwise);
325 }
326 }
327 ExprKind::Not { expr } | ExprKind::Neg { expr } => self.resolve_expr(expr),
328 ExprKind::Binary { lhs, rhs, .. } => {
329 self.resolve_expr(lhs);
330 self.resolve_expr(rhs);
331 }
332 ExprKind::Variant { fields, .. } => {
333 for field in fields {
334 self.resolve_expr(field);
335 }
336 }
337 _ => {}
338 }
339 }
340}