Skip to main content

kimun_notes/components/
overlay.rs

1//! The `Overlay` trait and its supporting types — the contract every editor
2//! overlay (note browser, Saved Searches modal, or dialog) implements so the
3//! `OverlayHost` can route input / app-messages / render to it uniformly.
4
5use std::sync::Arc;
6
7use kimun_core::NoteVault;
8use ratatui::Frame;
9use ratatui::layout::Rect;
10
11use crate::components::event_state::EventState;
12use crate::components::events::{AppTx, InputEvent, OverlayData};
13use crate::components::sortable::SortableList;
14use crate::settings::themes::Theme;
15
16/// Identifies which overlay is active — used for toggle, focus label, and hints.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum OverlayKind {
19    NoteBrowser,
20    SavedSearches,
21    CommandPalette,
22    Dialog,
23}
24
25impl OverlayKind {
26    /// Footer label for this overlay kind.
27    pub fn label(&self) -> &'static str {
28        match self {
29            OverlayKind::NoteBrowser => "NOTE BROWSER",
30            OverlayKind::SavedSearches => "SAVED SEARCHES",
31            OverlayKind::CommandPalette => "COMMANDS",
32            OverlayKind::Dialog => "DIALOG",
33        }
34    }
35}
36
37/// Outcome of routing an `AppEvent` to the active overlay. Overlays never
38/// request their own dismissal here: dialogs close by emitting the
39/// `AppEvent::CloseOverlay` event, which the editor handles separately.
40#[derive(Debug)]
41pub enum OverlayMsg {
42    /// The overlay did not recognise the message.
43    NotConsumed,
44    /// The overlay handled the message and stays open.
45    Consumed,
46}
47
48// `Send` because a screen holds `Box<dyn Overlay>` and screens are `Send` (see
49// `AppScreen` in `app_screen/mod.rs`). Every overlay already satisfied it.
50pub trait Overlay: Send {
51    fn kind(&self) -> OverlayKind;
52    fn handle_input(&mut self, event: &InputEvent, tx: &AppTx) -> EventState;
53    /// Receive an **Overlay data** result addressed to this overlay (see
54    /// CONTEXT.md). `NotConsumed` means the data was not for this overlay
55    /// (or is stale) — the host drops it; nothing else ever sees it.
56    fn handle_data(
57        &mut self,
58        _data: &OverlayData,
59        _vault: &Arc<NoteVault>,
60        _tx: &AppTx,
61    ) -> OverlayMsg {
62        OverlayMsg::NotConsumed
63    }
64    fn render(&mut self, f: &mut Frame, area: Rect, theme: &Theme);
65    fn hint_shortcuts(&self) -> Vec<(String, String)> {
66        vec![]
67    }
68    /// The query string this overlay holds, if it is query-backed (the note
69    /// browser). Used by the editor's save-current-query action to source the
70    /// query from the active overlay. Defaults to `None` for non-query overlays.
71    fn query(&self) -> Option<&str> {
72        None
73    }
74    /// The saved-search name this overlay's query came from (its breadcrumb
75    /// provenance), if any. Used to pre-fill the save-search dialog's name.
76    /// Defaults to `None` for overlays without a breadcrumb.
77    fn saved_search_provenance(&self) -> Option<&str> {
78        None
79    }
80    /// This overlay as a list the sort dialog can sort, if it is one (the
81    /// Ctrl+K search browser or the Ctrl+O file finder). Drives Ctrl+R over an open overlay. Defaults
82    /// to `None`.
83    fn as_sortable(&self) -> Option<&dyn SortableList> {
84        None
85    }
86    /// Whether this overlay's input takes the query syntax (the Ctrl+K
87    /// search browser) — F1 and its `[F1]` chip then open the syntax
88    /// reference over it. Defaults to `false`.
89    fn takes_query_syntax(&self) -> bool {
90        false
91    }
92    /// Mutable twin of [`Self::as_sortable`], for applying a sort to the
93    /// overlay parked under the sort dialog.
94    fn as_sortable_mut(&mut self) -> Option<&mut dyn SortableList> {
95        None
96    }
97}