fix: Windows prompt cursor positioning issue with ANSI escape sequences (#4464)

Signed-off-by: Matt Donovan <mattddonovan@protonmail.com>
Co-authored-by: Matt Donovan <mattddonovan@protonmail.com>
This commit is contained in:
Matt Donovan
2025-09-30 05:58:11 -07:00
committed by GitHub
parent 8f5eb10ba4
commit af40917b2d
+56 -1
View File
@@ -68,7 +68,7 @@ pub fn get_input(
rustyline::EventHandler::Conditional(Box::new(CtrlCHandler)),
);
let prompt = format!("{} ", console::style("( O)>").cyan().bold());
let prompt = get_input_prompt_string();
let input = match editor.readline(&prompt) {
Ok(text) => text,
@@ -271,6 +271,21 @@ fn parse_plan_command(input: String) -> Option<InputResult> {
Some(InputResult::Plan(options))
}
/// Generates the input prompt string for the CLI interface.
/// Returns a styled prompt with the goose face "( O)>" followed by a space.
/// On Windows, returns plain text without ANSI styling for better compatibility.
/// On other platforms, applies styling using ANSI escape codes.
fn get_input_prompt_string() -> String {
let goose = "( O)>";
if cfg!(target_os = "windows") {
// Use plain text on Windows to avoid ANSI compatibility issues
format!("{goose} ")
} else {
// On other platforms, use styled prompt with ANSI colors
format!("{} ", console::style(goose).cyan().bold())
}
}
fn print_help() {
println!(
"Available commands:
@@ -536,4 +551,44 @@ mod tests {
let result = handle_slash_command(" /summarize ");
assert!(matches!(result, Some(InputResult::Summarize)));
}
#[test]
fn test_get_input_prompt_string() {
let prompt = get_input_prompt_string();
// Prompt should always end with a space
assert!(prompt.ends_with(" "));
// Prompt should contain the goose face
assert!(prompt.contains("( O)>"));
// On Windows, prompt should be plain text without ANSI codes
#[cfg(target_os = "windows")]
{
assert_eq!(prompt, "( O)> ");
// Ensure no ANSI escape sequences
assert!(!prompt.contains("\x1b["));
}
// On non-Windows, prompt behavior depends on terminal capabilities
#[cfg(not(target_os = "windows"))]
{
// In CI environments, console crate may strip ANSI codes
let is_ci = std::env::var("CI").is_ok();
if is_ci {
// In CI, just verify basic structure - console crate handles ANSI detection
assert!(prompt.len() >= "( O)> ".len());
} else {
// In interactive terminals, expect styling to be applied
// Note: This may still vary based on terminal capabilities
assert!(prompt.len() >= "( O)> ".len());
// If ANSI codes are present, they should be valid
if prompt.contains("\x1b[") {
assert!(prompt.contains("36") || prompt.contains("1"));
}
}
}
}
}