Repository navigation
fix(focus): a click on the focused pane ends the new workspace's lane; keys typed after it reach that pane - #32148
Conversation
…ld meets the #31707 surface hold (red) Review of #31865 (its merge with #31707, comment 6572422551): 1. CreationInputHoldTests.keysForAPersonsNewWorkspaceTypedDuringASurfaceHoldGoToTheNewTerminal: a key typed into a cold terminal opens its surface hold (an adopted lane); the person then asks for a new workspace. CreationInputBuffer.capture prefers the focused (adopted) lane, so the keys typed for the new workspace go to the cold terminal. 2. SecondCreationKeysTests.keysHeldForTheFocusedTerminalReachItWhileAPersonsNewWorkspaceClaimHolds: keys held for the terminal that has the keyboard run again as typed when the hold ends at its limit; while the person's claim holds (the new workspace never showed) the claim keeps every such key that runs no binding, so the line is lost. Both fail on this commit and pass with the fix.
…ring a surface hold; a replayed key held for a terminal reaches it Review of #31865 (its merge with #31707): 1. CreationInputBuffer.capture: an adopted lane (a cold terminal's surface hold, keys carried from another hold) gives way to the person's new-workspace ticket. Keys typed after they asked for the workspace are its terminal's; keys typed before stay the cold terminal's. 2. CreationInputCoordinator: a replayed key that was held for a terminal (it runs again as typed because that terminal has the keyboard) goes to it; the person's keyboard claim keeps only replayed keys typed for no terminal. Before, a hold that ended at its limit while the new workspace was hidden lost the focused terminal's held line. CmuxNextApp lines: +0 (the replay flag carries the lane in the same lines). Regression tests: the two tests of the parent commit (red there).
…pane, not the new workspace (red) Review of #32098 (finding 1): the person asks for a new workspace, then clicks the pane that already has the focus. The click ends their keyboard claim but moves no focus generation (no responder change), so the keys typed after it still take the new workspace's lane through `buffer.newestGeneration == generation`, and they are dropped when the workspace never shows. Fails on this commit: b and c are held and lost.
…; the keys typed after it reach that pane Review of #32098 (finding 1): the person asks for a new workspace, then clicks the pane that already has the focus. The click ended their keyboard claim, but it moves no focus generation (the responder does not change), so the keys typed after it still took the new workspace's lane through `buffer.newestGeneration == generation`, and were dropped when the workspace never showed. When the person's action ends their claim (personActed: the app's one mouse-down subscription, or one of their actions), the window's hold records that they moved on from its new workspaces (CreationInputBuffer.personMovedOn): the generation that kept the lane is cleared, and a key typed now passes on to the focused view at once when every creation of the hold is such a workspace, the key is for no creation's or surface's terminal, and no key that runs as typed waits before it. Keys typed before the click still wait for the new workspace. The rule is in CmuxNextFocusUI; CmuxNextApp lines do not rise. Regression test: PersonTerminalKeyboardClaimTests.keysTypedAfterAClickOnTheFocusedPaneReachThatPane (red on the parent commit).
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
web and size checks: green Shipped in:
|
|
Review (subagent, correctness first): FIX at dbc308d I read the diff of 36fc468 and dbc308d and the full files at the head. I ran no build or test. The fix is right for the case it tests: the person clicks the focused pane, the claim ends, Blockers
Checked, no finding
|
This comment has been minimized.
This comment has been minimized.
…a cold terminal and go to a later creation (red) Review of #32148 (comment 6575210178), two lost-key blockers: (a) ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal: the person's new workspace's hold is open and their click ended its claim as another workspace shows cold; a line typed at once must wait for the focused terminal's surface and run there. With passesOn the keys go on to the window, where no terminal view has them. (b) PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace: after the click, a creation with no tab before its reply (Cmd-T's non-optimistic path) takes the next keys; capture gave them the left workspace's lane (workspaceTickets.max()), and they were dropped when it never showed.
…l keeps its keys and a later creation gets its own Review of #32148 (comment 6575210178), two lost-key blockers: 1. passesOn skipped the REOPEN-F4 surface hold (#31707): with the left workspace's hold still open, a cold terminal that the person clicked to got no surface lane, and the keys typed at once went on to a window where no terminal view had them. Now a hold whose every creation the person left (CreationInputBuffer.personLeftEveryCreation) takes the focused terminal's surface lane as no hold would, and a key passes on only while the focused view takes keys (responderTakesKeys; a remount waits). 2. A creation asked for after the click (Cmd-T's non-optimistic path, no tab before its reply) set the hold's generation again, so capture gave its keys the left workspace's lane (workspaceTickets.max()), and they were dropped when that workspace never showed. capture now never picks a workspace the person left (workspaceTickets.subtracting(movedOnFrom)). #32030's browser page hold, once it lands, needs the same rule (a page still to show keeps the key); its owner is told. Regression tests (red on the parent commit): ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal, PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace.
…n-claim-ended-by-click # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextApp/Focus/CreationInputCoordinator.swift # Packages/macOS/CmuxNext/Sources/CmuxNextFocusUI/CreationInputBuffer.swift
|
Review (review-32148-correctness): SHIP at da9e2e6 Correctness review of the full head (CreationInputBuffer, CreationInputCoordinator, CreationKeyboardClaims, both test files), read in a worktree at da9e2e6. No compile or test run by me; I read the fleet logs. Summary:
Non-blocking notes (not regressions, base behavior):
|
…e keys after the click go on to the clicked pane Review of #32148 (comment 6576859579), note 2: a new-workspace creation whose create failed left its id in the hold's count but not in its workspace tickets, so after the person's click the hold never counted as left (personLeftEveryCreation), and the keys typed after the click waited without a lane, to run as typed when the hold ended (into a second new workspace if that one showed). A failed creation is now recorded as over (failedWorkspaces) and counts as released; the person's action is still needed (their claim keeps the keys until then). Regression test: PersonTerminalKeyboardClaimTests.keysTypedAfterTheClickPassOnWhenAnEarlierNewWorkspaceFailed (red on the parent commit).
… creation's keys (red) Review of #32148 (comment 6576859579), note 1: the person's new workspace replied but the window never shows it; the person clicks, asks for another creation and types. awaitedWorkspace still names the left workspace, so the flush waits until the hold's limit (2 s by default; 8 s in the test) before the creation's keys run. Fails on this commit: the keys do not run within 2 s.
…t never shows Review of #32148 (comment 6576859579), note 1: the hold's flush waited for the window to show the newest new workspace (awaitedWorkspace) even after the person left it with a click. For a workspace that replied and never shows, the keys of a later creation (Cmd-T), and a cold terminal's lane keys, waited until the hold's limit (2 s). The flush now waits only for a workspace the person did not leave (shownWorkspaceToWaitFor). The keys typed for the left workspace before the click go with it when the hold ends: they run there if it shows by then, else they are dropped, as at the limit before. Regression test: PersonTerminalKeyboardClaimTests.aLeftWorkspaceThatNeverShowsDoesNotDelayALaterCreationsKeys (red on the parent commit).
|
Found 1 test failure on Blacksmith runners: Failure
|
… releases the wait for a left workspace (#32352) * test(focus): two key-routing gaps where the person's new-workspace hold meets the #31707 surface hold (red) Review of #31865 (its merge with #31707, comment 6572422551): 1. CreationInputHoldTests.keysForAPersonsNewWorkspaceTypedDuringASurfaceHoldGoToTheNewTerminal: a key typed into a cold terminal opens its surface hold (an adopted lane); the person then asks for a new workspace. CreationInputBuffer.capture prefers the focused (adopted) lane, so the keys typed for the new workspace go to the cold terminal. 2. SecondCreationKeysTests.keysHeldForTheFocusedTerminalReachItWhileAPersonsNewWorkspaceClaimHolds: keys held for the terminal that has the keyboard run again as typed when the hold ends at its limit; while the person's claim holds (the new workspace never showed) the claim keeps every such key that runs no binding, so the line is lost. Both fail on this commit and pass with the fix. * fix(focus): the person's new workspace takes the keys typed for it during a surface hold; a replayed key held for a terminal reaches it Review of #31865 (its merge with #31707): 1. CreationInputBuffer.capture: an adopted lane (a cold terminal's surface hold, keys carried from another hold) gives way to the person's new-workspace ticket. Keys typed after they asked for the workspace are its terminal's; keys typed before stay the cold terminal's. 2. CreationInputCoordinator: a replayed key that was held for a terminal (it runs again as typed because that terminal has the keyboard) goes to it; the person's keyboard claim keeps only replayed keys typed for no terminal. Before, a hold that ended at its limit while the new workspace was hidden lost the focused terminal's held line. CmuxNextApp lines: +0 (the replay flag carries the lane in the same lines). Regression tests: the two tests of the parent commit (red there). * test(focus): keys typed after a click on the focused pane reach that pane, not the new workspace (red) Review of #32098 (finding 1): the person asks for a new workspace, then clicks the pane that already has the focus. The click ends their keyboard claim but moves no focus generation (no responder change), so the keys typed after it still take the new workspace's lane through `buffer.newestGeneration == generation`, and they are dropped when the workspace never shows. Fails on this commit: b and c are held and lost. * fix(focus): a click on the focused pane ends the new workspace's lane; the keys typed after it reach that pane Review of #32098 (finding 1): the person asks for a new workspace, then clicks the pane that already has the focus. The click ended their keyboard claim, but it moves no focus generation (the responder does not change), so the keys typed after it still took the new workspace's lane through `buffer.newestGeneration == generation`, and were dropped when the workspace never showed. When the person's action ends their claim (personActed: the app's one mouse-down subscription, or one of their actions), the window's hold records that they moved on from its new workspaces (CreationInputBuffer.personMovedOn): the generation that kept the lane is cleared, and a key typed now passes on to the focused view at once when every creation of the hold is such a workspace, the key is for no creation's or surface's terminal, and no key that runs as typed waits before it. Keys typed before the click still wait for the new workspace. The rule is in CmuxNextFocusUI; CmuxNextApp lines do not rise. Regression test: PersonTerminalKeyboardClaimTests.keysTypedAfterAClickOnTheFocusedPaneReachThatPane (red on the parent commit). * test(focus): keys after the click that left a new workspace wait for a cold terminal and go to a later creation (red) Review of #32148 (comment 6575210178), two lost-key blockers: (a) ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal: the person's new workspace's hold is open and their click ended its claim as another workspace shows cold; a line typed at once must wait for the focused terminal's surface and run there. With passesOn the keys go on to the window, where no terminal view has them. (b) PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace: after the click, a creation with no tab before its reply (Cmd-T's non-optimistic path) takes the next keys; capture gave them the left workspace's lane (workspaceTickets.max()), and they were dropped when it never showed. * fix(focus): after the click that left a new workspace, a cold terminal keeps its keys and a later creation gets its own Review of #32148 (comment 6575210178), two lost-key blockers: 1. passesOn skipped the REOPEN-F4 surface hold (#31707): with the left workspace's hold still open, a cold terminal that the person clicked to got no surface lane, and the keys typed at once went on to a window where no terminal view had them. Now a hold whose every creation the person left (CreationInputBuffer.personLeftEveryCreation) takes the focused terminal's surface lane as no hold would, and a key passes on only while the focused view takes keys (responderTakesKeys; a remount waits). 2. A creation asked for after the click (Cmd-T's non-optimistic path, no tab before its reply) set the hold's generation again, so capture gave its keys the left workspace's lane (workspaceTickets.max()), and they were dropped when that workspace never showed. capture now never picks a workspace the person left (workspaceTickets.subtracting(movedOnFrom)). #32030's browser page hold, once it lands, needs the same rule (a page still to show keeps the key); its owner is told. Regression tests (red on the parent commit): ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal, PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace. * test(focus): after a failed new workspace and a click, keys go on to the clicked pane (red) Review of #32148 (comment 6576859579), note 2: two new workspaces in one hold, the first one's create fails, then the person clicks the focused pane. The failed ticket is no longer a workspace ticket but still counts in nextID, so personLeftEveryCreation stays false: the keys typed after the click wait without a lane and run as typed when the hold ends, into the second workspace if it shows. Fails on this commit: b and c are held. * fix(focus): a failed new workspace releases its ticket at once, so the keys after the click go on to the clicked pane Review of #32148 (comment 6576859579), note 2: a new-workspace creation whose create failed left its id in the hold's count but not in its workspace tickets, so after the person's click the hold never counted as left (personLeftEveryCreation), and the keys typed after the click waited without a lane, to run as typed when the hold ended (into a second new workspace if that one showed). A failed creation is now recorded as over (failedWorkspaces) and counts as released; the person's action is still needed (their claim keeps the keys until then). Regression test: PersonTerminalKeyboardClaimTests.keysTypedAfterTheClickPassOnWhenAnEarlierNewWorkspaceFailed (red on the parent commit). * test(focus): a left workspace that never shows does not delay a later creation's keys (red) Review of #32148 (comment 6576859579), note 1: the person's new workspace replied but the window never shows it; the person clicks, asks for another creation and types. awaitedWorkspace still names the left workspace, so the flush waits until the hold's limit (2 s by default; 8 s in the test) before the creation's keys run. Fails on this commit: the keys do not run within 2 s. * fix(focus): a click releases the hold's wait for a left workspace that never shows Review of #32148 (comment 6576859579), note 1: the hold's flush waited for the window to show the newest new workspace (awaitedWorkspace) even after the person left it with a click. For a workspace that replied and never shows, the keys of a later creation (Cmd-T), and a cold terminal's lane keys, waited until the hold's limit (2 s). The flush now waits only for a workspace the person did not leave (shownWorkspaceToWaitFor). The keys typed for the left workspace before the click go with it when the hold ends: they run there if it shows by then, else they are dropped, as at the limit before. Regression test: PersonTerminalKeyboardClaimTests.aLeftWorkspaceThatNeverShowsDoesNotDelayALaterCreationsKeys (red on the parent commit). * test(focus): the failed-workspace rule (note 2) is tested where it lives, in CreationInputBuffer The App-level test could not tell the fix from the bug: the test window's focused terminal has no surface, so after the click its keys take that terminal's surface lane (REOPEN-F4) and replay at the hold's end, which is the right target, and before the fix they also replayed (as typed). The rule itself is CreationInputBuffer's: CreationInputHoldTests.aFailedNewWorkspaceCountsAsLeftOnceThePersonActs checks personLeftEveryCreation and passesOn. Red on the base before the fix (red ref branch fix/creation-hold-left-workspace-release-red, never merge). * test(focus): a line typed for a new workspace before the click runs there when it shows a frame after the reply (red) Review of #32352 (comment 6580371831), blocker: Cmd-N, type, click, then the create's reply while the window does not show the workspace yet; the store applies daemon events once per frame, so it shows one frame later. The flush no longer waits for a workspace the person left (shownWorkspaceToWaitFor), so in the reply's turn it dropped the line (dropKeys(ofWorkspacesOtherThan:)). Fails on this commit: the line never runs in the new workspace's terminal. * fix(focus): a left new workspace's own keys wait for it to show with its terminal; the other lanes' keys go now Review of #32352 (comment 6580371831), blocker: the flush no longer waited for a new workspace the person left (note 1), so the keys typed for it before the click were dropped in the create reply's turn. The store applies daemon events once per frame, so the window usually shows the new workspace a frame after the reply. Now a left workspace that replied and still holds keys typed for it (CreationInputBuffer.leftWorkspaceWithKeys) keeps only those keys waiting: until the window shows it with its terminal (then they are bound to its first terminal and run there), or until the hold's limit (then they are dropped, as before). The keys of every other lane run at once (take(focused:keeping:)), so note 1's gain stays: a left workspace with no keys of its own keeps nothing waiting. Docs of open(...) and personMovedOn() and shownWorkspaceToWaitFor say so. Regression test: ColdFocusedTerminalTypeAheadTests.aLineTypedForANewWorkspaceBeforeTheClickRunsThereWhenItShowsAFrameAfterTheReply (red on the parent commit). --------- Co-authored-by: cmux-bot[bot] <348531757+cmux-bot[bot]@users.noreply.github.com>
…'s keys (#32478) * test(focus): two key-routing gaps where the person's new-workspace hold meets the #31707 surface hold (red) Review of #31865 (its merge with #31707, comment 6572422551): 1. CreationInputHoldTests.keysForAPersonsNewWorkspaceTypedDuringASurfaceHoldGoToTheNewTerminal: a key typed into a cold terminal opens its surface hold (an adopted lane); the person then asks for a new workspace. CreationInputBuffer.capture prefers the focused (adopted) lane, so the keys typed for the new workspace go to the cold terminal. 2. SecondCreationKeysTests.keysHeldForTheFocusedTerminalReachItWhileAPersonsNewWorkspaceClaimHolds: keys held for the terminal that has the keyboard run again as typed when the hold ends at its limit; while the person's claim holds (the new workspace never showed) the claim keeps every such key that runs no binding, so the line is lost. Both fail on this commit and pass with the fix. * fix(focus): the person's new workspace takes the keys typed for it during a surface hold; a replayed key held for a terminal reaches it Review of #31865 (its merge with #31707): 1. CreationInputBuffer.capture: an adopted lane (a cold terminal's surface hold, keys carried from another hold) gives way to the person's new-workspace ticket. Keys typed after they asked for the workspace are its terminal's; keys typed before stay the cold terminal's. 2. CreationInputCoordinator: a replayed key that was held for a terminal (it runs again as typed because that terminal has the keyboard) goes to it; the person's keyboard claim keeps only replayed keys typed for no terminal. Before, a hold that ended at its limit while the new workspace was hidden lost the focused terminal's held line. CmuxNextApp lines: +0 (the replay flag carries the lane in the same lines). Regression tests: the two tests of the parent commit (red there). * test(focus): keys typed after a click on the focused pane reach that pane, not the new workspace (red) Review of #32098 (finding 1): the person asks for a new workspace, then clicks the pane that already has the focus. The click ends their keyboard claim but moves no focus generation (no responder change), so the keys typed after it still take the new workspace's lane through `buffer.newestGeneration == generation`, and they are dropped when the workspace never shows. Fails on this commit: b and c are held and lost. * fix(focus): a click on the focused pane ends the new workspace's lane; the keys typed after it reach that pane Review of #32098 (finding 1): the person asks for a new workspace, then clicks the pane that already has the focus. The click ended their keyboard claim, but it moves no focus generation (the responder does not change), so the keys typed after it still took the new workspace's lane through `buffer.newestGeneration == generation`, and were dropped when the workspace never showed. When the person's action ends their claim (personActed: the app's one mouse-down subscription, or one of their actions), the window's hold records that they moved on from its new workspaces (CreationInputBuffer.personMovedOn): the generation that kept the lane is cleared, and a key typed now passes on to the focused view at once when every creation of the hold is such a workspace, the key is for no creation's or surface's terminal, and no key that runs as typed waits before it. Keys typed before the click still wait for the new workspace. The rule is in CmuxNextFocusUI; CmuxNextApp lines do not rise. Regression test: PersonTerminalKeyboardClaimTests.keysTypedAfterAClickOnTheFocusedPaneReachThatPane (red on the parent commit). * test(focus): keys after the click that left a new workspace wait for a cold terminal and go to a later creation (red) Review of #32148 (comment 6575210178), two lost-key blockers: (a) ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal: the person's new workspace's hold is open and their click ended its claim as another workspace shows cold; a line typed at once must wait for the focused terminal's surface and run there. With passesOn the keys go on to the window, where no terminal view has them. (b) PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace: after the click, a creation with no tab before its reply (Cmd-T's non-optimistic path) takes the next keys; capture gave them the left workspace's lane (workspaceTickets.max()), and they were dropped when it never showed. * fix(focus): after the click that left a new workspace, a cold terminal keeps its keys and a later creation gets its own Review of #32148 (comment 6575210178), two lost-key blockers: 1. passesOn skipped the REOPEN-F4 surface hold (#31707): with the left workspace's hold still open, a cold terminal that the person clicked to got no surface lane, and the keys typed at once went on to a window where no terminal view had them. Now a hold whose every creation the person left (CreationInputBuffer.personLeftEveryCreation) takes the focused terminal's surface lane as no hold would, and a key passes on only while the focused view takes keys (responderTakesKeys; a remount waits). 2. A creation asked for after the click (Cmd-T's non-optimistic path, no tab before its reply) set the hold's generation again, so capture gave its keys the left workspace's lane (workspaceTickets.max()), and they were dropped when that workspace never showed. capture now never picks a workspace the person left (workspaceTickets.subtracting(movedOnFrom)). #32030's browser page hold, once it lands, needs the same rule (a page still to show keeps the key); its owner is told. Regression tests (red on the parent commit): ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal, PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace. * test(focus): after a failed new workspace and a click, keys go on to the clicked pane (red) Review of #32148 (comment 6576859579), note 2: two new workspaces in one hold, the first one's create fails, then the person clicks the focused pane. The failed ticket is no longer a workspace ticket but still counts in nextID, so personLeftEveryCreation stays false: the keys typed after the click wait without a lane and run as typed when the hold ends, into the second workspace if it shows. Fails on this commit: b and c are held. * fix(focus): a failed new workspace releases its ticket at once, so the keys after the click go on to the clicked pane Review of #32148 (comment 6576859579), note 2: a new-workspace creation whose create failed left its id in the hold's count but not in its workspace tickets, so after the person's click the hold never counted as left (personLeftEveryCreation), and the keys typed after the click waited without a lane, to run as typed when the hold ended (into a second new workspace if that one showed). A failed creation is now recorded as over (failedWorkspaces) and counts as released; the person's action is still needed (their claim keeps the keys until then). Regression test: PersonTerminalKeyboardClaimTests.keysTypedAfterTheClickPassOnWhenAnEarlierNewWorkspaceFailed (red on the parent commit). * test(focus): a left workspace that never shows does not delay a later creation's keys (red) Review of #32148 (comment 6576859579), note 1: the person's new workspace replied but the window never shows it; the person clicks, asks for another creation and types. awaitedWorkspace still names the left workspace, so the flush waits until the hold's limit (2 s by default; 8 s in the test) before the creation's keys run. Fails on this commit: the keys do not run within 2 s. * fix(focus): a click releases the hold's wait for a left workspace that never shows Review of #32148 (comment 6576859579), note 1: the hold's flush waited for the window to show the newest new workspace (awaitedWorkspace) even after the person left it with a click. For a workspace that replied and never shows, the keys of a later creation (Cmd-T), and a cold terminal's lane keys, waited until the hold's limit (2 s). The flush now waits only for a workspace the person did not leave (shownWorkspaceToWaitFor). The keys typed for the left workspace before the click go with it when the hold ends: they run there if it shows by then, else they are dropped, as at the limit before. Regression test: PersonTerminalKeyboardClaimTests.aLeftWorkspaceThatNeverShowsDoesNotDelayALaterCreationsKeys (red on the parent commit). * test(focus): the failed-workspace rule (note 2) is tested where it lives, in CreationInputBuffer The App-level test could not tell the fix from the bug: the test window's focused terminal has no surface, so after the click its keys take that terminal's surface lane (REOPEN-F4) and replay at the hold's end, which is the right target, and before the fix they also replayed (as typed). The rule itself is CreationInputBuffer's: CreationInputHoldTests.aFailedNewWorkspaceCountsAsLeftOnceThePersonActs checks personLeftEveryCreation and passesOn. Red on the base before the fix (red ref branch fix/creation-hold-left-workspace-release-red, never merge). * test(focus): a line typed for a new workspace before the click runs there when it shows a frame after the reply (red) Review of #32352 (comment 6580371831), blocker: Cmd-N, type, click, then the create's reply while the window does not show the workspace yet; the store applies daemon events once per frame, so it shows one frame later. The flush no longer waits for a workspace the person left (shownWorkspaceToWaitFor), so in the reply's turn it dropped the line (dropKeys(ofWorkspacesOtherThan:)). Fails on this commit: the line never runs in the new workspace's terminal. * fix(focus): a left new workspace's own keys wait for it to show with its terminal; the other lanes' keys go now Review of #32352 (comment 6580371831), blocker: the flush no longer waited for a new workspace the person left (note 1), so the keys typed for it before the click were dropped in the create reply's turn. The store applies daemon events once per frame, so the window usually shows the new workspace a frame after the reply. Now a left workspace that replied and still holds keys typed for it (CreationInputBuffer.leftWorkspaceWithKeys) keeps only those keys waiting: until the window shows it with its terminal (then they are bound to its first terminal and run there), or until the hold's limit (then they are dropped, as before). The keys of every other lane run at once (take(focused:keeping:)), so note 1's gain stays: a left workspace with no keys of its own keeps nothing waiting. Docs of open(...) and personMovedOn() and shownWorkspaceToWaitFor say so. Regression test: ColdFocusedTerminalTypeAheadTests.aLineTypedForANewWorkspaceBeforeTheClickRunsThereWhenItShowsAFrameAfterTheReply (red on the parent commit). * test(focus): a shown second new workspace ends the wait for a left one's keys (red) Review of #32352 (comment 6581603361), note 2: Cmd-N (W1), type, click, Cmd-N (W2). When the window shows W2 with its terminal, W1's kept keys (keysKeptForLeftWorkspace) still kept the hold open until its limit, so keys typed into W2's shown terminal waited up to 2 s; before #32352 the hold ended there and W1's keys were dropped. Fails on this commit. * fix(focus): a shown second new workspace ends the wait for a left one's keys Review of #32352 (comment 6581603361), note 2: Cmd-N (W1), type, click, Cmd-N (W2). Once the window shows W2 (the workspace the person did not leave), keysKeptForLeftWorkspace returns nil: the hold ends there as it did before #32352, so the keys typed into W2 go on at once, and W1's kept keys are dropped with the hold (its workspace is not the one shown), as before. While W2 has not shown, W1's own keys still wait for W1. Regression test: CreationInputHoldTests.aShownSecondWorkspaceEndsTheWaitForALeftOnesKeys (red on the parent commit).
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
#32098 has landed; this branch is merged with feat (da9e2e6).
Lost keys (review of #32098, finding 1, #32098 (comment)). The steps:
The click ends the claim (
personActedfrom the app's one mouse-down subscription), but it moves no focus generation: the responder does not change, and cmux-focus-core'sis_noop_responderreturns before the generation bump. So the keys typed after the click still took W's lane throughbuffer.newestGeneration == generation, and they were dropped when W never showed.After this change, when the person's action ends their claim, the window's hold records that they moved on from its new workspaces (
CreationInputBuffer.personMovedOn()). The generation that kept the lane is cleared. A key typed now passes on to the focused view at once when all three of these hold:Keys typed before the click still wait for W. The rule is in CmuxNextFocusUI. cmux-focus-core is not changed (it is an FFI input). CmuxNextApp lines: +0.
REOPEN-F4 owner (a02ba201): please look; this is the creation hold next to your #31707 surface hold.
Testing
Focused command (fleet, Mac):
package-test-lane.sh suite Packages/macOS/CmuxNext PersonTerminalKeyboardClaimTests.keysTypedAfterAClickOnTheFocusedPaneReachThatPane: the keys typed after the click were lost (delivered == []), and the window still kept the keyboard for the creation.Review FIX repair (comment 6575210178)
Two lost-key blockers, each with a red test first (red ref c800f7d):
passesOnskipped the fix(focus): a reopened window's focused terminal is presented first, and keys typed before its surface wait for it (REOPEN-F4) #31707 surface hold. A cold terminal that the person clicked to, with the left workspace's hold still open, got no surface lane, so a line typed at once reached no terminal view. Fix: a hold whose every creation the person left (personLeftEveryCreation) takes the focused terminal's surface lane as no hold would. A key passes on only whileresponderTakesKeysholds, and no fix(focus): the reopen key hold also waits for a restored browser tab's page; Cmd-L reaches its address bar (REOPEN-F4 browser case) #32030 page is awaited (!awaitsPage; fix(focus): the reopen key hold also waits for a restored browser tab's page; Cmd-L reaches its address bar (REOPEN-F4 browser case) #32030 landed while this was open and is merged in).workspaceTickets.max()), and its keys were dropped. Fix:workspaceTickets.subtracting(movedOnFrom).max().ColdFocusedTerminalTypeAheadTests.aLineTypedAsAColdWorkspaceShowsAfterTheClickThatLeftANewWorkspaceReachesItsTerminal: the line never ran in the cold terminal.PersonTerminalKeyboardClaimTests.keysTypedForACreationAfterTheClickNeverGoToTheLeftWorkspace: replayed == [].Observed / Not run
Observed: the fleet steps above. Not run: a live click in a tagged build; a click that moves the focus (that path already bumps the generation and is covered by aPersonsFocusMoveEndsTheClaim).
Changelog
Fixed: Keys typed after a click on the focused pane, while a new workspace opens, reach that pane and are no longer lost.
Proof
No capture: key routing only.