@@ -633,6 +633,50 @@ impl HistoryCell for CompletedMcpToolCallWithImageOutput {
|
|||||||
const TOOL_CALL_MAX_LINES: usize = 5;
|
const TOOL_CALL_MAX_LINES: usize = 5;
|
||||||
const SESSION_HEADER_MAX_INNER_WIDTH: usize = 56; // Just an eyeballed value
|
const SESSION_HEADER_MAX_INNER_WIDTH: usize = 56; // Just an eyeballed value
|
||||||
|
|
||||||
|
fn card_inner_width(width: u16, max_inner_width: usize) -> Option<usize> {
|
||||||
|
if width < 4 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let inner_width = std::cmp::min(width.saturating_sub(4) as usize, max_inner_width);
|
||||||
|
Some(inner_width)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_border(lines: Vec<Line<'static>>) -> Vec<Line<'static>> {
|
||||||
|
let content_width = lines
|
||||||
|
.iter()
|
||||||
|
.map(|line| {
|
||||||
|
line.iter()
|
||||||
|
.map(|span| UnicodeWidthStr::width(span.content.as_ref()))
|
||||||
|
.sum::<usize>()
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let mut out = Vec::with_capacity(lines.len() + 2);
|
||||||
|
let border_inner_width = content_width + 2;
|
||||||
|
out.push(vec![format!("╭{}╮", "─".repeat(border_inner_width)).dim()].into());
|
||||||
|
|
||||||
|
for line in lines.into_iter() {
|
||||||
|
let used_width: usize = line
|
||||||
|
.iter()
|
||||||
|
.map(|span| UnicodeWidthStr::width(span.content.as_ref()))
|
||||||
|
.sum();
|
||||||
|
let span_count = line.spans.len();
|
||||||
|
let mut spans: Vec<Span<'static>> = Vec::with_capacity(span_count + 4);
|
||||||
|
spans.push(Span::from("│ ").dim());
|
||||||
|
spans.extend(line.into_iter());
|
||||||
|
if used_width < content_width {
|
||||||
|
spans.push(Span::from(" ".repeat(content_width - used_width)).dim());
|
||||||
|
}
|
||||||
|
spans.push(Span::from(" │").dim());
|
||||||
|
out.push(Line::from(spans));
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push(vec![format!("╰{}╯", "─".repeat(border_inner_width)).dim()].into());
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
fn title_case(s: &str) -> String {
|
fn title_case(s: &str) -> String {
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
return String::new();
|
return String::new();
|
||||||
@@ -816,46 +860,20 @@ impl SessionHeaderHistoryCell {
|
|||||||
|
|
||||||
impl HistoryCell for SessionHeaderHistoryCell {
|
impl HistoryCell for SessionHeaderHistoryCell {
|
||||||
fn display_lines(&self, width: u16) -> Vec<Line<'static>> {
|
fn display_lines(&self, width: u16) -> Vec<Line<'static>> {
|
||||||
let mut out: Vec<Line<'static>> = Vec::new();
|
let Some(inner_width) = card_inner_width(width, SESSION_HEADER_MAX_INNER_WIDTH) else {
|
||||||
if width < 4 {
|
return Vec::new();
|
||||||
return out;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
let inner_width = std::cmp::min(
|
let make_row = |spans: Vec<Span<'static>>| Line::from(spans);
|
||||||
width.saturating_sub(2) as usize,
|
|
||||||
SESSION_HEADER_MAX_INNER_WIDTH,
|
|
||||||
);
|
|
||||||
// Top border without a title on the border
|
|
||||||
let mut top = String::with_capacity(inner_width + 2);
|
|
||||||
top.push('╭');
|
|
||||||
top.push_str(&"─".repeat(inner_width));
|
|
||||||
top.push('╮');
|
|
||||||
out.push(Line::from(top.dim()));
|
|
||||||
|
|
||||||
// Title line rendered inside the box: " >_ OpenAI Codex (vX)"
|
// Title line rendered inside the box: ">_ OpenAI Codex (vX)"
|
||||||
let title_text = format!(" >_ OpenAI Codex (v{})", self.version);
|
let title_spans: Vec<Span<'static>> = vec![
|
||||||
let title_w = UnicodeWidthStr::width(title_text.as_str());
|
|
||||||
let pad_w = inner_width.saturating_sub(title_w);
|
|
||||||
let mut title_spans: Vec<Span<'static>> = vec![
|
|
||||||
Span::from("│").dim(),
|
|
||||||
Span::from(" ").dim(),
|
|
||||||
Span::from(">_ ").dim(),
|
Span::from(">_ ").dim(),
|
||||||
Span::from("OpenAI Codex").bold(),
|
Span::from("OpenAI Codex").bold(),
|
||||||
Span::from(" ").dim(),
|
Span::from(" ").dim(),
|
||||||
Span::from(format!("(v{})", self.version)).dim(),
|
Span::from(format!("(v{})", self.version)).dim(),
|
||||||
];
|
];
|
||||||
if pad_w > 0 {
|
|
||||||
title_spans.push(Span::from(" ".repeat(pad_w)).dim());
|
|
||||||
}
|
|
||||||
title_spans.push(Span::from("│").dim());
|
|
||||||
out.push(Line::from(title_spans));
|
|
||||||
|
|
||||||
// Spacer row between title and details
|
|
||||||
out.push(Line::from(vec![
|
|
||||||
Span::from(format!("│{}│", " ".repeat(inner_width))).dim(),
|
|
||||||
]));
|
|
||||||
|
|
||||||
// Model line: " model: <model> <reasoning_label> (change with /model)"
|
|
||||||
const CHANGE_MODEL_HINT_COMMAND: &str = "/model";
|
const CHANGE_MODEL_HINT_COMMAND: &str = "/model";
|
||||||
const CHANGE_MODEL_HINT_EXPLANATION: &str = " to change";
|
const CHANGE_MODEL_HINT_EXPLANATION: &str = " to change";
|
||||||
const DIR_LABEL: &str = "directory:";
|
const DIR_LABEL: &str = "directory:";
|
||||||
@@ -866,59 +884,33 @@ impl HistoryCell for SessionHeaderHistoryCell {
|
|||||||
label_width = label_width
|
label_width = label_width
|
||||||
);
|
);
|
||||||
let reasoning_label = self.reasoning_label();
|
let reasoning_label = self.reasoning_label();
|
||||||
let mut model_value_for_width = self.model.clone();
|
let mut model_spans: Vec<Span<'static>> = vec![
|
||||||
if let Some(reasoning) = reasoning_label {
|
Span::from(format!("{model_label} ")).dim(),
|
||||||
model_value_for_width.push(' ');
|
|
||||||
model_value_for_width.push_str(reasoning);
|
|
||||||
}
|
|
||||||
let model_text_for_width_calc = format!(
|
|
||||||
" {model_label} {model_value_for_width} {CHANGE_MODEL_HINT_COMMAND}{CHANGE_MODEL_HINT_EXPLANATION}",
|
|
||||||
);
|
|
||||||
let model_w = UnicodeWidthStr::width(model_text_for_width_calc.as_str());
|
|
||||||
let pad_w = inner_width.saturating_sub(model_w);
|
|
||||||
let mut spans: Vec<Span<'static>> = vec![
|
|
||||||
Span::from(format!("│ {model_label} ")).dim(),
|
|
||||||
Span::from(self.model.clone()),
|
Span::from(self.model.clone()),
|
||||||
];
|
];
|
||||||
if let Some(reasoning) = reasoning_label {
|
if let Some(reasoning) = reasoning_label {
|
||||||
spans.push(Span::from(" "));
|
model_spans.push(Span::from(" "));
|
||||||
spans.push(Span::from(reasoning));
|
model_spans.push(Span::from(reasoning));
|
||||||
}
|
}
|
||||||
spans.push(Span::from(" ").dim());
|
model_spans.push(" ".dim());
|
||||||
spans.push(Span::from(CHANGE_MODEL_HINT_COMMAND).cyan());
|
model_spans.push(CHANGE_MODEL_HINT_COMMAND.cyan());
|
||||||
spans.push(Span::from(CHANGE_MODEL_HINT_EXPLANATION).dim());
|
model_spans.push(CHANGE_MODEL_HINT_EXPLANATION.dim());
|
||||||
if pad_w > 0 {
|
|
||||||
spans.push(Span::from(" ".repeat(pad_w)).dim());
|
|
||||||
}
|
|
||||||
spans.push(Span::from("│").dim());
|
|
||||||
out.push(Line::from(spans));
|
|
||||||
|
|
||||||
// Directory line: " Directory: <cwd>"
|
|
||||||
let dir_label = format!("{DIR_LABEL:<label_width$}");
|
let dir_label = format!("{DIR_LABEL:<label_width$}");
|
||||||
let dir_prefix = format!(" {dir_label} ");
|
let dir_prefix = format!("{dir_label} ");
|
||||||
let dir_max_width = inner_width.saturating_sub(UnicodeWidthStr::width(dir_prefix.as_str()));
|
let dir_prefix_width = UnicodeWidthStr::width(dir_prefix.as_str());
|
||||||
|
let dir_max_width = inner_width.saturating_sub(dir_prefix_width);
|
||||||
let dir = self.format_directory(Some(dir_max_width));
|
let dir = self.format_directory(Some(dir_max_width));
|
||||||
let dir_text = format!(" {dir_label} {dir}");
|
let dir_spans = vec![Span::from(dir_prefix).dim(), Span::from(dir)];
|
||||||
let dir_w = UnicodeWidthStr::width(dir_text.as_str());
|
|
||||||
let pad_w = inner_width.saturating_sub(dir_w);
|
let lines = vec![
|
||||||
let mut spans: Vec<Span<'static>> = vec![
|
make_row(title_spans),
|
||||||
Span::from("│").dim(),
|
make_row(Vec::new()),
|
||||||
Span::from(" ").dim(),
|
make_row(model_spans),
|
||||||
Span::from(dir_label).dim(),
|
make_row(dir_spans),
|
||||||
Span::from(" ").dim(),
|
|
||||||
Span::from(dir),
|
|
||||||
];
|
];
|
||||||
if pad_w > 0 {
|
|
||||||
spans.push(Span::from(" ".repeat(pad_w)).dim());
|
|
||||||
}
|
|
||||||
spans.push(Span::from("│").dim());
|
|
||||||
out.push(Line::from(spans));
|
|
||||||
|
|
||||||
// Bottom border
|
with_border(lines)
|
||||||
let bottom = format!("╰{}╯", "─".repeat(inner_width));
|
|
||||||
out.push(Line::from(bottom.dim()));
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user