Format multiline commands (#2333)
<img width="966" height="729" alt="image" src="https://github.com/user-attachments/assets/fa45b7e1-cd46-427f-b2bc-8501e9e4760b" /> <img width="797" height="530" alt="image" src="https://github.com/user-attachments/assets/6993eec5-e157-4df7-b558-15643ad10d64" />
This commit is contained in:
@@ -43,7 +43,6 @@ use crate::bottom_pane::BottomPane;
|
|||||||
use crate::bottom_pane::BottomPaneParams;
|
use crate::bottom_pane::BottomPaneParams;
|
||||||
use crate::bottom_pane::CancellationEvent;
|
use crate::bottom_pane::CancellationEvent;
|
||||||
use crate::bottom_pane::InputResult;
|
use crate::bottom_pane::InputResult;
|
||||||
use crate::exec_command::strip_bash_lc_and_escape;
|
|
||||||
use crate::history_cell;
|
use crate::history_cell;
|
||||||
use crate::history_cell::CommandOutput;
|
use crate::history_cell::CommandOutput;
|
||||||
use crate::history_cell::ExecCell;
|
use crate::history_cell::ExecCell;
|
||||||
@@ -391,17 +390,6 @@ impl ChatWidget<'_> {
|
|||||||
|
|
||||||
pub(crate) fn handle_exec_approval_now(&mut self, id: String, ev: ExecApprovalRequestEvent) {
|
pub(crate) fn handle_exec_approval_now(&mut self, id: String, ev: ExecApprovalRequestEvent) {
|
||||||
self.flush_answer_stream_with_separator();
|
self.flush_answer_stream_with_separator();
|
||||||
// Log a background summary immediately so the history is chronological.
|
|
||||||
let cmdline = strip_bash_lc_and_escape(&ev.command);
|
|
||||||
let text = format!(
|
|
||||||
"command requires approval:\n$ {cmdline}{reason}",
|
|
||||||
reason = ev
|
|
||||||
.reason
|
|
||||||
.as_ref()
|
|
||||||
.map(|r| format!("\n{r}"))
|
|
||||||
.unwrap_or_default()
|
|
||||||
);
|
|
||||||
self.add_to_history(&history_cell::new_background_event(text));
|
|
||||||
|
|
||||||
let request = ApprovalRequest::Exec {
|
let request = ApprovalRequest::Exec {
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -136,14 +136,6 @@ fn pretty_provider_name(id: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_background_event(message: String) -> PlainHistoryCell {
|
|
||||||
let mut lines: Vec<Line<'static>> = Vec::new();
|
|
||||||
lines.push(Line::from("event".dim()));
|
|
||||||
lines.extend(message.lines().map(|line| ansi_escape_line(line).dim()));
|
|
||||||
lines.push(Line::from(""));
|
|
||||||
PlainHistoryCell { lines }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn new_session_info(
|
pub(crate) fn new_session_info(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
event: SessionConfiguredEvent,
|
event: SessionConfiguredEvent,
|
||||||
|
|||||||
@@ -109,6 +109,34 @@ pub(crate) struct UserApprovalWidget<'a> {
|
|||||||
done: bool,
|
done: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_command_display<'a>(
|
||||||
|
first_line: Vec<Span<'a>>,
|
||||||
|
cmd: String,
|
||||||
|
last_line: Vec<Span<'a>>,
|
||||||
|
) -> Vec<Line<'a>> {
|
||||||
|
let command_lines: Vec<Span> = cmd
|
||||||
|
.lines()
|
||||||
|
.map(|line| Span::from(line.to_string()).style(Style::new().add_modifier(Modifier::DIM)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut lines: Vec<Line<'a>> = vec![];
|
||||||
|
|
||||||
|
let mut first_line = first_line.clone();
|
||||||
|
if command_lines.len() == 1 {
|
||||||
|
first_line.push(command_lines[0].clone());
|
||||||
|
first_line.extend(last_line);
|
||||||
|
} else {
|
||||||
|
for line in command_lines {
|
||||||
|
lines.push(Line::from(vec![Span::from(" "), line]));
|
||||||
|
}
|
||||||
|
let last_line = last_line.clone();
|
||||||
|
lines.push(Line::from(last_line));
|
||||||
|
}
|
||||||
|
lines.insert(0, Line::from(first_line));
|
||||||
|
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
|
||||||
impl UserApprovalWidget<'_> {
|
impl UserApprovalWidget<'_> {
|
||||||
pub(crate) fn new(approval_request: ApprovalRequest, app_event_tx: AppEventSender) -> Self {
|
pub(crate) fn new(approval_request: ApprovalRequest, app_event_tx: AppEventSender) -> Self {
|
||||||
let confirmation_prompt = match &approval_request {
|
let confirmation_prompt = match &approval_request {
|
||||||
@@ -116,17 +144,13 @@ impl UserApprovalWidget<'_> {
|
|||||||
command, reason, ..
|
command, reason, ..
|
||||||
} => {
|
} => {
|
||||||
let cmd = strip_bash_lc_and_escape(command);
|
let cmd = strip_bash_lc_and_escape(command);
|
||||||
// Present a single-line summary without cwd: "codex wants to run: <cmd>"
|
let mut contents: Vec<Line> = to_command_display(
|
||||||
let mut cmd_span: Span = cmd.clone().into();
|
vec!["? ".fg(Color::Blue), "Codex wants to run ".bold()],
|
||||||
cmd_span.style = cmd_span.style.add_modifier(Modifier::DIM);
|
cmd,
|
||||||
let mut contents: Vec<Line> = vec![
|
vec![],
|
||||||
Line::from(vec![
|
);
|
||||||
"? ".fg(Color::Blue),
|
|
||||||
"Codex wants to run ".bold(),
|
contents.push(Line::from(""));
|
||||||
cmd_span,
|
|
||||||
]),
|
|
||||||
Line::from(""),
|
|
||||||
];
|
|
||||||
if let Some(reason) = reason {
|
if let Some(reason) = reason {
|
||||||
contents.push(Line::from(reason.clone().italic()));
|
contents.push(Line::from(reason.clone().italic()));
|
||||||
contents.push(Line::from(""));
|
contents.push(Line::from(""));
|
||||||
@@ -244,44 +268,52 @@ impl UserApprovalWidget<'_> {
|
|||||||
// Result line based on decision.
|
// Result line based on decision.
|
||||||
match decision {
|
match decision {
|
||||||
ReviewDecision::Approved => {
|
ReviewDecision::Approved => {
|
||||||
lines.push(Line::from(vec![
|
lines.extend(to_command_display(
|
||||||
"✔ ".fg(Color::Green),
|
vec![
|
||||||
"You ".into(),
|
"✔ ".fg(Color::Green),
|
||||||
"approved".bold(),
|
"You ".into(),
|
||||||
" codex to run ".into(),
|
"approved".bold(),
|
||||||
cmd_span,
|
" codex to run ".into(),
|
||||||
" ".into(),
|
],
|
||||||
"this time".bold(),
|
cmd,
|
||||||
]));
|
vec![" this time".bold()],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
ReviewDecision::ApprovedForSession => {
|
ReviewDecision::ApprovedForSession => {
|
||||||
lines.push(Line::from(vec![
|
lines.extend(to_command_display(
|
||||||
"✔ ".fg(Color::Green),
|
vec![
|
||||||
"You ".into(),
|
"✔ ".fg(Color::Green),
|
||||||
"approved".bold(),
|
"You ".into(),
|
||||||
" codex to run ".into(),
|
"approved".bold(),
|
||||||
cmd_span,
|
"codex to run ".into(),
|
||||||
" ".into(),
|
],
|
||||||
"every time this session".bold(),
|
cmd,
|
||||||
]));
|
vec![" every time this session".bold()],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
ReviewDecision::Denied => {
|
ReviewDecision::Denied => {
|
||||||
lines.push(Line::from(vec![
|
lines.extend(to_command_display(
|
||||||
"✗ ".fg(Color::Red),
|
vec![
|
||||||
"You ".into(),
|
"✗ ".fg(Color::Red),
|
||||||
"did not approve".bold(),
|
"You ".into(),
|
||||||
" codex to run ".into(),
|
"did not approve".bold(),
|
||||||
cmd_span,
|
" codex to run ".into(),
|
||||||
]));
|
],
|
||||||
|
cmd,
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
ReviewDecision::Abort => {
|
ReviewDecision::Abort => {
|
||||||
lines.push(Line::from(vec![
|
lines.extend(to_command_display(
|
||||||
"✗ ".fg(Color::Red),
|
vec![
|
||||||
"You ".into(),
|
"✗ ".fg(Color::Red),
|
||||||
"canceled".bold(),
|
"You ".into(),
|
||||||
" the request to run ".into(),
|
"canceled".bold(),
|
||||||
cmd_span,
|
" the request to run ".into(),
|
||||||
]));
|
],
|
||||||
|
cmd,
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user