Remove ANSI formatting codes from g3-core
Move terminal formatting responsibility to g3-cli layer: - format_str_replace_summary(): Remove ANSI codes, add colorize_str_replace_summary() helper in CLI to apply green/red colors for insertions/deletions - format_timing_footer(): Remove dimming ANSI codes (now plain text) - str_replace tool result: Remove ANSI codes from success message Remaining acceptable ANSI usage in g3-core: - iTerm2 inline image protocol (terminal-specific escape sequence) - Image metadata dimming (direct print, would need larger refactor) - Terminal beep for stale TODO warning (audio, not visual) - ANSI stripping utility in research.rs (not output) This continues the separation of concerns: g3-core handles logic, g3-cli handles all terminal formatting.
This commit is contained in:
@@ -15,6 +15,22 @@ mod ansi {
|
|||||||
pub const RED: &str = "\x1b[31m";
|
pub const RED: &str = "\x1b[31m";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Colorize a str_replace summary (e.g., "+5 | -3" -> green "+5" | red "-3")
|
||||||
|
fn colorize_str_replace_summary(summary: &str) -> String {
|
||||||
|
// Parse patterns like "+5 | -3", "+5", "-3"
|
||||||
|
if summary.contains(" | ") {
|
||||||
|
let parts: Vec<&str> = summary.split(" | ").collect();
|
||||||
|
if parts.len() == 2 {
|
||||||
|
return format!("\x1b[32m{}\x1b[0m \x1b[2m|\x1b[0m \x1b[31m{}\x1b[0m", parts[0], parts[1]);
|
||||||
|
}
|
||||||
|
} else if summary.starts_with('+') {
|
||||||
|
return format!("\x1b[32m{}\x1b[0m", summary);
|
||||||
|
} else if summary.starts_with('-') {
|
||||||
|
return format!("\x1b[31m{}\x1b[0m", summary);
|
||||||
|
}
|
||||||
|
summary.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// ANSI color codes for tool names
|
/// ANSI color codes for tool names
|
||||||
const TOOL_COLOR_NORMAL: &str = "\x1b[32m";
|
const TOOL_COLOR_NORMAL: &str = "\x1b[32m";
|
||||||
const TOOL_COLOR_NORMAL_BOLD: &str = "\x1b[1;32m";
|
const TOOL_COLOR_NORMAL_BOLD: &str = "\x1b[1;32m";
|
||||||
@@ -523,6 +539,13 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
// Color for tool name
|
// Color for tool name
|
||||||
let tool_color = if is_agent_mode { TOOL_COLOR_AGENT } else { TOOL_COLOR_NORMAL };
|
let tool_color = if is_agent_mode { TOOL_COLOR_AGENT } else { TOOL_COLOR_NORMAL };
|
||||||
|
|
||||||
|
// Colorize summary for str_replace (green insertions, red deletions)
|
||||||
|
let display_summary = if tool_name == "str_replace" {
|
||||||
|
colorize_str_replace_summary(summary)
|
||||||
|
} else {
|
||||||
|
summary.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
// Print compact single line
|
// Print compact single line
|
||||||
if is_continuation {
|
if is_continuation {
|
||||||
// Continuation line for consecutive read_file on same file:
|
// Continuation line for consecutive read_file on same file:
|
||||||
@@ -530,7 +553,7 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
println!(
|
println!(
|
||||||
" \x1b[2m└─ reading further\x1b[0m\x1b[35m{}\x1b[0m \x1b[2m| {}\x1b[0m \x1b[2m| {} ◉ {}\x1b[0m",
|
" \x1b[2m└─ reading further\x1b[0m\x1b[35m{}\x1b[0m \x1b[2m| {}\x1b[0m \x1b[2m| {} ◉ {}\x1b[0m",
|
||||||
range_suffix,
|
range_suffix,
|
||||||
summary,
|
display_summary,
|
||||||
tokens_delta,
|
tokens_delta,
|
||||||
duration_str
|
duration_str
|
||||||
);
|
);
|
||||||
@@ -539,14 +562,14 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
// Pad to align with longest compact tool (str_replace = 11 chars)
|
// Pad to align with longest compact tool (str_replace = 11 chars)
|
||||||
println!(
|
println!(
|
||||||
" \x1b[2m●\x1b[0m {}{:<11}\x1b[0m \x1b[2m| {}\x1b[0m \x1b[2m| {} ◉ {}\x1b[0m",
|
" \x1b[2m●\x1b[0m {}{:<11}\x1b[0m \x1b[2m| {}\x1b[0m \x1b[2m| {} ◉ {}\x1b[0m",
|
||||||
tool_color, tool_name, summary, tokens_delta, duration_str
|
tool_color, tool_name, display_summary, tokens_delta, duration_str
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Tools with file path: " ● tool_name | path [range] | summary | tokens ◉ time"
|
// Tools with file path: " ● tool_name | path [range] | summary | tokens ◉ time"
|
||||||
// Pad to align with longest compact tool (str_replace = 11 chars)
|
// Pad to align with longest compact tool (str_replace = 11 chars)
|
||||||
println!(
|
println!(
|
||||||
" \x1b[2m●\x1b[0m {}{:<11}\x1b[0m \x1b[2m|\x1b[0m \x1b[35m{}{}\x1b[0m \x1b[2m| {}\x1b[0m \x1b[2m| {} ◉ {}\x1b[0m",
|
" \x1b[2m●\x1b[0m {}{:<11}\x1b[0m \x1b[2m|\x1b[0m \x1b[35m{}{}\x1b[0m \x1b[2m| {}\x1b[0m \x1b[2m| {} ◉ {}\x1b[0m",
|
||||||
tool_color, tool_name, display_arg, range_suffix, summary, tokens_delta, duration_str
|
tool_color, tool_name, display_arg, range_suffix, display_summary, tokens_delta, duration_str
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -142,11 +142,11 @@ pub fn format_timing_footer(
|
|||||||
// Add token usage info if available (dimmed)
|
// Add token usage info if available (dimmed)
|
||||||
if let Some(tokens) = turn_tokens {
|
if let Some(tokens) = turn_tokens {
|
||||||
format!(
|
format!(
|
||||||
"{} \x1b[2m{} ◉ | {:.0}%\x1b[0m",
|
"{} {} ◉ | {:.0}%",
|
||||||
timing, tokens, context_percentage
|
timing, tokens, context_percentage
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{} \x1b[2m{:.0}%\x1b[0m", timing, context_percentage)
|
format!("{} {:.0}%", timing, context_percentage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,11 +326,11 @@ pub fn format_write_file_result(tool_result: &str) -> String {
|
|||||||
/// Format a str_replace result summary.
|
/// Format a str_replace result summary.
|
||||||
pub fn format_str_replace_summary(insertions: i32, deletions: i32) -> String {
|
pub fn format_str_replace_summary(insertions: i32, deletions: i32) -> String {
|
||||||
if insertions > 0 && deletions > 0 {
|
if insertions > 0 && deletions > 0 {
|
||||||
format!("\x1b[32m+{}\x1b[0m \x1b[2m|\x1b[0m \x1b[31m-{}\x1b[0m", insertions, deletions)
|
format!("+{} | -{}", insertions, deletions)
|
||||||
} else if insertions > 0 {
|
} else if insertions > 0 {
|
||||||
format!("\x1b[32m+{}\x1b[0m", insertions)
|
format!("+{}", insertions)
|
||||||
} else {
|
} else {
|
||||||
format!("\x1b[31m-{}\x1b[0m", deletions)
|
format!("-{}", deletions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ pub async fn execute_str_replace<W: UiWriter>(
|
|||||||
|
|
||||||
// Write the result back to the file
|
// Write the result back to the file
|
||||||
match std::fs::write(&file_path, &result) {
|
match std::fs::write(&file_path, &result) {
|
||||||
Ok(()) => Ok(format!("✅ \x1b[32m+{} insertions\x1b[0m | \x1b[31m-{} deletions\x1b[0m", insertions, deletions)),
|
Ok(()) => Ok(format!("✅ +{} insertions | -{} deletions", insertions, deletions)),
|
||||||
Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", file_path, e)),
|
Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", file_path, e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user