vtcode_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::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 {
34 session,
35 area: None,
36 }
37 }
38
39 #[must_use]
41 pub fn area(mut self, area: Rect) -> Self {
42 self.area = Some(area);
43 self
44 }
45}
46
47impl<'a> Widget for InputWidget<'a> {
48 fn render(self, area: Rect, buf: &mut Buffer) {
49 Clear.render(area, buf);
50 if area.height == 0 {
51 return;
52 }
53
54 let mut input_area = area;
55 let mut status_area = None;
56 let mut status_line = None;
57
58 if area.height >= 2
60 && let Some(spans) = self.session.build_input_status_widget_data(area.width)
61 {
62 let block_height = area.height.saturating_sub(1).max(1);
63 input_area.height = block_height;
64 status_area = Some(Rect::new(area.x, area.y + block_height, area.width, 1));
65 status_line = Some(Line::from(spans));
66 }
67
68 let temp_data = self.session.build_input_widget_data(1, 1);
69 let shell_mode_title = self.session.shell_mode_border_title();
70 let mut block = if shell_mode_title.is_some() {
71 ratatui::widgets::Block::bordered()
72 } else {
73 ratatui::widgets::Block::new()
74 };
75 block = block
76 .style(temp_data.background_style)
77 .padding(self.session.input_block_padding());
78 if let Some(title) = shell_mode_title {
79 block = block
80 .title(title)
81 .border_type(crate::ui::tui::session::terminal_capabilities::get_border_type())
82 .border_style(
83 self.session
84 .styles
85 .accent_style()
86 .add_modifier(Modifier::BOLD),
87 );
88 }
89 let inner = block.inner(input_area);
90 let input_data = self
91 .session
92 .build_input_widget_data(inner.width, inner.height);
93
94 let paragraph = Paragraph::new(input_data.text)
95 .style(input_data.background_style)
96 .wrap(Wrap { trim: false })
97 .block(block);
98 paragraph.render(input_area, buf);
99
100 if input_data.cursor_should_be_visible && inner.width > 0 && inner.height > 0 {
102 let cursor_x = input_data
103 .cursor_x
104 .min(inner.width.saturating_sub(1))
105 .saturating_add(inner.x);
106 let cursor_y = input_data
107 .cursor_y
108 .min(inner.height.saturating_sub(1))
109 .saturating_add(inner.y);
110
111 if let Some(cell) = buf.cell_mut((cursor_x, cursor_y)) {
112 if input_data.use_fake_cursor {
113 let mut style = cell.style();
114 style = style.add_modifier(Modifier::REVERSED);
115 cell.set_style(style);
116 if cell.symbol().is_empty() {
117 cell.set_symbol(" ");
118 }
119 } else {
120 cell.set_symbol("");
121 }
124 }
125 }
126
127 if let (Some(status_rect), Some(line)) = (status_area, status_line) {
129 let paragraph = Paragraph::new(line)
130 .style(input_data.default_style)
131 .wrap(Wrap { trim: false });
132 paragraph.render(status_rect, buf);
133 }
134 }
135}