fix(rofi): #143 — reset selection to row 0 on query edits (inputchange)

Upstream keeps the selected row *index* across a refilter (rofi#2317),
so backspacing grew the list back under a stationary highlight and Enter
launched the wrong app. The maintainer's reply pointed at the
inputchange {} config block — adopted as pure config in the generated
config.rasi (kb-row-first on every query edit), no patch, no source
build. Covers every rofi surface: drun, text menus, dmenu pickers.

V2: headless VM (theme-shot variant driving QMP keystrokes). On HEAD the
repro left the highlight on row 3 (kitty -> Bulk Rename); patched, the
highlight snaps to the first entry after backspace — verified in the
executive-slate drun grid, boreal's whole-swap grid, and the
keyboard-layout dmenu picker. nix flake check --no-build passes; the
rendered config.rasi carries the nested block.

Backlog #143 deleted (watch closed), decision recorded as Resolved,
ROADMAP checkmark added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 20:37:35 +01:00
parent 8a4914c22e
commit f899b192fe
3 changed files with 32 additions and 56 deletions

View File

@@ -33,62 +33,6 @@ flake pin are different root causes even when they show up on the same machine.
## NEXT
### 143. Rofi keeps the selected *row number* when the search changes, so the highlight lands on an unrelated entry
Bernardo 2026-07-16, and his repro is exact: open the app menu, type `ca`, move
the selection two items right (onto ChatGPT), press backspace once (query is
now `c`). The list re-expands — first entry is now Slack — but the highlight
stays on the **third row**, which is now GHex, an app that has nothing to do
with what he typed. Enter at that moment launches the wrong thing.
**Cause — upstream rofi (2.0.0, `source/widgets/listview.c`), not our config.**
A filter change ends in `listview_set_num_elements()`, which does not reset the
selection; it re-asserts the old one:
```c
lv->req_elements = rows;
listview_set_selected(lv, lv->selected); /* the *previous* index */
```
and `listview_set_selected()` only clamps it to the new bounds:
```c
lv->selected = MIN(selected, lv->req_elements - 1);
```
So what is preserved is the **row number**, not the entry — nothing checks that
row 2 still holds the thing that was selected, or that it matches the query at
all. Typing *more* hides this (the list shrinks, the clamp usually drags the
highlight along); **backspacing exposes it**, because the list grows back
underneath a stationary index. There is no option for it: `-dump-config` has
nothing about selection-on-refilter, and `auto-select` is a different feature
(it fires only when exactly one row survives).
**One correction to the report:** it is not the app menu. `listview` is the
widget behind **every** rofi surface we ship, so our text menus (Recovery,
System, Preferences…) do the same. It is merely far more visible in drun, where
the list is long and — because we set `sort = true` — reorders on every
keystroke, so a stationary index points somewhere new each time. In a short
text menu you would probably see it and correct without noticing why.
**Reported upstream 2026-07-16: https://github.com/davatorium/rofi/issues/2317**
(open, filed as `bemagri`, with the 2.0.0 line numbers and the observation that
`rofi_view_set_selected_line` already maps a stable id through `line_map` — so
the fix reuses an existing primitive rather than inventing one). No patch was
sent: the scoping call is the maintainer's, since keeping the index across a
*reload* looks deliberate (#1064 asked for exactly that, and got it in 1.7.4).
No duplicate found before filing.
**Decided 2026-07-16 (Bernardo): wait for upstream. Do not carry a patch.** The
overlay option was real but priced badly — our derivations are in no binary
cache, so a patched rofi means **every machine compiles rofi from source**, on
every lock bump, to fix a highlight. That is a permanent, distro-wide install
cost for an annoyance with a free workaround (glance before you press Enter).
**This item is now a watch, not work:** the only thing to do is check
rofi#2317, and take the fix when a release carries it. If it is still open at
the next lock bump, that is fine — nothing here rots meanwhile.
*Last checked 2026-07-17: open, no maintainer response, no linked PR.*
### 152. Generated waybar polish: bar height vs workspace highlighter, right-edge icon spacing
Bernardo, 2026-07-17. Two visual fixes to the **generated** bar (the one
@@ -353,6 +297,12 @@ decide. **Resolved** entries stay for history; agents treat them as closed.
### Resolved (2026-07-17)
- **#143 rofi refilter highlight** — the 07-16 "wait for upstream" ruling
was priced against carrying a patch; the maintainer's reply on
rofi#2317 pointed at the `inputchange {}` config block instead. Adopted
same day as pure config (`kb-row-first` on query edits, generated
config.rasi) — no patch, no source build, watch closed
(ROADMAP § Rofi highlight).
- **#120 netinstall** — stays deferred in PROPOSED (re-affirmed). When it
is promoted, a public binary cache (cachix) is the likely first step.
- **#134 unstable packages** — build it: Nomarchy carries the

View File

@@ -589,6 +589,25 @@ Design/decision records and a running log of shipped work (items marked
hardened against — a clean install cannot reach that state. V2:
`checks.doctor` grew a linger sub-case (warn fires, exit stays 0, clears
after `disable-linger`). The Waybar exec-once loose thread became #149.
- ✓ **Rofi highlight lands on an unrelated entry after backspace (#143,
2026-07-17):** upstream keeps the selected row *index* across a refilter
(rofi#2317), so backspacing grew the list back under a stationary
highlight — Enter then launched the wrong app. Bernardo's 07-16 ruling
("wait for upstream, no source-built rofi distro-wide") was priced
against a patch; the maintainer's reply pointed at a knob the item's
`-dump-config` survey had missed: the `inputchange {}` configuration
block. Shipped as config, zero build cost: `inputchange { action:
"kb-row-first"; }` in the generated `config.rasi` (rofi.nix
extraConfig — home-manager renders nested sections), so every edit of
the query resets the highlight to row 0, dmenu/launcher/text-menus
alike — the same "reset on filter change" dmenu and fuzzel ship.
Trade-off accepted: arrow-down-then-refine no longer holds position,
but that is precisely the interaction that was broken. V2 headless VM
(scratch theme-shot variant driving QMP keystrokes): on HEAD the
repro's highlight stayed on row 3 ("kitty" → "Bulk Rename"); patched,
backspace snaps it to the first entry — shown in the drun grid
(executive-slate), boreal's whole-swap grid, and the keyboard-layout
dmenu picker.
- ✓ **Dock mode survives a rebuild (#142, 2026-07-16):** Bernardo: every rebuild
while docked re-lit the laptop panel and threw a workspace onto it, and he
re-picked Dock mode by hand. It was not forgetfulness — **a rebuild performed

View File

@@ -1827,6 +1827,13 @@ in
case-smart = false;
sort = true;
sorting-method = "normal";
# Selection follows the row *index* across a refilter, not the
# entry — with sort=true a backspace can leave the highlight on an
# unrelated app (rofi#2317; maintainer pointed at this knob).
# Reset to row 0 on every query edit, like dmenu/fuzzel.
inputchange = {
action = "kb-row-first";
};
};
# Whole-swap themes bring their own rofi.rasi; otherwise the theme