Skip to main content

fret_runtime/window_command_gating/
helpers.rs

1/// Best-effort: builds a `WindowCommandGatingSnapshot` from the currently published services.
2use fret_core::AppWindowId;
3
4use crate::WindowCommandActionAvailabilityService;
5use crate::WindowCommandEnabledService;
6use crate::WindowKeyContextStackService;
7use crate::{CommandId, CommandScope, CommandsHost, GlobalsHost, InputContext};
8
9use super::{WindowCommandGatingService, WindowCommandGatingSnapshot};
10
11pub fn snapshot_for_window(
12    app: &impl GlobalsHost,
13    window: AppWindowId,
14) -> WindowCommandGatingSnapshot {
15    snapshot_for_window_with_input_ctx_fallback(app, window, InputContext::default())
16}
17
18/// Best-effort: returns a `WindowCommandGatingSnapshot` from a previously published override if
19/// present (`WindowCommandGatingService`), otherwise falls back to `snapshot_for_window`.
20pub fn best_effort_snapshot_for_window(
21    app: &impl GlobalsHost,
22    window: AppWindowId,
23) -> WindowCommandGatingSnapshot {
24    best_effort_snapshot_for_window_with_input_ctx_fallback(app, window, InputContext::default())
25}
26
27/// Best-effort: returns a `WindowCommandGatingSnapshot` from a previously published override if
28/// present (`WindowCommandGatingService`), otherwise falls back to
29/// `snapshot_for_window_with_input_ctx_fallback`.
30pub fn best_effort_snapshot_for_window_with_input_ctx_fallback(
31    app: &impl GlobalsHost,
32    window: AppWindowId,
33    fallback_input_ctx: InputContext,
34) -> WindowCommandGatingSnapshot {
35    app.global::<WindowCommandGatingService>()
36        .and_then(|svc| svc.snapshot(window))
37        .cloned()
38        .unwrap_or_else(|| {
39            snapshot_for_window_with_input_ctx_fallback(app, window, fallback_input_ctx)
40        })
41}
42
43pub fn snapshot_for_window_with_input_ctx_fallback(
44    app: &impl GlobalsHost,
45    window: AppWindowId,
46    fallback_input_ctx: InputContext,
47) -> WindowCommandGatingSnapshot {
48    let input_ctx =
49        crate::best_effort_input_context_for_window_with_fallback(app, window, fallback_input_ctx);
50
51    let enabled_overrides = app
52        .global::<WindowCommandEnabledService>()
53        .and_then(|svc| svc.snapshot(window))
54        .cloned()
55        .unwrap_or_default();
56
57    let action_availability = app
58        .global::<WindowCommandActionAvailabilityService>()
59        .and_then(|svc| svc.snapshot_arc(window));
60
61    let key_contexts: Vec<std::sync::Arc<str>> = app
62        .global::<WindowKeyContextStackService>()
63        .and_then(|svc| svc.snapshot(window))
64        .map(|v| v.to_vec())
65        .unwrap_or_default();
66
67    WindowCommandGatingSnapshot::new(input_ctx, enabled_overrides)
68        .with_action_availability(action_availability)
69        .with_key_contexts(key_contexts)
70}
71
72/// Returns whether `command` is enabled according to the best-effort window gating snapshot.
73///
74/// This is intended for cross-surface checks (OS menus, in-window menus, command palettes,
75/// shortcuts, effect filtering) that need consistent results without depending on UI internals.
76pub fn command_is_enabled_for_window_with_input_ctx_fallback(
77    app: &(impl GlobalsHost + CommandsHost),
78    window: AppWindowId,
79    command: &CommandId,
80    fallback_input_ctx: InputContext,
81) -> bool {
82    let gating =
83        best_effort_snapshot_for_window_with_input_ctx_fallback(app, window, fallback_input_ctx);
84    if let Some(meta) = app.commands().get(command.clone()) {
85        gating.is_enabled_for_command(command, meta)
86    } else {
87        gating.is_enabled_for_meta(command, CommandScope::App, None)
88    }
89}