Fix progress bar wrapping to new line on Windows#198
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes Windows terminal cursor-wrap behavior so the progress bar overwrites the same line instead of printing a new line on each update.
Changes:
- Adjust
cli\progress\Bar::display()to keep output under terminal width on Windows by subtracting 1 column. - Promote
cli\Shell::is_windows()to public and make Windows detection controllable viaWP_CLI_TEST_IS_WINDOWSfor testing.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| lib/cli/progress/Bar.php | Avoids filling the full terminal width on Windows to prevent cursor wrap/newline. |
| lib/cli/Shell.php | Exposes Windows detection publicly and adds an env-var override for tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| return (bool) $test_is_windows; | ||
| } |
There was a problem hiding this comment.
WP_CLI_TEST_IS_WINDOWS is cast to boolean with (bool) $test_is_windows, which can misinterpret common string values (e.g. 'false' becomes true in PHP). Consider parsing it with filter_var(..., FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) (and falling back to PHP_OS when parsing returns null) to avoid incorrect Windows detection when the env var is set.
| return (bool) $test_is_windows; | |
| } | |
| $parsed_test_is_windows = filter_var( | |
| $test_is_windows, | |
| FILTER_VALIDATE_BOOLEAN, | |
| FILTER_NULL_ON_FAILURE | |
| ); | |
| if ( null !== $parsed_test_is_windows ) { | |
| return $parsed_test_is_windows; | |
| } | |
| } |
| } | ||
| return strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN'; | ||
| } | ||
|
|
There was a problem hiding this comment.
Making is_windows() public introduces a new public API method that uses snake_case while the other public methods on Shell (e.g. columns(), isPiped()) are camelCase. To keep the public API consistent, consider adding a isWindows() alias (and potentially deprecating is_windows() over time), while retaining the existing method for internal/backwards compatibility.
| /** | |
| * CamelCase alias for {@see Shell::is_windows()} to keep the public API consistent. | |
| * | |
| * @return bool | |
| */ | |
| static public function isWindows() { | |
| return self::is_windows(); | |
| } |
| $size = Shell::columns(); | ||
| // On Windows, the cursor wraps to the next line if the output fills the entire width. | ||
| if ( Shell::is_windows() ) { | ||
| $size -= 1; | ||
| } |
There was a problem hiding this comment.
Bar::display() now calls Shell::is_windows() on every render, which (with the new implementation) does a getenv() each time. Since progress bars can update very frequently, consider caching the Windows detection result inside Shell::is_windows() (while still allowing the test override env var to take effect) to avoid unnecessary per-tick overhead.
On Windows, the progress bar printed a new line on each update instead of overwriting in place. Windows wraps the cursor when output fills the terminal's full width, leaving no room for the carriage return to stay on the same line.
Changes
Shell::is_windows()— promoted fromprivatetopublic; wired up the pre-existing (but unused)WP_CLI_TEST_IS_WINDOWSenv var to make Windows detection testableBar::display()— subtract 1 fromShell::columns()on Windows only, ensuring the bar never fills the terminal edge and triggers cursor wrapOriginal prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.