steer_tui/tui/handlers/
simple.rs1use crate::error::Result;
2use crate::tui::InputMode;
3use crate::tui::Tui;
4use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
5use std::time::Duration;
6use steer_core::app::AppCommand;
7use tui_textarea::Input;
8
9impl Tui {
10 pub async fn handle_simple_mode(&mut self, key: KeyEvent) -> Result<bool> {
11 match self.input_mode {
13 InputMode::BashCommand => return self.handle_bash_mode(key).await,
14 InputMode::AwaitingApproval => return self.handle_approval_mode(key).await,
15 InputMode::EditMessageSelection => return self.handle_edit_selection_mode(key).await,
16 InputMode::FuzzyFinder => return self.handle_fuzzy_finder_mode(key).await,
17 InputMode::ConfirmExit => return self.handle_confirm_exit_mode(key).await,
18 InputMode::Setup => return self.handle_setup_mode(key).await,
19 InputMode::Simple | InputMode::VimInsert | InputMode::VimNormal => {}
20 }
21
22 match key.code {
23 KeyCode::Esc => {
24 if self
26 .double_tap_tracker
27 .is_double_tap(KeyCode::Esc, Duration::from_millis(300))
28 {
29 let content = self.input_panel_state.content();
31 if content.is_empty() {
32 self.enter_edit_selection_mode();
34 } else {
35 self.input_panel_state.clear();
37 }
38 self.double_tap_tracker.clear_key(&KeyCode::Esc);
40 } else {
41 self.double_tap_tracker.record_key(KeyCode::Esc);
43 if self.is_processing {
44 self.client
45 .send_command(AppCommand::CancelProcessing)
46 .await?;
47 }
48 }
50 }
51
52 KeyCode::Enter
54 if key.modifiers.contains(KeyModifiers::SHIFT)
55 || key.modifiers.contains(KeyModifiers::ALT)
56 || key.modifiers.contains(KeyModifiers::CONTROL) =>
57 {
58 self.input_panel_state
59 .handle_input(Input::from(KeyEvent::new(
60 KeyCode::Char('\n'),
61 KeyModifiers::empty(),
62 )));
63 }
64
65 KeyCode::Enter => {
66 let content = self.input_panel_state.content().trim().to_string();
67 if !content.is_empty() {
68 if content.starts_with('!') && content.len() > 1 {
69 let command = content[1..].trim().to_string();
71 self.client
72 .send_command(AppCommand::ExecuteBashCommand { command })
73 .await?;
74 } else if content.starts_with('/') {
75 self.handle_slash_command(content).await?;
77 } else {
78 self.send_message(content).await?;
80 }
81 self.input_panel_state.clear();
82 }
83 }
84
85 KeyCode::Char('!') => {
86 let content = self.input_panel_state.content();
87 if content.is_empty() {
88 self.input_panel_state
90 .textarea
91 .set_placeholder_text("Enter bash command...");
92 self.switch_mode(InputMode::BashCommand);
93 } else {
94 self.input_panel_state.handle_input(Input::from(key));
96 }
97 }
98
99 KeyCode::Char('/') => {
100 let content = self.input_panel_state.content();
101 if content.is_empty() {
102 self.input_panel_state.handle_input(Input::from(key));
104 self.input_panel_state.activate_command_fuzzy();
105 self.switch_mode(InputMode::FuzzyFinder);
106
107 let results: Vec<_> = self
109 .command_registry
110 .all_commands()
111 .into_iter()
112 .map(|cmd| {
113 crate::tui::widgets::fuzzy_finder::PickerItem::new(
114 cmd.name.to_string(),
115 format!("/{} ", cmd.name),
116 )
117 })
118 .collect();
119 self.input_panel_state.fuzzy_finder.update_results(results);
120 } else {
121 self.input_panel_state.handle_input(Input::from(key));
123 }
124 }
125
126 KeyCode::Char('@') => {
127 self.input_panel_state.handle_input(Input::from(key));
129 self.input_panel_state.activate_fuzzy();
130 self.switch_mode(InputMode::FuzzyFinder);
131
132 let file_results = self
134 .input_panel_state
135 .file_cache()
136 .fuzzy_search("", Some(20))
137 .await;
138 let picker_items: Vec<_> = file_results
139 .into_iter()
140 .map(|path| {
141 crate::tui::widgets::fuzzy_finder::PickerItem::new(
142 path.clone(),
143 format!("@{path} "),
144 )
145 })
146 .collect();
147 self.input_panel_state
148 .fuzzy_finder
149 .update_results(picker_items);
150 }
151
152 KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => {
153 if self.is_processing {
154 self.client
155 .send_command(AppCommand::CancelProcessing)
156 .await?;
157 } else {
158 self.switch_mode(InputMode::ConfirmExit);
159 }
160 }
161
162 KeyCode::Char('r') if key.modifiers.contains(KeyModifiers::CONTROL) => {
164 self.chat_viewport.state_mut().toggle_view_mode();
165 }
166
167 _ => {
168 if self.handle_text_manipulation(key)? {
170 return Ok(false);
171 }
172
173 self.input_panel_state.handle_input(Input::from(key));
175
176 if self.input_panel_state.content().is_empty() {
178 self.input_panel_state
179 .textarea
180 .set_placeholder_text("Type your message here...");
181 }
182 }
183 }
184
185 Ok(false)
186 }
187}