From 95f89a093a253c3a5a0d9471c239966a23e3de7e Mon Sep 17 00:00:00 2001 From: Justin Ma Date: Sun, 2 Mar 2025 01:30:00 +0800 Subject: [PATCH] Add ansi codes to move cursor position (#15221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Add ansi codes to move cursor position: `ansi cursor_left`, `ansi cursor_right`, `ansi cursor_up`, `ansi cursor_down` Why I add these? I'm trying to add a spinner to the message end for a long running task, just to find that I need to move the cursor left to make it work as expected: `with-progress 'Waiting for the task to finish' { sleep 10sec }` ```nu def with-progress [ message: string, # Message to display action: closure, # Action to perform --success: string, # Success message --error: string # Error message ] { print -n $'($message) ' # ASCII spinner frames let frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] # Start the spinner in the background let spinner_pid = job spawn { mut i = 0 print -n (ansi cursor_off) loop { print -n (ansi cursor_left) print -n ($frames | get $i) sleep 100ms $i = ($i + 1) mod ($frames | length) } } # Run the action and capture result let result = try { do $action { success: true } } catch { { success: false } } # Stop the spinner job kill $spinner_pid print "\r \r" # Show appropriate message if $result.success { print ($success | default '✓ Done!') } else { print ($error | default '✗ Failed!') exit 1 } } ``` # User-Facing Changes # Tests + Formatting # After Submitting --- crates/nu-command/src/platform/ansi/ansi_.rs | 8 ++++++++ crates/nu-command/tests/commands/platform/ansi_.rs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/nu-command/src/platform/ansi/ansi_.rs b/crates/nu-command/src/platform/ansi/ansi_.rs index 4e40f7df3f..143bbc9ac1 100644 --- a/crates/nu-command/src/platform/ansi/ansi_.rs +++ b/crates/nu-command/src/platform/ansi/ansi_.rs @@ -466,6 +466,14 @@ static CODE_LIST: LazyLock> = LazyLock::new(|| { vec![ // Cursor position in ESC [ ;R where r = row and c = column AnsiCode{ short_name: None, long_name:"cursor_position", code: "\x1b[6n".to_string()}, + // Move cursor one character left + AnsiCode{ short_name: None, long_name:"cursor_left", code: "\x1b[D".to_string()}, + // Move cursor one character right + AnsiCode{ short_name: None, long_name:"cursor_right", code: "\x1b[C".to_string()}, + // Move cursor one line up + AnsiCode{ short_name: None, long_name:"cursor_up", code: "\x1b[A".to_string()}, + // Move cursor one line down + AnsiCode{ short_name: None, long_name:"cursor_down", code: "\x1b[B".to_string()}, // Report Terminal Identity AnsiCode{ short_name: None, long_name:"identity", code: "\x1b[0c".to_string()}, diff --git a/crates/nu-command/tests/commands/platform/ansi_.rs b/crates/nu-command/tests/commands/platform/ansi_.rs index c7bea5cafb..7ee80ffe9d 100644 --- a/crates/nu-command/tests/commands/platform/ansi_.rs +++ b/crates/nu-command/tests/commands/platform/ansi_.rs @@ -11,7 +11,7 @@ fn test_ansi_shows_error_on_escape() { fn test_ansi_list_outputs_table() { let actual = nu!("ansi --list | length"); - assert_eq!(actual.out, "425"); + assert_eq!(actual.out, "429"); } #[test]