feat: Ctrl+J for newline in Rust TUI, default to one line of height (#926)
While the `TextArea` used in the Rust TUI is "multiline," it is not like an HTML `<textarea>` in that it does not wrap, so there was not much benefit to setting `MIN_TEXTAREA_ROWS` to `3`, so this PR changes it to `1`. Though there are now three ways to "increase" the height due to actual linebreaks: * paste in multiline content (this worked before this PR) * pressing `Ctrl+J` will insert a newline * if you have your terminal emulator set such that it is possible to press something that `crossterm` interprets as "Enter plus some modifier," then now that will also work Now things look a bit more compact on startup: <img width="745" alt="image" src="https://github.com/user-attachments/assets/86e2857f-f31c-46f5-a80b-1ab2120b266e" />
This commit is contained in:
@@ -29,7 +29,7 @@ use crate::user_approval_widget::ApprovalRequest;
|
||||
use crate::user_approval_widget::UserApprovalWidget;
|
||||
|
||||
/// Minimum number of visible text rows inside the textarea.
|
||||
const MIN_TEXTAREA_ROWS: usize = 3;
|
||||
const MIN_TEXTAREA_ROWS: usize = 1;
|
||||
/// Number of terminal rows consumed by the textarea border (top + bottom).
|
||||
const TEXTAREA_BORDER_LINES: u16 = 2;
|
||||
|
||||
@@ -176,6 +176,24 @@ impl<'a> BottomPane<'a> {
|
||||
self.request_redraw()?;
|
||||
Ok(InputResult::Submitted(text))
|
||||
}
|
||||
Input {
|
||||
key: Key::Enter, ..
|
||||
}
|
||||
| Input {
|
||||
key: Key::Char('j'),
|
||||
ctrl: true,
|
||||
alt: false,
|
||||
shift: false,
|
||||
} => {
|
||||
// If the user has their terminal emulator configured so
|
||||
// Enter+Shift (or any modifier) sends a different key
|
||||
// event, we should let them insert a newline.
|
||||
//
|
||||
// We also allow Ctrl+J to insert a newline.
|
||||
self.textarea.insert_newline();
|
||||
self.request_redraw()?;
|
||||
Ok(InputResult::None)
|
||||
}
|
||||
input => {
|
||||
self.textarea.input(input);
|
||||
self.request_redraw()?;
|
||||
@@ -284,7 +302,6 @@ impl WidgetRef for &BottomPane<'_> {
|
||||
// for all variants of PaneState.
|
||||
fn update_border_for_input_focus(textarea: &mut TextArea, state: &PaneState, has_focus: bool) {
|
||||
struct BlockState {
|
||||
title: &'static str,
|
||||
right_title: Line<'static>,
|
||||
border_style: Style,
|
||||
}
|
||||
@@ -297,26 +314,23 @@ fn update_border_for_input_focus(textarea: &mut TextArea, state: &PaneState, has
|
||||
|
||||
let block_state = if has_focus && accepting_input {
|
||||
BlockState {
|
||||
title: "use Enter to send for now (Ctrl-D to quit)",
|
||||
right_title: Line::from("press enter to send").alignment(Alignment::Right),
|
||||
right_title: Line::from("Enter to send | Ctrl+D to quit | Ctrl+J for newline")
|
||||
.alignment(Alignment::Right),
|
||||
border_style: Style::default(),
|
||||
}
|
||||
} else {
|
||||
BlockState {
|
||||
title: "",
|
||||
right_title: Line::from(""),
|
||||
border_style: Style::default().dim(),
|
||||
}
|
||||
};
|
||||
|
||||
let BlockState {
|
||||
title,
|
||||
right_title,
|
||||
border_style,
|
||||
} = block_state;
|
||||
textarea.set_block(
|
||||
ratatui::widgets::Block::default()
|
||||
.title_bottom(title)
|
||||
.title_bottom(right_title)
|
||||
.borders(ratatui::widgets::Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
|
||||
Reference in New Issue
Block a user