Conversation
When a key is pressed from within an active oneshot layer (oneshot_depth > 0 on the originating layer) and triggers an Op::Oneshot* action (such as oneshotm), deactivate and pop the originating layer before activating the target oneshot layer. This prevents the previous oneshot layer from lingering active and shadowing subsequent base layer keys, while preserving sequential oneshot modifier chaining when tapping modifier oneshots from the base layer. Bump version to 0.3.5.
Automated code review9 findings in Bugs / cleanup to be fixed
No code change planned (existing/intentional design)
Fix commits incoming on this branch shortly. |
Code review of the previous commit found the auto-pop fix incomplete and partly incorrect: - Op::Layer/Op::LayerM and Op::Overload could also be triggered from within an active oneshot layer but never popped it, so the same lingering-layer bug still reproduced through those ops. - The pop only decremented oneshot_depth/active by 1, so a layer armed twice before being consumed (e.g. double-tapping the oneshot key) stayed active after the "fix" ran. - The pop logic was duplicated between the Oneshot-family and OneshotMulti arms instead of centralized, which is exactly why Layer/Overload missed it. - The pop ran after any macro/nested-descriptor side effects instead of before them. - pending_overload/pending_timeout replay a layer index (`dl`) captured at press time into execute_descriptor an arbitrary amount of time later; the pop-check had no way to tell a stale replay from a fresh one, so it could mis-pop an unrelated oneshot latch armed/consumed on the same layer index in the meantime. Extract a single pop_originating_oneshot_layer helper (fully clearing oneshot_depth via a while loop, same pattern as clear_oneshot) and call it from all four press branches that can be reached from within an active oneshot layer. Guard it with an oneshot_depth snapshot captured alongside `dl` in OverloadState/TimeoutState, threaded through execute_descriptor as oneshot_snapshot: Option<u8> -- None for every synchronous/immediate call, Some(snapshot) for the two deferred-replay call sites -- so a stale replay only pops if the live depth still matches what was captured at press time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Pushed a fix for all 7 addressed findings in d85f75d — summary:
Added 4 regression tests covering each of these. All 98 tests pass, The two "no code change" findings (mod-aggregation exclusion, bounds guard) still stand as noted above — existing/intentional design, not touched by this fix. |
Summary
When a key is pressed from within an active one-shot layer (
oneshot_depth > 0on the originating layer) and triggers anOp::Oneshot*action (such asoneshotm), the originating layer is now automatically deactivated and popped before activating the target one-shot layer.Problem
Previously,
Op::Oneshot*actions did not pop or clear any active one-shot layers. When activating a one-shot macro layer (e.g.c+space = oneshot(macros)) and then pressing a key mapped tooneshotm(shift, macro(dot space)), the[macros]layer remained active withoneshot_depth == 1. A subsequent keypress (e.g.a) was then mistakenly resolved against[macros](executinga = oneshotm(shift, macro(S-1 space))producing!) instead of falling back to[main]with Shift (A).Solution
self.layer_state[layer].oneshot_depth > 0on the originating layer index duringOp::Oneshot | Op::OneshotM | Op::OneshotKandOp::OneshotMulti.self.deactivate_layer(output, layer)and decrementself.layer_state[layer].oneshot_depth -= 1.oneshot(shift)thenoneshot(control)on[main]) remains fully functional and continues to aggregate modifiers without popping each other.0.3.5.Tests
test_oneshotm_inside_oneshot_layer_pops_originating_layertest_oneshot_modifier_chaining_aggregates