tui_dispatch_core/debug/
actions.rs

1//! Debug actions and side effects
2
3/// Debug actions provided by tui-dispatch
4///
5/// These are framework-level debug actions that apps can map from their own
6/// action types via keybindings.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum DebugAction {
9    /// Toggle debug freeze mode on/off
10    Toggle,
11    /// Copy frozen frame to clipboard
12    CopyFrame,
13    /// Toggle state overlay
14    ToggleState,
15    /// Toggle mouse capture mode for cell inspection
16    ToggleMouseCapture,
17    /// Inspect cell at position (from mouse click)
18    InspectCell { column: u16, row: u16 },
19    /// Close current overlay
20    CloseOverlay,
21    /// Request a new frame capture
22    RequestCapture,
23}
24
25impl DebugAction {
26    /// Standard command names for keybinding lookup
27    pub const CMD_TOGGLE: &'static str = "debug.toggle";
28    pub const CMD_COPY_FRAME: &'static str = "debug.copy";
29    pub const CMD_TOGGLE_STATE: &'static str = "debug.state";
30    pub const CMD_TOGGLE_MOUSE: &'static str = "debug.mouse";
31    pub const CMD_CLOSE_OVERLAY: &'static str = "debug.close";
32
33    /// Try to parse a command string into a debug action
34    pub fn from_command(cmd: &str) -> Option<Self> {
35        match cmd {
36            Self::CMD_TOGGLE => Some(Self::Toggle),
37            Self::CMD_COPY_FRAME => Some(Self::CopyFrame),
38            Self::CMD_TOGGLE_STATE => Some(Self::ToggleState),
39            Self::CMD_TOGGLE_MOUSE => Some(Self::ToggleMouseCapture),
40            Self::CMD_CLOSE_OVERLAY => Some(Self::CloseOverlay),
41            _ => None,
42        }
43    }
44
45    /// Get the command string for this action
46    pub fn command(&self) -> Option<&'static str> {
47        match self {
48            Self::Toggle => Some(Self::CMD_TOGGLE),
49            Self::CopyFrame => Some(Self::CMD_COPY_FRAME),
50            Self::ToggleState => Some(Self::CMD_TOGGLE_STATE),
51            Self::ToggleMouseCapture => Some(Self::CMD_TOGGLE_MOUSE),
52            Self::CloseOverlay => Some(Self::CMD_CLOSE_OVERLAY),
53            // These don't have command strings (triggered programmatically)
54            Self::InspectCell { .. } | Self::RequestCapture => None,
55        }
56    }
57}
58
59/// Side effects that the app needs to handle after debug actions
60///
61/// The `DebugLayer` returns these when processing actions that require
62/// app-level handling (clipboard access, mouse capture mode, etc).
63#[derive(Debug)]
64pub enum DebugSideEffect<A> {
65    /// Process queued actions (when exiting debug mode)
66    ///
67    /// These actions were queued while the UI was frozen and should
68    /// now be dispatched through the normal action pipeline.
69    ProcessQueuedActions(Vec<A>),
70
71    /// Copy text to clipboard
72    ///
73    /// The app should use its preferred clipboard mechanism (OSC52, etc).
74    CopyToClipboard(String),
75
76    /// Enable terminal mouse capture
77    ///
78    /// The app should enable mouse event capture for cell inspection.
79    EnableMouseCapture,
80
81    /// Disable terminal mouse capture
82    ///
83    /// The app should disable mouse capture and return to normal mode.
84    DisableMouseCapture,
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_from_command() {
93        assert_eq!(
94            DebugAction::from_command("debug.toggle"),
95            Some(DebugAction::Toggle)
96        );
97        assert_eq!(
98            DebugAction::from_command("debug.copy"),
99            Some(DebugAction::CopyFrame)
100        );
101        assert_eq!(
102            DebugAction::from_command("debug.state"),
103            Some(DebugAction::ToggleState)
104        );
105        assert_eq!(DebugAction::from_command("unknown"), None);
106    }
107
108    #[test]
109    fn test_command_roundtrip() {
110        let actions = [
111            DebugAction::Toggle,
112            DebugAction::CopyFrame,
113            DebugAction::ToggleState,
114            DebugAction::ToggleMouseCapture,
115            DebugAction::CloseOverlay,
116        ];
117
118        for action in actions {
119            let cmd = action.command().expect("should have command");
120            let parsed = DebugAction::from_command(cmd).expect("should parse");
121            assert_eq!(parsed, action);
122        }
123    }
124}