feat(tui): add Ctrl+↑/↓ shortcuts to resize chat/thinking split

- Update help UI to show “Ctrl+↑/↓ → resize chat/thinking split”.
- Introduce `ensure_ratio_bounds` and `nudge_ratio` on `LayoutNode` to clamp and adjust split ratios.
- Ensure vertical split favors the thinking panel when it becomes focused.
- Add `adjust_vertical_split` method in `ChatApp` and handle Ctrl+↑/↓ in normal mode to modify the split and update status messages.
This commit is contained in:
2025-10-13 22:23:36 +02:00
parent 3e4eacd1d3
commit 825dfc0722
3 changed files with 64 additions and 0 deletions

View File

@@ -2407,6 +2407,12 @@ impl ChatApp {
} else if !order.contains(&self.focused_panel) {
self.focused_panel = order[0];
}
if let FocusedPanel::Thinking = self.focused_panel {
// Ensure the vertical split favours thinking panel if chat collapsed entirely
if let Some(tab) = self.workspace_mut().active_tab_mut() {
tab.root.ensure_ratio_bounds();
}
}
}
pub fn cycle_focus_forward(&mut self) {
@@ -2461,6 +2467,12 @@ impl ChatApp {
configure_textarea_defaults(&mut self.textarea);
}
pub fn adjust_vertical_split(&mut self, delta: f32) {
if let Some(tab) = self.workspace_mut().active_tab_mut() {
tab.root.nudge_ratio(delta);
}
}
async fn process_slash_submission(&mut self) -> Result<SlashOutcome> {
let raw = self.controller.input_buffer().text().to_string();
if raw.trim().is_empty() {
@@ -4169,6 +4181,16 @@ impl ChatApp {
key.code,
KeyCode::Right | KeyCode::Char('l') | KeyCode::Char('L')
);
let is_resize_up = key.modifiers.contains(KeyModifiers::CONTROL)
&& matches!(
key.code,
KeyCode::Up | KeyCode::Char('k') | KeyCode::Char('K')
);
let is_resize_down = key.modifiers.contains(KeyModifiers::CONTROL)
&& matches!(
key.code,
KeyCode::Down | KeyCode::Char('j') | KeyCode::Char('J')
);
if is_reveal_active && matches!(self.mode, InputMode::Normal) {
self.reveal_active_file();
@@ -4208,6 +4230,21 @@ impl ChatApp {
return Ok(AppState::Running);
}
if (is_resize_up || is_resize_down) && matches!(self.mode, InputMode::Normal) {
let delta = if is_resize_up { -0.05 } else { 0.05 };
self.adjust_vertical_split(delta);
self.status = format!(
"Vertical split adjusted ({})",
if delta.is_sign_positive() {
"down"
} else {
"up"
}
);
self.error = None;
return Ok(AppState::Running);
}
if is_symbol_search_key && matches!(self.mode, InputMode::Normal) {
self.set_input_mode(InputMode::SymbolSearch);
self.symbol_search.clear_query();

View File

@@ -85,6 +85,31 @@ pub enum LayoutNode {
}
impl LayoutNode {
pub fn ensure_ratio_bounds(&mut self) {
match self {
LayoutNode::Split {
ratio,
first,
second,
..
} => {
*ratio = ratio.clamp(0.1, 0.9);
first.ensure_ratio_bounds();
second.ensure_ratio_bounds();
}
LayoutNode::Leaf(_) => {}
}
}
pub fn nudge_ratio(&mut self, delta: f32) {
match self {
LayoutNode::Split { ratio, .. } => {
*ratio = (*ratio + delta).clamp(0.1, 0.9);
}
LayoutNode::Leaf(_) => {}
}
}
fn replace_leaf(&mut self, target: PaneId, replacement: LayoutNode) -> bool {
match self {
LayoutNode::Leaf(id) => {

View File

@@ -3070,6 +3070,7 @@ fn render_help(frame: &mut Frame<'_>, app: &ChatApp) {
Line::from(" :h, :help → open help from command mode"),
Line::from(" :files, :explorer → toggle files panel"),
Line::from(" Ctrl+←/→ → resize files panel"),
Line::from(" Ctrl+↑/↓ → resize chat/thinking split"),
],
1 => vec![
// Editing
@@ -3183,6 +3184,7 @@ fn render_help(frame: &mut Frame<'_>, app: &ChatApp) {
Line::from(" F1 or ? → toggle help overlay"),
Line::from(" :files, :explorer → toggle files panel"),
Line::from(" Ctrl+←/→ → resize files panel"),
Line::from(" Ctrl+↑/↓ → resize chat/thinking split"),
Line::from(" :quit → quit application"),
Line::from(" Ctrl+C twice → quit application"),
Line::from(" :reload → reload configuration and themes"),