refactor(progress): migrate from indicatif to clx#7928
Conversation
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly refactors the user interface's progress reporting capabilities. By switching from Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Pull request overview
This PR refactors the progress reporting system by migrating from the indicatif library to clx. The change simplifies progress tracking by leveraging clx's built-in features for terminal progress (OSC sequences), pause/resume for logging, and unified progress job management.
Changes:
- Replaced indicatif's MultiProgress and ProgressBar with clx's ProgressJob and ProgressJobBuilder
- Added MISE_FORCE_PROGRESS environment variable to enable progress UI in non-TTY environments
- Removed custom OSC progress implementation (osc.rs) in favor of clx's built-in support
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ui/progress_report.rs | Replaced indicatif progress bars with clx ProgressJob implementation, using arc spinner and ETA display |
| src/ui/osc.rs | Removed entire file containing custom OSC terminal progress implementation |
| src/ui/multi_progress_report.rs | Migrated from indicatif MultiProgress to clx progress system with header job for overall progress |
| src/ui/mod.rs | Removed osc module from public exports |
| src/logger.rs | Replaced MultiProgressReport suspend calls with direct clx pause/resume |
| src/env.rs | Removed terminal detection variables, added MISE_FORCE_PROGRESS flag |
| Cargo.toml | Replaced indicatif dependency with local clx path dependency |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Cargo.toml
Outdated
| indenter = "0.3" | ||
| indexmap = { version = "2", features = ["serde"] } | ||
| indicatif = { version = "0.18", features = ["improved_unicode"] } | ||
| clx = { path = "/Users/jdickey/src/clx" } |
There was a problem hiding this comment.
The clx dependency uses an absolute local path specific to one developer's machine. This will break for other developers and in CI/CD environments. Consider publishing clx to crates.io or using a git dependency with a specific commit/tag, e.g., clx = { git = \"https://github.com/...\", rev = \"...\" }
| clx = { path = "/Users/jdickey/src/clx" } | |
| clx = { git = "https://github.com/jdx/clx", tag = "v0.1.0" } |
src/ui/multi_progress_report.rs
Outdated
| // Disable OSC progress if terminal_progress is disabled | ||
| // Note: clx::osc::configure can only be called once, so we check first |
There was a problem hiding this comment.
Using panic::catch_unwind to silently ignore errors when calling clx::osc::configure is unclear and may hide important failures. If this is expected behavior (e.g., configure can only be called once), add a comment explaining why the panic is caught and ignored.
| // Disable OSC progress if terminal_progress is disabled | |
| // Note: clx::osc::configure can only be called once, so we check first | |
| // Disable OSC progress if terminal_progress is disabled. | |
| // clx::osc::configure may panic if called more than once or on unsupported | |
| // terminals. This is a best-effort optimization only, so we intentionally | |
| // catch and ignore any panic here rather than aborting the process. |
src/ui/multi_progress_report.rs
Outdated
| pub fn allocate_report_id(&self) -> usize { | ||
| // With clx, we don't need explicit IDs - each ProgressJob tracks itself | ||
| 0 | ||
| } |
There was a problem hiding this comment.
Always returning 0 from allocate_report_id suggests this method is now obsolete. If this is a legacy compatibility shim that's no longer needed, consider deprecating it or removing it in a follow-up PR to avoid confusion about its purpose.
src/ui/multi_progress_report.rs
Outdated
| pub fn update_report_progress(&self, _report_id: usize, _position: u64, _length: u64) { | ||
| // With clx, progress is tracked by each ProgressJob directly | ||
| } |
There was a problem hiding this comment.
This empty method with unused parameters suggests it's a legacy compatibility shim. Consider deprecating or removing it in a follow-up PR to clarify that it's no longer needed with the clx migration.
615b751 to
bc0f730
Compare
There was a problem hiding this comment.
Code Review
This pull request successfully migrates the progress reporting from indicatif to the clx library. This simplifies the codebase by removing the custom OSC implementation and leveraging clx's features for progress bars, spinners, and logging suspension. The changes also introduce a new header for multi-tool progress and an environment variable to force progress bars for debugging.
My review has identified a critical issue with a local path dependency in Cargo.toml that needs to be addressed to make the project buildable for other contributors. I've also pointed out a potential improvement in src/ui/multi_progress_report.rs regarding the use of catch_unwind for better code robustness.
| indenter = "0.3" | ||
| indexmap = { version = "2", features = ["serde"] } | ||
| indicatif = { version = "0.18", features = ["improved_unicode"] } | ||
| clx = "1" |
There was a problem hiding this comment.
This dependency on clx uses a local path, which will cause the build to fail for anyone who does not have the clx source code at /Users/jdickey/src/clx. To ensure the project is buildable for all contributors and in CI environments, this should be changed to a dependency from a git repository or a published crate on crates.io.
clx = { git = "https://github.com/jdx/clx" }
| let _ = std::panic::catch_unwind(|| { | ||
| clx::osc::configure(false); | ||
| }); |
There was a problem hiding this comment.
Using std::panic::catch_unwind to handle the clx::osc::configure function being called multiple times is a bit of a code smell. It can hide other potential panics that might occur within this block and makes the control flow less clear.
A safer approach would be to ensure this is only called once using a std::sync::Once or OnceLock at the application level. This would make the initialization explicit and avoid relying on catching panics.
8b79f1f to
0a61ffa
Compare
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 x -- echo |
20.6 ± 0.6 | 19.4 | 26.1 | 1.00 |
mise x -- echo |
21.1 ± 0.8 | 19.4 | 23.2 | 1.02 ± 0.05 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 env |
20.1 ± 0.5 | 18.8 | 23.5 | 1.00 |
mise env |
21.3 ± 0.9 | 19.0 | 27.4 | 1.06 ± 0.05 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 hook-env |
20.4 ± 0.6 | 19.6 | 28.3 | 1.00 |
mise hook-env |
20.5 ± 0.5 | 19.5 | 23.4 | 1.00 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 ls |
18.4 ± 0.5 | 17.3 | 22.6 | 1.00 |
mise ls |
19.7 ± 0.5 | 18.1 | 24.7 | 1.07 ± 0.04 |
xtasks/test/perf
| Command | mise-2026.1.12 | mise | Variance |
|---|---|---|---|
| install (cached) | 112ms | 114ms | -1% |
| ls (cached) | 72ms | 73ms | -1% |
| bin-paths (cached) | 76ms | 74ms | +2% |
| task-ls (cached) | 549ms | 551ms | +0% |
674aa12 to
43b2a74
Compare
cececbd to
e568674
Compare
1aded7d to
299f5e4
Compare
4e19cb6 to
6c48b38
Compare
- Replace indicatif with clx progress library - Add header showing "mise VERSION by @jdx [cur/total]" that updates as tools complete - Use arc spinner style on the right side of progress lines - Add ETA display after progress bar - Use clx's built-in OSC terminal progress support (remove osc.rs) - Use clx pause/resume for clean logging during progress - Add MISE_FORCE_PROGRESS env var to force progress UI in non-TTY Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow clx to be re-resolved to pick up latest version with hide_complete option. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Without this call, the final "Done" state wasn't being rendered before the process exits. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
clx now handles this automatically - set_status(Done) does a synchronous render to ensure the final state is visible before process exit. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
clx's progress_current() clamps the value to the existing total, so when finish_with_icon was called with total=0 (from a previous reset), progress_current(1_000_000) was being clamped to 0. This caused the progress bar to show as empty [ ] instead of being hidden by hide_complete. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add [step/total] counters to progress messages when operations are declared via start_operations(). This provides context about progress in non-TTY environments (CI, piped output). Example output: mise node@22.22.0 [1/3] download node-v22.22.0.tar.gz mise node@22.22.0 [2/3] checksum node-v22.22.0.tar.gz mise node@22.22.0 [3/3] extract node-v22.22.0.tar.gz Changes: - Add next_operation() method to SingleReport trait - Track current_operation in ProgressState and VerboseReport - Prepend [current/total] in set_message() when operations declared - Add next_operation() calls in backends: http, s3, github, aqua - Add next_operation() calls in core plugins: node, go, bun, deno, elixir, java, zig Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When using -f/--force to reinstall a tool, the uninstall step is now counted as operation 1, so progress shows [1/4] uninstall, [2/4] download, etc. instead of [1/1] uninstall followed by [1/3] download. Changes: - Add install_operation_count() method to Backend trait (default: 3) - Query operation count in install_version before starting progress - Add custom install_operation_count for http, s3, aqua backends - Remove start_operations calls from individual backends/plugins - mod.rs now handles start_operations with correct total count Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use published clx version instead of local path dependency - Fix MISE_FORCE_PROGRESS to check truthiness with var_is_true - Improve catch_unwind comment explaining singleton pattern - Remove dead code (allocate_report_id, update_report_progress) - Remove unused _needs_extraction variable in github.rs - Fix aqua operation count to include GitHub API digest case Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace separate initialized flag with header_job.is_some() check. This fixes edge case where init_footer(1) would block subsequent init_footer calls with larger counts from creating the header. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The install_operation_count was using `settings.lockfile && settings.experimental` but the actual install code uses `settings.lockfile`. This caused operation count mismatches when experimental was false but lockfile was true. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bytes() template function to show download progress like "5.2 MB / 10.4 MB" to the left of the ETA. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The clx bytes() template function uses the progress tuple values, which mise maps to 0-1,000,000 scale for multi-operation tracking. This caused incorrect byte displays. Fix by using a custom format_bytes() helper and passing actual byte values through the "bytes" prop instead of relying on clx's built-in bytes() function. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update clx to 1.3.0 which has multi-operation tracking - Remove custom ProgressState and format_bytes from progress_report.rs - Use clx's bytes(total=false, hide_complete=true) for byte display - Remove extraction byte tracking from file.rs and http.rs - Remove install summary feature from install.rs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Deduplicate install_operation_count implementations between HttpBackend and S3Backend by extracting the shared logic to a helper function. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused suspend_if_active and suspend methods from MultiProgressReport - Extract needs_extraction helper in aqua backend to deduplicate condition - Reset MultiProgressReport state in footer_finish for subsequent operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
69ae34b to
4af52d1
Compare
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
bugbot run |
| .await?; | ||
| ctx.pr.next_operation(); | ||
| } else if self.is_version_installed(&ctx.config, &tv, true) { | ||
| return Ok(tv); |
There was a problem hiding this comment.
Redundant is_version_installed check can be cached
Low Severity
is_version_installed is called twice in certain code paths (lines 850 and 865). When ctx.force is true but the version is NOT installed, the check executes on line 850 (as part of the && condition) and again on line 865 (in the else if). Cache the result in a variable: let is_installed = self.is_version_installed(...); let will_uninstall = ctx.force && is_installed; then use else if is_installed on line 865.
### 🚀 Features - **(edit)** add interactive config editor (`mise edit`) by @jdx in [#7930](#7930) - **(lockfile)** graduate lockfiles from experimental by @jdx in [#7929](#7929) - **(task)** add support for usage values in task confirm dialog by @roele in [#7924](#7924) - **(task)** improve source freshness checking with edge case handling by @jdx in [#7932](#7932) ### 🐛 Bug Fixes - **(activate)** preserve ordering of paths appended after mise activate by @jdx in [#7919](#7919) - **(install)** sort failed installations for deterministic error output by @jdx in [#7936](#7936) - **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [#7923](#7923) - **(lockfile)** add atomic writes and cache invalidation by @jdx in [#7927](#7927) - **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [#7925](#7925) - **(upgrade)** respect tracked configs when pruning old versions by @jdx in [#7926](#7926) ### 🚜 Refactor - **(progress)** migrate from indicatif to clx by @jdx in [#7928](#7928) ### 📚 Documentation - improve clarity on uvx and pipx dependencies by @ygormutti in [#7878](#7878) ### ⚡ Performance - **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [#7933](#7933) - use Aho-Corasick for efficient redaction by @jdx in [#7931](#7931) ### 🧪 Testing - remove flaky test_http_version_list test by @jdx in [#7934](#7934) ### Chore - use github backend instead of ubi in mise.lock by @jdx in [#7922](#7922) ### New Contributors - @ygormutti made their first contribution in [#7878](#7878)
## Summary - Replace indicatif with clx progress library for all progress reporting - Add `[step/total]` counters to non-TTY progress output for better context - Use arc spinner style on the right side of progress lines - Add ETA display with smoothed rate calculation (hides when complete) - Show bytes downloaded during download/checksum phases (hides during extraction) - Progress bar hides when complete (using `hide_complete` option) - Use clx's built-in OSC terminal progress support (remove custom osc.rs) - Use clx pause/resume for clean logging during progress display - Add `MISE_FORCE_PROGRESS` env var to force progress UI in non-TTY ## Test plan - [x] `mise i -f node` - verify progress shows download/checksum/extract steps - [x] `mise i node 2>&1 | cat` - verify `[1/4]` step counters in non-TTY mode - [x] Verify ETA appears during downloads with stable (non-jumpy) values - [x] Verify bytes/ETA/progress bar hide when task completes - [x] Verify arc spinner style on the right - [x] Test `MISE_FORCE_PROGRESS=1` in non-TTY environment 🤖 Generated with [Claude Code](https://claude.ai/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it rewires progress state management and install step accounting across multiple backends, which could cause misleading progress or ordering regressions during installs/uninstalls. No auth or data-model changes, but it touches core installation UX paths. > > **Overview** > Migrates progress reporting from `indicatif` to `clx`, replacing the multi-progress UI implementation (`src/ui/multi_progress_report.rs`, `src/ui/progress_report.rs`) and removing the custom OSC implementation (`src/ui/osc.rs`) in favor of `clx`’s built-ins. > > Refactors install progress tracking to be **operation-based**: adds `Backend::install_operation_count()` (with HTTP/S3 helpers) and updates backends/plugins to call `pr.next_operation()` at checksum/extract boundaries, including accounting for forced uninstall steps in `Backend::install_version`. > > Updates logging to pause/resume `clx` progress while emitting terminal logs, adds `MISE_FORCE_PROGRESS` for forcing UI progress in non-TTY, and adjusts dependency/lockfiles (adds `clx`, drops `indicatif`, minor crate bumps). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4af52d1. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### 🚀 Features - **(edit)** add interactive config editor (`mise edit`) by @jdx in [jdx#7930](jdx#7930) - **(lockfile)** graduate lockfiles from experimental by @jdx in [jdx#7929](jdx#7929) - **(task)** add support for usage values in task confirm dialog by @roele in [jdx#7924](jdx#7924) - **(task)** improve source freshness checking with edge case handling by @jdx in [jdx#7932](jdx#7932) ### 🐛 Bug Fixes - **(activate)** preserve ordering of paths appended after mise activate by @jdx in [jdx#7919](jdx#7919) - **(install)** sort failed installations for deterministic error output by @jdx in [jdx#7936](jdx#7936) - **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [jdx#7923](jdx#7923) - **(lockfile)** add atomic writes and cache invalidation by @jdx in [jdx#7927](jdx#7927) - **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [jdx#7925](jdx#7925) - **(upgrade)** respect tracked configs when pruning old versions by @jdx in [jdx#7926](jdx#7926) ### 🚜 Refactor - **(progress)** migrate from indicatif to clx by @jdx in [jdx#7928](jdx#7928) ### 📚 Documentation - improve clarity on uvx and pipx dependencies by @ygormutti in [jdx#7878](jdx#7878) ### ⚡ Performance - **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [jdx#7933](jdx#7933) - use Aho-Corasick for efficient redaction by @jdx in [jdx#7931](jdx#7931) ### 🧪 Testing - remove flaky test_http_version_list test by @jdx in [jdx#7934](jdx#7934) ### Chore - use github backend instead of ubi in mise.lock by @jdx in [jdx#7922](jdx#7922) ### New Contributors - @ygormutti made their first contribution in [jdx#7878](jdx#7878)


Summary
[step/total]counters to non-TTY progress output for better contexthide_completeoption)MISE_FORCE_PROGRESSenv var to force progress UI in non-TTYTest plan
mise i -f node- verify progress shows download/checksum/extract stepsmise i node 2>&1 | cat- verify[1/4]step counters in non-TTY modeMISE_FORCE_PROGRESS=1in non-TTY environment🤖 Generated with Claude Code
Note
Medium Risk
Medium risk because it rewires progress state management and install step accounting across multiple backends, which could cause misleading progress or ordering regressions during installs/uninstalls. No auth or data-model changes, but it touches core installation UX paths.
Overview
Migrates progress reporting from
indicatiftoclx, replacing the multi-progress UI implementation (src/ui/multi_progress_report.rs,src/ui/progress_report.rs) and removing the custom OSC implementation (src/ui/osc.rs) in favor ofclx’s built-ins.Refactors install progress tracking to be operation-based: adds
Backend::install_operation_count()(with HTTP/S3 helpers) and updates backends/plugins to callpr.next_operation()at checksum/extract boundaries, including accounting for forced uninstall steps inBackend::install_version.Updates logging to pause/resume
clxprogress while emitting terminal logs, addsMISE_FORCE_PROGRESSfor forcing UI progress in non-TTY, and adjusts dependency/lockfiles (addsclx, dropsindicatif, minor crate bumps).Written by Cursor Bugbot for commit 4af52d1. This will update automatically on new commits. Configure here.