Skip to main content

fresh/view/
query_replace_input.rs

1//! Input handler for query-replace confirmation prompts.
2//!
3//! This handler routes character input to the interactive replace system
4//! instead of inserting it into a prompt buffer.
5
6use crate::input::handler::{DeferredAction, InputContext, InputHandler, InputResult};
7use crossterm::event::{KeyCode, KeyEvent};
8
9/// Input handler for QueryReplaceConfirm prompts.
10///
11/// This is a simple modal handler that:
12/// - Routes character keys (y/n/a/q/!) to the interactive replace handler
13/// - Handles Escape to cancel
14/// - Consumes all other keys to maintain modal behavior
15pub struct QueryReplaceConfirmInputHandler;
16
17impl QueryReplaceConfirmInputHandler {
18    pub fn new() -> Self {
19        Self
20    }
21}
22
23impl Default for QueryReplaceConfirmInputHandler {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl InputHandler for QueryReplaceConfirmInputHandler {
30    fn handle_key_event(&mut self, event: &KeyEvent, ctx: &mut InputContext) -> InputResult {
31        match event.code {
32            // Character input goes to interactive replace handler
33            KeyCode::Char(c) => {
34                ctx.defer(DeferredAction::InteractiveReplaceKey(c));
35                InputResult::Consumed
36            }
37            // Escape cancels the operation
38            KeyCode::Esc => {
39                ctx.defer(DeferredAction::CancelInteractiveReplace);
40                InputResult::Consumed
41            }
42            // Consume all other keys for modal behavior
43            _ => InputResult::Consumed,
44        }
45    }
46
47    fn is_modal(&self) -> bool {
48        true
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use crossterm::event::KeyModifiers;
56
57    fn key(code: KeyCode) -> KeyEvent {
58        KeyEvent::new(code, KeyModifiers::NONE)
59    }
60
61    #[test]
62    fn test_character_keys_defer_to_handler() {
63        let mut handler = QueryReplaceConfirmInputHandler::new();
64        let mut ctx = InputContext::new();
65
66        let result = handler.handle_key_event(&key(KeyCode::Char('y')), &mut ctx);
67        assert!(matches!(result, InputResult::Consumed));
68        assert_eq!(ctx.deferred_actions.len(), 1);
69        assert!(matches!(
70            ctx.deferred_actions[0],
71            DeferredAction::InteractiveReplaceKey('y')
72        ));
73    }
74
75    #[test]
76    fn test_escape_cancels() {
77        let mut handler = QueryReplaceConfirmInputHandler::new();
78        let mut ctx = InputContext::new();
79
80        let result = handler.handle_key_event(&key(KeyCode::Esc), &mut ctx);
81        assert!(matches!(result, InputResult::Consumed));
82        assert_eq!(ctx.deferred_actions.len(), 1);
83        assert!(matches!(
84            ctx.deferred_actions[0],
85            DeferredAction::CancelInteractiveReplace
86        ));
87    }
88
89    #[test]
90    fn test_other_keys_consumed() {
91        let mut handler = QueryReplaceConfirmInputHandler::new();
92        let mut ctx = InputContext::new();
93
94        let result = handler.handle_key_event(&key(KeyCode::Enter), &mut ctx);
95        assert!(matches!(result, InputResult::Consumed));
96        assert!(ctx.deferred_actions.is_empty());
97
98        let result = handler.handle_key_event(&key(KeyCode::Up), &mut ctx);
99        assert!(matches!(result, InputResult::Consumed));
100        assert!(ctx.deferred_actions.is_empty());
101    }
102
103    #[test]
104    fn test_is_modal() {
105        let handler = QueryReplaceConfirmInputHandler::new();
106        assert!(handler.is_modal());
107    }
108}