Fix input formatting bugs: newline, line wrapping, and TTY check
Fixes three bugs in the input formatter introduced in 4e16942:
1. Bug 2 & 3 (missing newline, line duplication):
- Changed print! to println! to add trailing newline
- Calculate visual lines based on terminal width instead of
logical line count, fixing duplication for wrapped lines
2. Bug 1 (^M on non-interactive prompts):
- Added TTY check to skip formatting when stdout is not a terminal
- Prevents terminal state corruption for stdin prompts
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
//! - Quoted text ("..." or '...') becomes cyan
|
||||
//! - Standard markdown formatting (bold, italic, code) is applied
|
||||
|
||||
use crossterm::terminal;
|
||||
use regex::Regex;
|
||||
use std::io::Write;
|
||||
use std::io::IsTerminal;
|
||||
use termimad::MadSkin;
|
||||
|
||||
use crate::streaming_markdown::StreamingMarkdownFormatter;
|
||||
@@ -87,22 +89,39 @@ pub fn format_input(input: &str) -> String {
|
||||
///
|
||||
/// 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.
|
||||
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);
|
||||
|
||||
// Count how many lines the input spans (for multiline input)
|
||||
let line_count = input.lines().count().max(1);
|
||||
// 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 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
|
||||
for _ in 0..line_count {
|
||||
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
|
||||
print!("\x1b[2m{}\x1b[0m{}", prompt, formatted);
|
||||
println!("\x1b[2m{}\x1b[0m{}", prompt, formatted);
|
||||
|
||||
// Ensure output is flushed
|
||||
let _ = std::io::stdout().flush();
|
||||
|
||||
Reference in New Issue
Block a user