vtcode_tui/core_tui/session/
impl_events.rs1use super::*;
2
3impl Session {
4 pub fn handle_event(
5 &mut self,
6 event: CrosstermEvent,
7 events: &UnboundedSender<InlineEvent>,
8 callback: Option<&(dyn Fn(&InlineEvent) + Send + Sync + 'static)>,
9 ) {
10 match event {
11 CrosstermEvent::Key(key) => {
12 if matches!(key.kind, KeyEventKind::Press)
15 && let Some(outbound) = events::process_key(self, key)
16 {
17 self.emit_inline_event(&outbound, events, callback);
18 }
19 }
20 CrosstermEvent::Mouse(mouse_event) => match mouse_event.kind {
21 MouseEventKind::ScrollDown => {
22 if self.history_picker_state.active {
24 self.history_picker_state.move_down();
25 self.mark_dirty();
26 } else {
27 self.scroll_line_down();
28 self.mark_dirty();
29 }
30 }
31 MouseEventKind::ScrollUp => {
32 if self.history_picker_state.active {
34 self.history_picker_state.move_up();
35 self.mark_dirty();
36 } else {
37 self.scroll_line_up();
38 self.mark_dirty();
39 }
40 }
41 MouseEventKind::Down(ratatui::crossterm::event::MouseButton::Left) => {
42 self.mouse_selection
44 .start_selection(mouse_event.column, mouse_event.row);
45 self.mark_dirty();
46 if !self.handle_input_click(mouse_event) {
47 self.handle_transcript_click(mouse_event);
48 }
49 }
50 MouseEventKind::Drag(ratatui::crossterm::event::MouseButton::Left) => {
51 self.mouse_selection
52 .update_selection(mouse_event.column, mouse_event.row);
53 self.mark_dirty();
54 }
55 MouseEventKind::Up(ratatui::crossterm::event::MouseButton::Left) => {
56 self.mouse_selection
57 .finish_selection(mouse_event.column, mouse_event.row);
58 self.mark_dirty();
59 }
60 _ => {}
61 },
62 CrosstermEvent::Paste(content) => {
63 if self.input_enabled {
64 self.insert_paste_text(&content);
65 self.check_file_reference_trigger();
66 self.mark_dirty();
67 } else if let Some(modal) = self.modal.as_mut()
68 && let (Some(list), Some(search)) = (modal.list.as_mut(), modal.search.as_mut())
69 {
70 search.insert(&content);
71 list.apply_search(&search.query);
72 self.mark_dirty();
73 }
74 }
75 CrosstermEvent::Resize(_, rows) => {
76 self.apply_view_rows(rows);
77 self.mark_dirty();
78 }
79 CrosstermEvent::FocusGained => {
80 }
82 CrosstermEvent::FocusLost => {
83 }
85 }
86 }
87
88 pub(crate) fn handle_transcript_click(&mut self, mouse_event: MouseEvent) -> bool {
89 if !matches!(
90 mouse_event.kind,
91 MouseEventKind::Down(ratatui::crossterm::event::MouseButton::Left)
92 ) {
93 return false;
94 }
95
96 let Some(area) = self.transcript_area else {
97 return false;
98 };
99
100 if mouse_event.row < area.y
101 || mouse_event.row >= area.y.saturating_add(area.height)
102 || mouse_event.column < area.x
103 || mouse_event.column >= area.x.saturating_add(area.width)
104 {
105 return false;
106 }
107
108 if self.transcript_width == 0 || self.transcript_rows == 0 {
109 return false;
110 }
111
112 let row_in_view = (mouse_event.row - area.y) as usize;
113 if row_in_view >= self.transcript_rows as usize {
114 return false;
115 }
116
117 let viewport_rows = self.transcript_rows.max(1) as usize;
118 let padding = usize::from(ui::INLINE_TRANSCRIPT_BOTTOM_PADDING);
119 let effective_padding = padding.min(viewport_rows.saturating_sub(1));
120 let total_rows = self.total_transcript_rows(self.transcript_width) + effective_padding;
121 let (top_offset, _clamped_total_rows) =
122 self.prepare_transcript_scroll(total_rows, viewport_rows);
123 let view_top = top_offset.min(self.scroll_manager.max_offset());
124 self.transcript_view_top = view_top;
125
126 let clicked_row = view_top.saturating_add(row_in_view);
127 let expanded = self.expand_collapsed_paste_at_row(self.transcript_width, clicked_row);
128 if expanded {
129 self.mark_dirty();
130 }
131 expanded
132 }
133
134 pub(crate) fn handle_input_click(&mut self, mouse_event: MouseEvent) -> bool {
135 if !matches!(
136 mouse_event.kind,
137 MouseEventKind::Down(ratatui::crossterm::event::MouseButton::Left)
138 ) {
139 return false;
140 }
141
142 let Some(area) = self.input_area else {
143 return false;
144 };
145
146 if mouse_event.row < area.y
147 || mouse_event.row >= area.y.saturating_add(area.height)
148 || mouse_event.column < area.x
149 || mouse_event.column >= area.x.saturating_add(area.width)
150 {
151 return false;
152 }
153
154 let cursor_at_end = self.input_manager.cursor() == self.input_manager.content().len();
155 if !self.input_compact_mode || !cursor_at_end {
156 return false;
157 }
158
159 if self.input_compact_placeholder().is_none() {
160 return false;
161 }
162
163 self.input_compact_mode = false;
164 self.mark_dirty();
165 true
166 }
167}