Skip to content

More reactive updates with enable_steady_tick()#760

Open
MoreDelay wants to merge 5 commits intoconsole-rs:mainfrom
MoreDelay:responsive-steady-tick
Open

More reactive updates with enable_steady_tick()#760
MoreDelay wants to merge 5 commits intoconsole-rs:mainfrom
MoreDelay:responsive-steady-tick

Conversation

@MoreDelay
Copy link

I have a use case where I create two progress bars where the first bar shows the overall progress whereas the second bar shows the progress of the current task, each also showing the elapsed time. A task can take a few seconds or up to a few minutes. This is exactly the kind of situation where one would use enable_steady_tick() to let the overall progress bar update its timer.

However I noticed that on task switches, the overall progress bar lags behind ever so slightly as the tick gets ignored on its increment, and thus waits until the specified interval has passed. I would like to have the overall progress bar update at the same time as the task progress bar. In this situation, I would either have to make due with a stale elapsed timer, or implement my own ticker thread logic around the bar.

So instead, I propose to add a configuration option to specify how the steady ticker should react to calls to tick().

The first commit changes the behavior such that the bar gets updated immediately on a call to tick(), even with a running ticker. The second commit adds a configuration option to get back the old behavior if preferred. This is currently a breaking API change on enable_steady_tick(), so I'm not sure if you may want this to be a new method instead.

Feel free to leave suggestions, or whether or not these changes are in scope for this project.

@djc
Copy link
Member

djc commented Jan 23, 2026

I don't really think it's a good idea to change the documented behavior for steady ticks in a semver-compatible release, I'm not confident in the proposed changes (and I don't have time to dig in in the near future), and I don't think it's worth a semver-incompatible release.

Note that I'm not saying the idea is wholly without merit -- I can see where you're coming from and it might make sense. But as a project that mostly gets passive, volunteer maintenance, I don't think this is a change I'm able to digest soon.

@MoreDelay
Copy link
Author

I expected as much, these commits are meant more to act as a basis for discussion. Would you say it is fine to add a new method that uses the new behavior, perhaps something like enable_steady_tick_reactive()? In that case the config enum is only used internally and the previous behavior remains as it was.

@djc
Copy link
Member

djc commented Jan 23, 2026

Probably, though I'd like a more pithy/descriptive name.


/// Behavior of a steady ticker when its progress bar is ticked
#[derive(Debug, Clone, Copy)]
pub(crate) enum TickerReaction {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this should go below Ticker.

Comment on lines +798 to +814
let now = Instant::now();

let do_tick = match reaction {
TickerReaction::Immediately => true,
TickerReaction::OnTimeout => match last_tick {
None => true,
Some(last_tick) => {
let passed = now - last_tick;
passed >= interval
}
},
};

if do_tick {
state.tick(now);
last_tick = Some(now);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is confused about what it wants to be. If you want .tick() to be responsive, IMO it should not affect a running ticker at all.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know what you mean, but this would actually result in a different behavior for spinners. When the spinner thread keeps track of the last tick, then there will always be an interval pause until the next automatic tick happens. When we just do the tick outside with no communication with the thread, then these reactive ticks and the automatic ticks appear irregular.

The attached video demonstrates this, where all tickers tick once a second, while the bars increments every 1.2 seconds. The "Inside Ticker" bar uses a responsive ticker as implemented here, the "Outside Ticker" uses the original ticker implementation but also ticks on increments.

To me both approaches are fine, I just want you to be aware.

ticker-behavior.webm

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking more about it, I found a way to get the desired spinner behavior without that complicated timeout logic. Now the thread is only notified when we want it to tick, so the check is moved outside.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants