Skip to content

Commit a296b9d

Browse files
echobtfactorydroid
andauthored
fix(tui): enable paste in MCP server configuration modal (#276)
Previously, when adding an MCP server (HTTP or stdio) or setting API keys, users could not paste text into the input fields. This was because the paste event (EngineEvent::Paste) was only routed to Form modals and the main input widget, not to the unified modal stack that includes the MCP manager modal. Changes: - Add handle_paste method to the Modal trait with default no-op impl - Add handle_paste method to ModalStack to delegate to top modal - Implement handle_paste in McpManagerModal for all text input modes: - AddStdioServer (name, command, args fields) - AddHttpServer (name, url fields) - SetAuth (api_key field) - SelectFromRegistry (search_query field) - Update event loop to check modal_stack for paste events first Co-authored-by: Droid Agent <droid@factory.ai>
1 parent 3be8563 commit a296b9d

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

cortex-tui/src/modal/mcp_manager.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,46 @@ impl Modal for McpManagerModal {
14161416
"MCP Servers"
14171417
}
14181418

1419+
fn handle_paste(&mut self, text: &str) -> bool {
1420+
match &mut self.mode {
1421+
McpMode::AddStdioServer {
1422+
name,
1423+
command,
1424+
args,
1425+
focus,
1426+
} => {
1427+
match focus {
1428+
AddStdioServerFocus::Name => name.push_str(text),
1429+
AddStdioServerFocus::Command => command.push_str(text),
1430+
AddStdioServerFocus::Args => args.push_str(text),
1431+
}
1432+
true
1433+
}
1434+
McpMode::AddHttpServer { name, url, focus } => {
1435+
match focus {
1436+
AddHttpServerFocus::Name => name.push_str(text),
1437+
AddHttpServerFocus::Url => url.push_str(text),
1438+
}
1439+
true
1440+
}
1441+
McpMode::SetAuth {
1442+
server_name: _,
1443+
api_key,
1444+
} => {
1445+
api_key.push_str(text);
1446+
true
1447+
}
1448+
McpMode::SelectFromRegistry {
1449+
selected: _,
1450+
search_query,
1451+
} => {
1452+
search_query.push_str(text);
1453+
true
1454+
}
1455+
_ => false,
1456+
}
1457+
}
1458+
14191459
fn desired_height(&self, max_height: u16, _width: u16) -> u16 {
14201460
match &self.mode {
14211461
McpMode::List => {

cortex-tui/src/modal/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ pub trait Modal: Send {
5757
/// Handle a key event, returning the result
5858
fn handle_key(&mut self, key: KeyEvent) -> ModalResult;
5959

60+
/// Handle pasted text. Returns true if the paste was handled.
61+
/// Default implementation does nothing.
62+
fn handle_paste(&mut self, _text: &str) -> bool {
63+
false
64+
}
65+
6066
/// Key hints to display at the bottom
6167
fn key_hints(&self) -> Vec<(&'static str, &'static str)>;
6268

@@ -243,6 +249,16 @@ impl ModalStack {
243249
}
244250
}
245251

252+
/// Handle pasted text, delegating to the top modal
253+
/// Returns true if the paste was handled
254+
pub fn handle_paste(&mut self, text: &str) -> bool {
255+
if let Some(modal) = self.current_mut() {
256+
modal.handle_paste(text)
257+
} else {
258+
false
259+
}
260+
}
261+
246262
/// Clear all modals from the stack
247263
pub fn clear(&mut self) {
248264
self.stack.clear();

cortex-tui/src/runner/event_loop.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,10 +1672,13 @@ impl EventLoop {
16721672
}
16731673

16741674
EngineEvent::Paste(text) => {
1675-
// Check if a form modal is active and route paste to it
1676-
if let Some(crate::app::ActiveModal::Form(ref mut form_state)) =
1675+
// Check modal stack first (unified modal system)
1676+
if self.modal_stack.is_active() && self.modal_stack.handle_paste(&text) {
1677+
// Paste was handled by modal
1678+
} else if let Some(crate::app::ActiveModal::Form(ref mut form_state)) =
16771679
self.app_state.active_modal
16781680
{
1681+
// Check if a form modal is active and route paste to it
16791682
form_state.handle_paste(&text);
16801683
} else {
16811684
// Otherwise insert pasted text into the main input widget

0 commit comments

Comments
 (0)