vtcode_ui/tui/core_tui/widgets/
input.rs1use ratatui::{
2 buffer::Buffer,
3 layout::Rect,
4 style::Modifier,
5 text::Line,
6 widgets::{Clear, Paragraph, Widget, Wrap},
7};
8
9use crate::tui::ui::tui::session::Session;
10
11pub struct InputWidget<'a> {
26 session: &'a mut Session,
27 area: Option<Rect>,
28}
29
30impl<'a> InputWidget<'a> {
31 pub fn new(session: &'a mut Session) -> Self {
33 Self { session, area: None }
34 }
35
36 #[must_use]
38 pub fn area(mut self, area: Rect) -> Self {
39 self.area = Some(area);
40 self
41 }
42}
43
44impl<'a> Widget for InputWidget<'a> {
45 fn render(self, area: Rect, buf: &mut Buffer) {
46 Clear.render(area, buf);
47 if area.height == 0 {
48 return;
49 }
50
51 let mut input_area = area;
52 let mut status_area = None;
53 let mut status_line = None;
54
55 if area.height >= 2
57 && let Some(spans) = self.session.build_input_status_widget_data(area.width)
58 {
59 let block_height = area.height.saturating_sub(1).max(1);
60 input_area.height = block_height;
61 status_area = Some(Rect::new(area.x, area.y + block_height, area.width, 1));
62 status_line = Some(Line::from(spans));
63 }
64
65 let temp_data = self.session.build_input_widget_data(1, 1);
66 let shell_mode_title = self.session.shell_mode_border_title();
67 let mut block = if shell_mode_title.is_some() {
68 ratatui::widgets::Block::bordered()
69 } else {
70 ratatui::widgets::Block::new()
71 };
72 block = block
73 .style(temp_data.background_style)
74 .padding(self.session.input_block_padding());
75 if let Some(title) = shell_mode_title {
76 block = block
77 .title(title)
78 .border_type(crate::tui::ui::tui::session::terminal_capabilities::get_border_type())
79 .border_style(self.session.styles.accent_style().add_modifier(Modifier::BOLD));
80 }
81 let inner = block.inner(input_area);
82 let input_data = self.session.build_input_widget_data(inner.width, inner.height);
83
84 let paragraph = Paragraph::new(input_data.text)
85 .style(input_data.background_style)
86 .wrap(Wrap { trim: false })
87 .block(block);
88 paragraph.render(input_area, buf);
89
90 if input_data.cursor_should_be_visible && inner.width > 0 && inner.height > 0 {
92 let cursor_x = input_data.cursor_x.min(inner.width.saturating_sub(1)).saturating_add(inner.x);
93 let cursor_y = input_data.cursor_y.min(inner.height.saturating_sub(1)).saturating_add(inner.y);
94
95 if let Some(cell) = buf.cell_mut((cursor_x, cursor_y)) {
96 if input_data.use_fake_cursor {
97 let mut style = cell.style();
98 style = style.add_modifier(Modifier::REVERSED);
99 cell.set_style(style);
100 if cell.symbol().is_empty() {
101 cell.set_symbol(" ");
102 }
103 } else {
104 cell.set_symbol("");
105 }
108 }
109 }
110
111 if let (Some(status_rect), Some(line)) = (status_area, status_line) {
113 let paragraph = Paragraph::new(line).style(input_data.default_style).wrap(Wrap { trim: false });
114 paragraph.render(status_rect, buf);
115 }
116 }
117}