1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use crate::tui_internal::app::app_server_requests::ResolvedAppServerRequest;
use crate::tui_internal::bottom_pane::ApprovalRequest;
use crate::tui_internal::bottom_pane::McpServerElicitationFormRequest;
use crate::tui_internal::render::renderable::Renderable;
use lemurclaw_core::app_server_protocol::ToolRequestUserInputParams;
use crossterm::event::KeyEvent;
use std::time::Instant;
use super::CancellationEvent;
/// Reason an active bottom-pane view finished.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ViewCompletion {
Accepted,
Cancelled,
}
/// Trait implemented by every view that can be shown in the bottom pane.
pub(crate) trait BottomPaneView: Renderable {
/// Handle a key event while the view is active. A redraw is always
/// scheduled after this call.
fn handle_key_event(&mut self, _key_event: KeyEvent) {}
/// Return `true` if the view has finished and should be removed.
fn is_complete(&self) -> bool {
false
}
/// Return the completion reason once the view has finished.
fn completion(&self) -> Option<ViewCompletion> {
None
}
/// Return true when this view should be removed after a child view is accepted.
fn dismiss_after_child_accept(&self) -> bool {
false
}
/// Clear any pending child-flow cleanup marker after a child view is cancelled.
fn clear_dismiss_after_child_accept(&mut self) {}
/// Stable identifier for views that need external refreshes while open.
fn view_id(&self) -> Option<&'static str> {
None
}
/// Actual item index for list-based views that want to preserve selection
/// across external refreshes.
fn selected_index(&self) -> Option<usize> {
None
}
/// Active tab id for tabbed list-based views.
#[allow(dead_code)]
fn active_tab_id(&self) -> Option<&str> {
None
}
/// Handle Ctrl-C while this view is active.
fn on_ctrl_c(&mut self) -> CancellationEvent {
CancellationEvent::NotHandled
}
/// Return true if Esc should be routed through `handle_key_event` instead
/// of the `on_ctrl_c` cancellation path.
fn prefer_esc_to_handle_key_event(&self) -> bool {
false
}
/// Return true when this key event will interrupt the active agent turn.
fn will_interrupt_turn_on_key_event(&self, _key_event: KeyEvent) -> bool {
false
}
/// Optional paste handler. Return true if the view modified its state and
/// needs a redraw.
fn handle_paste(&mut self, _pasted: String) -> bool {
false
}
/// Flush any pending paste-burst state. Return true if state changed.
///
/// This lets a modal that reuses `ChatComposer` participate in the same
/// time-based paste burst flushing as the primary composer.
fn flush_paste_burst_if_due(&mut self) -> bool {
false
}
/// Whether the view is currently holding paste-burst transient state.
///
/// When `true`, the bottom pane will schedule a short delayed redraw to
/// give the burst time window a chance to flush.
fn is_in_paste_burst(&self) -> bool {
false
}
/// Process time-based state immediately before rendering.
///
/// Return true when state changed and the bottom pane should redraw or
/// complete the active view.
fn pre_draw_tick(&mut self, _now: Instant) -> bool {
false
}
/// Try to handle approval request; return the original value if not
/// consumed.
fn try_consume_approval_request(
&mut self,
request: ApprovalRequest,
) -> Option<ApprovalRequest> {
Some(request)
}
/// Try to handle request_user_input; return the original value if not
/// consumed.
fn try_consume_user_input_request(
&mut self,
request: ToolRequestUserInputParams,
) -> Option<ToolRequestUserInputParams> {
Some(request)
}
/// Try to handle a supported MCP server elicitation form request; return the original value if
/// not consumed.
fn try_consume_mcp_server_elicitation_request(
&mut self,
request: McpServerElicitationFormRequest,
) -> Option<McpServerElicitationFormRequest> {
Some(request)
}
/// Dismiss a request that was resolved by another client.
///
/// Returns `true` when the view changed state.
fn dismiss_app_server_request(&mut self, _request: &ResolvedAppServerRequest) -> bool {
false
}
/// Whether this view means the session is blocked waiting for the user.
///
/// Views that return `true` surface an "Action Required" terminal title
/// instead of the normal working spinner so terminal tabs clearly show that
/// Codex needs user input.
fn terminal_title_requires_action(&self) -> bool {
false
}
/// Return the next time-based redraw this view needs while it is active.
fn next_frame_delay(&self) -> Option<std::time::Duration> {
None
}
}