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::config::constants::ui;
10use crate::ui::tui::session::Session;
11
12pub struct InputWidget<'a> {
27 session: &'a mut Session,
28 area: Option<Rect>,
29}
30
31impl<'a> InputWidget<'a> {
32 pub fn new(session: &'a mut Session) -> Self {
34 Self {
35 session,
36 area: None,
37 }
38 }
39
40 #[must_use]
42 pub fn area(mut self, area: Rect) -> Self {
43 self.area = Some(area);
44 self
45 }
46}
47
48impl<'a> Widget for InputWidget<'a> {
49 fn render(self, area: Rect, buf: &mut Buffer) {
50 Clear.render(area, buf);
51 if area.height == 0 {
52 return;
53 }
54
55 let mut input_area = area;
56 let mut status_area = None;
57 let mut status_line = None;
58
59 if area.height >= 2
61 && let Some(spans) = self.session.build_input_status_widget_data(area.width)
62 {
63 let block_height = area.height.saturating_sub(1).max(1);
64 input_area.height = block_height;
65 status_area = Some(Rect::new(area.x, area.y + block_height, area.width, 1));
66 status_line = Some(Line::from(spans));
67 }
68
69 let temp_data = self.session.build_input_widget_data(1, 1);
70 let block = ratatui::widgets::Block::new()
71 .style(temp_data.background_style)
72 .padding(ratatui::widgets::Padding::new(
73 ui::INLINE_INPUT_PADDING_HORIZONTAL,
74 ui::INLINE_INPUT_PADDING_HORIZONTAL,
75 ui::INLINE_INPUT_PADDING_VERTICAL,
76 ui::INLINE_INPUT_PADDING_VERTICAL,
77 ));
78 let inner = block.inner(input_area);
79 let input_data = self
80 .session
81 .build_input_widget_data(inner.width, inner.height);
82
83 let paragraph = Paragraph::new(input_data.text)
84 .style(input_data.background_style)
85 .wrap(Wrap { trim: false })
86 .block(block);
87 paragraph.render(input_area, buf);
88
89 if input_data.cursor_should_be_visible && inner.width > 0 && inner.height > 0 {
91 let cursor_x = input_data
92 .cursor_x
93 .min(inner.width.saturating_sub(1))
94 .saturating_add(inner.x);
95 let cursor_y = input_data
96 .cursor_y
97 .min(inner.height.saturating_sub(1))
98 .saturating_add(inner.y);
99
100 if let Some(cell) = buf.cell_mut((cursor_x, cursor_y)) {
101 if input_data.use_fake_cursor {
102 let mut style = cell.style();
103 style = style.add_modifier(Modifier::REVERSED);
104 cell.set_style(style);
105 if cell.symbol().is_empty() {
106 cell.set_symbol(" ");
107 }
108 } else {
109 cell.set_symbol("");
110 }
113 }
114 }
115
116 if let (Some(status_rect), Some(line)) = (status_area, status_line) {
118 let paragraph = Paragraph::new(line)
119 .style(input_data.default_style)
120 .wrap(Wrap { trim: false });
121 paragraph.render(status_rect, buf);
122 }
123 }
124}