feat: Add more /review options (#3961)

Adds the following options:

1. Review current changes
2. Review a specific commit
3. Review against a base branch (PR style)
4. Custom instructions

<img width="487" height="330" alt="Screenshot 2025-09-20 at 2 11 36 PM"
src="https://github.com/user-attachments/assets/edb0aaa5-5747-47fa-881f-cc4c4f7fe8bc"
/>

---

\+ Adds the following UI helpers:

1. Makes list selection searchable
2. Adds navigation to the bottom pane, so you could add a stack of
popups
3. Basic custom prompt view
This commit is contained in:
dedrisian-oai
2025-09-21 20:18:35 -07:00
committed by GitHub
parent a4ebd069e5
commit 5996ee0e5f
12 changed files with 1232 additions and 115 deletions

View File

@@ -20,10 +20,12 @@ mod bottom_pane_view;
mod chat_composer;
mod chat_composer_history;
mod command_popup;
pub mod custom_prompt_view;
mod file_search_popup;
mod list_selection_view;
pub(crate) use list_selection_view::SelectionViewParams;
mod paste_burst;
mod popup_consts;
pub mod popup_consts;
mod scroll_state;
mod selection_popup_common;
mod textarea;
@@ -148,10 +150,10 @@ impl BottomPane {
// status indicator shown while a task is running, or approval modal).
// In these states the textarea is not interactable, so we should not
// show its caret.
if self.active_view.is_some() {
None
let [_, content] = self.layout(area);
if let Some(view) = self.active_view.as_ref() {
view.cursor_pos(content)
} else {
let [_, content] = self.layout(area);
self.composer.cursor_pos(content)
}
}
@@ -224,7 +226,17 @@ impl BottomPane {
}
pub fn handle_paste(&mut self, pasted: String) {
if self.active_view.is_none() {
if let Some(mut view) = self.active_view.take() {
let needs_redraw = view.handle_paste(self, pasted);
if view.is_complete() {
self.on_active_view_complete();
} else {
self.active_view = Some(view);
}
if needs_redraw {
self.request_redraw();
}
} else {
let needs_redraw = self.composer.handle_paste(pasted);
if needs_redraw {
self.request_redraw();
@@ -318,22 +330,9 @@ impl BottomPane {
}
/// Show a generic list selection view with the provided items.
pub(crate) fn show_selection_view(
&mut self,
title: String,
subtitle: Option<String>,
footer_hint: Option<String>,
items: Vec<SelectionItem>,
) {
let view = list_selection_view::ListSelectionView::new(
title,
subtitle,
footer_hint,
items,
self.app_event_tx.clone(),
);
pub(crate) fn show_selection_view(&mut self, params: list_selection_view::SelectionViewParams) {
let view = list_selection_view::ListSelectionView::new(params, self.app_event_tx.clone());
self.active_view = Some(Box::new(view));
self.request_redraw();
}
/// Update the queued messages shown under the status header.
@@ -373,6 +372,11 @@ impl BottomPane {
self.request_redraw();
}
pub(crate) fn show_view(&mut self, view: Box<dyn BottomPaneView>) {
self.active_view = Some(view);
self.request_redraw();
}
/// Called when the agent requests user approval.
pub fn push_approval_request(&mut self, request: ApprovalRequest) {
let request = if let Some(view) = self.active_view.as_mut() {