Repository navigation
fix(herdr): show the pane's session when pane.focus focuses it - #1546
Conversation
|
Thanks Jonas, this is a really nice catch, and the source links made it easy to check. I read herdr 0.9.5 alongside it and you're right: One thing on the event order. When the pane isn't already the focused one in its session, |
a671c16 to
2dd3b44
Compare
|
Thanks for reading it against herdr, and for catching the order. You're right, and I've done it in this PR rather than a follow-up: ff1b6dc.
I've also rebased on main (c606b6b) and re-run the controls there. Since the test now reads the focus events before it checks the client, main and the |
1b609f5 to
7d653bc
Compare
herdr 0.9.5's pane.focus and agent.focus make the pane's workspace the active one (handle_pane_focus and focus_pane_in_workspace in herdr's src/app). A herdr workspace is a tuios session, but herdrFocusPane only ran focus-window, which focuses the pane inside its own session. A pane in a session no client showed was focused where nobody could see it, and the client stayed on the session it was on. herdrFocusPane now moves the attached client to the pane's session after focus-window, the way workspace.focus already did. That move is herdrShowSession, taken out of herdrWorkspaceFocus so both share it, with the same choice of client and the same select-workspace grant. With no client attached the pane is still focused in its session, as before. TestHerdrFocusShowsThePanesSession covers a focus in the shown session, a pane.focus across sessions and an agent.focus back. Its negative controls are in e2e/tui/NEGATIVE_CONTROLS.md.
…sion herdr sends workspace_focused, tab_focused and pane_focused whenever the active workspace or pane changes (emit_focus_api_events in herdr's src/app/api.rs). tuios accepted subscriptions to those events but never sent them for a move between sessions, so a herdr client that re-reads its state on a focus event kept showing the old focus until its next refresh, after a pane.focus had moved the attached client. The herdr translator now reads client-session-changed. A client that enters a session it did not show sends the three events, for that session, its current tab and its focused pane. The translator remembers the session each client shows, so a rename, which re-announces the client in the same session, sends nothing. TestHerdrFocusShowsThePanesSession now subscribes to the focus events and checks them for the move. The control is in e2e/tui/NEGATIVE_CONTROLS.md.
herdr sends focus events only for the active workspace. A pane.focus on a pane its session did not have focused ran focus-window before the client moved, and the translator turned that window-focused into a pane_focused for a session nobody showed. The stream then read pane_focused, workspace_focused, tab_focused, pane_focused, where herdr sends the three once, workspace first. The translator now keeps the session each client is in, and drops window-focused for a session no client is in. With no client attached it sends pane_focused as before, since there is no active workspace to compare with. The move's own pane_focused names the pane. TestHerdrFocusShowsThePanesSession now focuses another window in the far session first, and checks the focus events come once each, in herdr's order. The control is in e2e/tui/NEGATIVE_CONTROLS.md.
The control table for TestHerdrFocusShowsThePanesSession named main as 57150e1 and quoted the client check for it. Since the test reads the focus events before it checks the client, a build without the client move fails at the event stream instead. Main at c606b6b and the build with the herdrShowSession call cut were run again against the test as it stands, and the table quotes what they print. The translator control names its commit after the rebase.
7d653bc to
b1d5a51
Compare
What does this pull request do?
herdr's
pane.focusandagent.focusnow show the pane's session on the attached client. Until now they focused the pane inside its own session and left the client where it was, so a pane in another session was focused where nobody could see it.The herdr event stream also sends
workspace_focused,tab_focusedandpane_focusedwhen a client moves to another session, so herdr clients that re-read their state on those events see the new focus at once.Follows #1493, which made
pane.focusmark the pane seen.Motivation / Context
tuios follows herdr's API at 0.9.5. There, focusing a pane makes the pane's workspace the active one:
handle_pane_focuscallsfocus_pane_in_workspace(src/app/api/panes.rs L491-L507)focus_pane_in_workspaceswitches to the pane's workspace and tab before it focuses the pane (src/app/actions.rs L226-L254)switch_workspace_tabsets that workspace active (src/app/actions.rs L406-L420)workspace_focused,tab_focusedandpane_focused(accept_current_focus_with_api_eventsandemit_focus_api_events, src/app/api.rs L833-L874)All links are at the
v0.9.5tag's commit.A herdr workspace is a tuios session (
docs/AGENT_STATE.md, "How tuios maps onto herdr"). tuios already shows the session forworkspace.focus, by moving the attached client the way the session switcher does.pane.focusran onlyfocus-window, which focuses a pane within its session and never moves a client to another session.What has been changed
pane.focus,agent.focus: afterfocus-window, the attached client moves to the pane's session when it isn't showing it already. With no client attached, the pane is still focused in its session, as before.client-session-changed. A client that moves from one session to another sendsworkspace_focused,tab_focusedandpane_focusedfor the new session, its current tab and its focused pane, once each and in that order. A client's first attach sends nothing, since herdr has no attach, only a switch. A rename, which re-announces a client in the same session, sends nothing either. Awindow-focusedin a session no client is in sends nopane_focused, because herdr sends focus events only for the active workspace. Without that, apane.focuson a pane that wasn't the focused one in its session readpane_focused,workspace_focused,tab_focused,pane_focused. With no client attached,pane_focusedis sent as before.herdrShowSession, taken out ofherdrWorkspaceFocus, so both methods pick the client the same way (the one showing the caller's session, else the one showing the active workspace) and need the sameselect-workspacegrant.workspace.focusbehaves as before.docs/AGENT_STATE.md(the method and event tables) anddocs/protocol.md("Changes to existing verbs").e2e/tui/herdr_focus_session_test.go, recorded ine2e/tui/NEGATIVE_CONTROLS.md.Notes on compatibility
pane.focusoragent.focuson a pane in another session now moves the attached tuios client to that session, as herdr moves its own UI.workspace.focused,tab.focusedorpane.focusednow get those events when a client switches sessions, throughpane.focus,workspace.focusor the session switcher. Attaching a client sends none of them.pane.focusedno longer get it for a window focused in a session no client shows, while a client is attached elsewhere. It comes when a client moves there.Follow-up, for a later PR: event-hook plugins see three events per switch
Plugin event hooks are fed by the same translator, so a plugin subscribed to all three focus events now runs three times, at once, on a session switch.
plugins/pr-statusis one: its three runs check the saved text before any of them has written it, so a switch after the minute-long cache has gone stale makes up to threegh pr viewcalls instead of one. The cell still ends up right; the cost is the extra calls.This matches herdr, which sends the same three events, so this PR leaves it as is. We may want to handle it differently down the road, for instance with a lock in
pr-status.shso only one run callsgh, or by having the plugin listen topane.focusedalone. That belongs in its own PR.Binary size cost
Measured with go1.27.3, against the base c606b6b:
+4,096 bytes(46,944,416 → 46,948,512)+16,560 bytes(43,724,354 → 43,740,914)Negative controls
Control run (
TestHerdrFocusShowsThePanesSession, recorded ine2e/tui/NEGATIVE_CONTROLS.md):herdrShowSessioncall inherdrFocusPane: same messageclient-session-changedcase in the herdr translator: "the stream ended before workspace_focused and pane_focused"pane_focusedfor a session no client is in (b97aa14): "the focus events read pane_focused workspace_focused tab_focused pane_focused, want workspace_focused tab_focused pane_focused"TestPluginPRStatusguards the attach case: with focus events on attach, its three hook runs each calledgh(CI run 41798073377, shard 2: "gh ran 3 times for two focuses in a minute, want 1").