diff --git a/src/ui.rs b/src/ui.rs
index b64c53f..9c01269 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -101,6 +101,24 @@ pub fn run_tui(cfg: Config) {
let default_cfg = cfg;
loop {
+ // Drive the sweep tick BEFORE drawing + polling, so the run
+ // advances at poll_ms cadence even when no key is pressed.
+ // (The picker + editor modes don't tick — they only react to
+ // keys, so the tick is a no-op for them.)
+ if let Mode::Sweep(app) = &mut mode {
+ let outcome = match app.tick() {
+ Ok(o) => o,
+ Err(e) => {
+ eprintln!("run error: {e}");
+ break;
+ }
+ };
+ if matches!(outcome, TickOutcome::SweepDone) {
+ let finished = std::mem::replace(app, App::empty());
+ mode = Mode::Done(finished);
+ }
+ }
+
terminal.draw(|f| draw(f, &mode)).expect("draw failed");
let poll_ms = match &mode {
Mode::Sweep(app) | Mode::Done(app) => app.run.poll_ms(),
@@ -144,25 +162,10 @@ pub fn run_tui(cfg: Config) {
}
}
Mode::Sweep(app) => {
- // Drive one tick before polling events so the sweep
- // advances even while we're waiting for input.
- let outcome = match app.tick() {
- Ok(o) => o,
- Err(e) => {
- eprintln!("run error: {e}");
- break;
- }
- };
- let done = matches!(outcome, TickOutcome::SweepDone);
- if done {
- // Move the App out of the Sweep mode into Done. We
- // can't do this while `app` is borrowed, so use a
- // sentinel — replace with empty + push the real one
- // into Done below.
- let finished = std::mem::replace(app, App::empty());
- mode = Mode::Done(finished);
- continue;
- }
+ // The tick already ran at the top of the loop (before
+ // draw + poll) so the sweep advances even without input.
+ // Here we only handle key events.
+ let _ = app; // borrow to keep the match arm exhaustive
match key.code {
KeyCode::Char('q') | KeyCode::Esc => break,
_ => {}
@@ -255,10 +258,10 @@ fn editor_key(state: &mut EditorState, key: KeyCode) -> EditorAction {
// Not editing — navigate fields + rows.
match key {
- KeyCode::Up => {
+ KeyCode::Up | KeyCode::Char('k') => {
editor_move(state, -1);
}
- KeyCode::Down => {
+ KeyCode::Down | KeyCode::Char('j') => {
editor_move(state, 1);
}
KeyCode::Left | KeyCode::Right => {
@@ -318,12 +321,13 @@ fn editor_key(state: &mut EditorState, key: KeyCode) -> EditorAction {
state.cursor = state.cfg.workloads.len() - 1;
state.field = EditorField::Name;
}
- // Move the current workload row up/down (reorder).
- KeyCode::Char('k') if state.cursor < state.cfg.workloads.len() && state.cursor > 0 => {
+ // Move the current workload row up/down (reorder). Uses `>`/`<`
+ // (intuitive for ordering) so j/k stay navigation-only.
+ KeyCode::Char('<') if state.cursor < state.cfg.workloads.len() && state.cursor > 0 => {
state.cfg.workloads.swap(state.cursor, state.cursor - 1);
state.cursor -= 1;
}
- KeyCode::Char('j') if state.cursor < state.cfg.workloads.len()
+ KeyCode::Char('>') if state.cursor < state.cfg.workloads.len()
&& state.cursor + 1 < state.cfg.workloads.len() =>
{
state.cfg.workloads.swap(state.cursor, state.cursor + 1);
@@ -672,7 +676,7 @@ fn draw_editor(f: &mut Frame, state: &EditorState) {
f.render_widget(
Paragraph::new(Line::from(vec![
Span::styled(
- "↑↓ row ←→ field Enter edit/toggle a add d del j/k move Esc back",
+ "j/k row ←→ field Enter edit/toggle a add d del </> reorder Esc back",
Style::default().fg(Color::DarkGray),
),
])),
Fix TUI sweep not ticking (7z ran forever) + j/k nav in editor
Two bugs in one: 1. The sweep tick was inside the match &mut mode block, which only ran AFTER event::poll returned (either a key was pressed or the poll timed out + continue'd). When no key was pressed, the poll timed out → continue → the tick never ran → the sweep never advanced → 7z ran forever. Fix: move the tick to the TOP of the loop (before draw + poll) so it runs every iteration regardless of input. 2. The editor used KeyCode::Down for navigation but the test harness (and users) expect j/k to work (same as the picker). Added j/k as Down/Up aliases in the editor. The old j/k reorder handlers are now </> (intuitive for ordering) to avoid the collision. Verified live via forkpty: picker → Custom → editor → Start → 7zip-bench 5s sweep ticks (elapsed/remaining advance) → STOPPED at 5s (7z overruns, run loop stops it) → SweepDone → Done mode → q prints summary. 52/52 tests; clippy clean.
feb1f8ff6355e3506ac77049cb27b9a0f9e532fd
josie <administrator@josie-c.com> · 2026-09-01T22:19 ·
browse files at this commit
parents:
f023dc2