Readability improvements across streaming_parser, input_formatter, commands

- streaming_parser.rs: Reduced ~70 lines by removing redundant comments,
  consolidating doc comments, using slice syntax for TOOL_CALL_PATTERNS
- input_formatter.rs: Lazy regex compilation via once_cell (performance),
  cleaner function structure, reduced comment noise
- commands.rs: Extracted format_research_task_summary() and
  format_research_report_header() helpers, reduced ~40 lines of duplication
- pending_research.rs: Fixed 2 unused variable warnings in tests

All changes are behavior-preserving. 446 tests pass.

Agent: carmack
This commit is contained in:
Dhanji R. Prasanna
2026-01-30 14:48:08 +11:00
parent 51f12769d5
commit afc5bc8574
4 changed files with 120 additions and 219 deletions

View File

@@ -1,129 +1,102 @@
//! Input formatting for interactive mode.
//!
//! Formats user input with markdown-style highlighting:
//! - ALL CAPS words become bold
//! - Quoted text ("..." or '...') becomes cyan
//! - Standard markdown formatting (bold, italic, code) is applied
//! Applies visual highlighting to user input:
//! - ALL CAPS words (2+ chars) → bold green
//! - Quoted text ("..." or '...') cyan
//! - Standard markdown (bold, italic, code) via termimad
use crossterm::terminal;
use regex::Regex;
use std::io::Write;
use std::io::IsTerminal;
use once_cell::sync::Lazy;
use termimad::MadSkin;
use crate::streaming_markdown::StreamingMarkdownFormatter;
/// Pre-process input text to add markdown markers for special formatting.
///
/// This pass runs BEFORE markdown formatting:
/// 1. ALL CAPS words (2+ chars) → wrapped in ** for bold
/// 2. Quoted text "..." or '...' → wrapped in special markers for cyan
///
/// Returns the preprocessed text ready for markdown formatting.
// Compiled regexes for preprocessing (compiled once, reused)
static CAPS_RE: Lazy<Regex> = Lazy::new(|| {
// ALL CAPS words: 2+ uppercase letters, may include numbers, word boundaries
Regex::new(r"\b([A-Z][A-Z0-9]{1,}[A-Z0-9]*)\b").unwrap()
});
static DOUBLE_QUOTE_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r#""([^"]+)""#).unwrap());
static SINGLE_QUOTE_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"'([^']+)'").unwrap());
/// Pre-process input to add markdown markers before formatting.
/// ALL CAPS → **bold**, quoted text → special markers for cyan.
pub fn preprocess_input(input: &str) -> String {
let mut result = input.to_string();
// First, handle ALL CAPS words (2+ uppercase letters, may include numbers)
// Must be a standalone word (word boundaries)
let caps_re = Regex::new(r"\b([A-Z][A-Z0-9]{1,}[A-Z0-9]*)\b").unwrap();
result = caps_re.replace_all(&result, "**$1**").to_string();
// ALL CAPS → **bold**
result = CAPS_RE.replace_all(&result, "**$1**").to_string();
// Then, handle quoted text - wrap in a special marker that we'll process after markdown
// Use lowercase placeholders that won't be matched by the ALL CAPS regex
let double_quote_re = Regex::new(r#""([^"]+)""#).unwrap();
result = double_quote_re.replace_all(&result, "\x00qdbl\x00$1\x00qend\x00").to_string();
let single_quote_re = Regex::new(r"'([^']+)'").unwrap();
result = single_quote_re.replace_all(&result, "\x00qsgl\x00$1\x00qend\x00").to_string();
// Quoted text → markers (processed after markdown to apply cyan)
result = DOUBLE_QUOTE_RE.replace_all(&result, "\x00qdbl\x00$1\x00qend\x00").to_string();
result = SINGLE_QUOTE_RE.replace_all(&result, "\x00qsgl\x00$1\x00qend\x00").to_string();
result
}
/// Apply cyan highlighting to quoted text markers.
/// This runs AFTER markdown formatting to apply the cyan color.
// Regexes for post-processing quote markers into ANSI cyan
static CYAN_DOUBLE_RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(r#"(\x1b\[36m")([^\x1b]*)\x1b\[0m"#).unwrap()
});
static CYAN_SINGLE_RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"(\x1b\[36m')([^\x1b]*)\x1b\[0m").unwrap()
});
/// Apply cyan highlighting to quoted text markers (runs after markdown formatting).
fn apply_quote_highlighting(text: &str) -> String {
let mut result = text.to_string();
// Replace double-quote markers with cyan formatting
// \x1b[36m = cyan, \x1b[0m = reset
result = result.replace("\x00qdbl\x00", "\x1b[36m\"");
result = result.replace("\x00qsgl\x00", "\x1b[36m'");
result = result.replace("\x00qend\x00", "\x1b[0m");
// Add back the closing quotes
// We need to insert them before the reset code
let re = Regex::new(r#"(\x1b\[36m")([^\x1b]*)\x1b\[0m"#).unwrap();
result = re.replace_all(&result, |caps: &regex::Captures| {
// Insert closing quotes before reset code
result = CYAN_DOUBLE_RE.replace_all(&result, |caps: &regex::Captures| {
format!("{}{}\"\x1b[0m", &caps[1], &caps[2])
}).to_string();
let re = Regex::new(r"(\x1b\[36m')([^\x1b]*)\x1b\[0m").unwrap();
result = re.replace_all(&result, |caps: &regex::Captures| {
result = CYAN_SINGLE_RE.replace_all(&result, |caps: &regex::Captures| {
format!("{}{}'\x1b[0m", &caps[1], &caps[2])
}).to_string();
result
}
/// Format user input with markdown and special highlighting.
///
/// Applies:
/// 1. ALL CAPS → bold (green)
/// 2. Quoted text → cyan
/// 3. Standard markdown (bold, italic, inline code)
/// Format user input with markdown and special highlighting (ALL CAPS, quotes).
pub fn format_input(input: &str) -> String {
// Pre-process to add markdown markers
let preprocessed = preprocess_input(input);
// Apply markdown formatting using the streaming formatter
let skin = MadSkin::default();
let mut formatter = StreamingMarkdownFormatter::new(skin);
let formatted = formatter.process(&preprocessed);
let formatted = formatted + &formatter.finish();
// Apply quote highlighting (after markdown so colors don't interfere)
apply_quote_highlighting(&formatted)
}
/// Reprint user input in place with formatting.
///
/// This moves the cursor up to overwrite the original input line,
/// then prints the formatted version.
///
/// Note: This function only performs formatting when stdout is a TTY.
/// In non-TTY contexts (piped output, etc.), it does nothing to avoid
/// corrupting terminal state for subsequent stdin operations.
/// Reprint user input in place with formatting (TTY only).
/// Moves cursor up to overwrite original input, then prints formatted version.
pub fn reprint_formatted_input(input: &str, prompt: &str) {
// Only reformat if stdout is a TTY - avoid corrupting terminal state otherwise
if !std::io::stdout().is_terminal() {
return;
}
// Format the input
let formatted = format_input(input);
// Get terminal width to calculate visual lines
// The prompt + input may wrap across multiple terminal rows
let term_width = terminal::size()
.map(|(w, _)| w as usize)
.unwrap_or(80);
// Calculate visual lines (prompt + input may wrap across terminal rows)
let term_width = terminal::size().map(|(w, _)| w as usize).unwrap_or(80);
let visual_lines = (prompt.len() + input.len()).div_ceil(term_width).max(1);
// Calculate visual lines: prompt + input length divided by terminal width
// This accounts for line wrapping in the terminal
let total_chars = prompt.len() + input.len();
let visual_lines = ((total_chars + term_width - 1) / term_width).max(1); // ceiling division
// Move cursor up by the number of lines and clear
// Move up and clear each line
for _ in 0..visual_lines {
// Move up one line and clear it
print!("\x1b[1A\x1b[2K");
}
// Reprint with prompt and formatted input
// Use dim color for the prompt to distinguish from the formatted input
// Dim prompt + formatted input
println!("\x1b[2m{}\x1b[0m{}", prompt, formatted);
// Ensure output is flushed
let _ = std::io::stdout().flush();
}