refactor(cli): adopt flex-width rendering, remove data-layer truncation
Replace hardcoded truncation widths across CLI commands with render::flex_width() calls that adapt to terminal size. Remove server-side truncate_to_chars() in timeline collect/seed stages so full text is preserved through the pipeline — truncation now happens only at the presentation layer where terminal width is known. Affected commands: explain, file-history, list (issues/mrs/notes), me, timeline, who (active/expert/workload).
This commit is contained in:
@@ -378,17 +378,10 @@ fn get_mr_assignees(conn: &Connection, mr_id: i64) -> Result<Vec<String>> {
|
||||
// Description excerpt helper
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn truncate_description(desc: Option<&str>, max_len: usize) -> String {
|
||||
fn truncate_description(desc: Option<&str>) -> String {
|
||||
match desc {
|
||||
None | Some("") => "(no description)".to_string(),
|
||||
Some(s) => {
|
||||
if s.len() <= max_len {
|
||||
s.to_string()
|
||||
} else {
|
||||
let boundary = s.floor_char_boundary(max_len);
|
||||
format!("{}...", &s[..boundary])
|
||||
}
|
||||
}
|
||||
Some(s) => s.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +406,7 @@ pub fn run_explain(conn: &Connection, params: &ExplainParams) -> Result<ExplainR
|
||||
};
|
||||
|
||||
let description_excerpt = if should_include(¶ms.sections, "description") {
|
||||
Some(truncate_description(description.as_deref(), 500))
|
||||
Some(truncate_description(description.as_deref()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -537,8 +530,10 @@ const DECISION_WINDOW_MS: i64 = 60 * 60 * 1000;
|
||||
|
||||
/// Maximum length (in bytes, snapped to a char boundary) for the
|
||||
/// `context_note` field in a `KeyDecision`.
|
||||
#[allow(dead_code)]
|
||||
const NOTE_TRUNCATE_LEN: usize = 500;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn truncate_note(text: &str, max_len: usize) -> String {
|
||||
if text.len() <= max_len {
|
||||
text.to_string()
|
||||
@@ -682,7 +677,7 @@ pub fn extract_key_decisions(
|
||||
timestamp: ms_to_iso(event.created_at),
|
||||
actor: event.actor.clone(),
|
||||
action: event.description.clone(),
|
||||
context_note: truncate_note(¬e.body, NOTE_TRUNCATE_LEN),
|
||||
context_note: note.body.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1257,7 +1252,7 @@ pub fn print_explain(result: &ExplainResult) {
|
||||
Theme::dim().render(&to_relative(&t.last_note_at))
|
||||
);
|
||||
if let Some(ref excerpt) = t.first_note_excerpt {
|
||||
let preview = render::truncate(excerpt, 100);
|
||||
let preview = render::truncate(excerpt, render::flex_width(8, 30));
|
||||
// Show first line only in human output
|
||||
if let Some(line) = preview.lines().next() {
|
||||
println!(" {}", Theme::muted().render(line));
|
||||
@@ -1283,7 +1278,7 @@ pub fn print_explain(result: &ExplainResult) {
|
||||
" {} {} — {} {}",
|
||||
Icons::success(),
|
||||
Theme::mr_ref().render(&format!("!{}", mr.iid)),
|
||||
render::truncate(&mr.title, 60),
|
||||
render::truncate(&mr.title, render::flex_width(25, 20)),
|
||||
mr_state.render(&format!("[{}]", mr.state))
|
||||
);
|
||||
}
|
||||
@@ -1305,7 +1300,7 @@ pub fn print_explain(result: &ExplainResult) {
|
||||
println!(
|
||||
" {arrow} {} {}{state_str} ({})",
|
||||
ref_style.render(&format!("{ref_prefix}{}", ri.iid)),
|
||||
render::truncate(ri.title.as_deref().unwrap_or("(untitled)"), 50),
|
||||
render::truncate(ri.title.as_deref().unwrap_or("(untitled)"), render::flex_width(30, 20)),
|
||||
Theme::dim().render(&ri.reference_type)
|
||||
);
|
||||
}
|
||||
@@ -1596,14 +1591,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_truncate_description() {
|
||||
assert_eq!(truncate_description(None, 500), "(no description)");
|
||||
assert_eq!(truncate_description(Some(""), 500), "(no description)");
|
||||
assert_eq!(truncate_description(Some("short"), 500), "short");
|
||||
assert_eq!(truncate_description(None), "(no description)");
|
||||
assert_eq!(truncate_description(Some("")), "(no description)");
|
||||
assert_eq!(truncate_description(Some("short")), "short");
|
||||
|
||||
let long = "a".repeat(600);
|
||||
let truncated = truncate_description(Some(&long), 500);
|
||||
assert!(truncated.ends_with("..."));
|
||||
assert!(truncated.len() <= 504); // 500 + "..."
|
||||
let result = truncate_description(Some(&long));
|
||||
assert_eq!(result, long); // no truncation — full description preserved
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user