4ec53cb4
feat: x on a pane still waiting is refused, not dropped
a73x 2026-08-30 16:52
Commit message
src/tui/wall_test_wall.zig
| Old | New | ||
|---|---|---|---|
| @@ -1230,3 +1230,17 @@ test "State.waiting has a word of its own, and truncation drops the label before | |||
| 1230 | if (!std.mem.endsWith(u8, bar, " [waiting]")) return error.WaitingBarLostTheStateWord; | 1230 | if (!std.mem.endsWith(u8, bar, " [waiting]")) return error.WaitingBarLostTheStateWord; |
| 1231 | if (bar.len > 30) return error.WaitingBarOverranTheTerminal; | 1231 | if (bar.len > 30) return error.WaitingBarOverranTheTerminal; |
| 1232 | } | 1232 | } |
| 1233 | |||
| 1234 | test "endKey: x on a pane that has not bound yet is refused - a drop would last one poll" { | ||
| 1235 | var shared = Shared{ .out_fd = -1, .size = .{ .cols = 80, .rows = 24 }, .is_tty = true }; | ||
| 1236 | var tiles = fixture.diffFixture(&shared); | ||
| 1237 | tiles[1].pending = true; | ||
| 1238 | tiles[1].alive.store(false, .release); | ||
| 1239 | tiles[1].state = .waiting; | ||
| 1240 | // The refusal, not the local drop the same fields would earn a tile | ||
| 1241 | // whose dial never landed: this pane's session is real, and the | ||
| 1242 | // daemon's next list would birth a dropped tile straight back. | ||
| 1243 | try std.testing.expectEqual(EndKey.waiting, wv.endKey(&tiles[1], 0)); | ||
| 1244 | tiles[1].pending = false; | ||
| 1245 | try std.testing.expectEqual(EndKey.drop, wv.endKey(&tiles[1], 0)); | ||
| 1246 | } | ||
src/tui/wallview.zig
| Old | New | ||
|---|---|---|---|
| @@ -536,6 +536,9 @@ pub const EndKey = union(enum) { | |||
| 536 | ask: client.SwitchIntent, | 536 | ask: client.SwitchIntent, |
| 537 | /// No session yet: the TILE goes, locally. | 537 | /// No session yet: the TILE goes, locally. |
| 538 | drop, | 538 | drop, |
| 539 | /// A pending pane. Its session is real — the daemon's next list would | ||
| 540 | /// birth a dropped tile straight back — and its bind is a poll away. | ||
| 541 | waiting, | ||
| 539 | /// Nothing to do, and a sentence owed. | 542 | /// Nothing to do, and a sentence owed. |
| 540 | none, | 543 | none, |
| 541 | }; | 544 | }; |
| @@ -549,6 +552,7 @@ pub fn endKey(t: *Tile, now: i64) EndKey { | |||
| 549 | // back — but a tile whose host no poll can reach (a declined prompt, a | 552 | // back — but a tile whose host no poll can reach (a declined prompt, a |
| 550 | // box that is down) was otherwise on the wall for the wall's life with | 553 | // box that is down) was otherwise on the wall for the wall's life with |
| 551 | // no key that could remove it. | 554 | // no key that could remove it. |
| 555 | if (t.pending) return .waiting; | ||
| 552 | if (!t.alive.load(.acquire)) return .drop; | 556 | if (!t.alive.load(.acquire)) return .drop; |
| 553 | // A pump still on its FIRST dial is alive and parked in `dial`, which | 557 | // A pump still on its FIRST dial is alive and parked in `dial`, which |
| 554 | // polls `gone` and never `ask`: the key would be swallowed for as long | 558 | // polls `gone` and never `ask`: the key would be swallowed for as long |
| @@ -2439,6 +2443,11 @@ pub fn run(alloc: std.mem.Allocator, host_specs: []const HostSpec, entry: Entry) | |||
| 2439 | "[nothing attached there yet - tile closed]"); | 2443 | "[nothing attached there yet - tile closed]"); |
| 2440 | wall_layout.relayout(w, shared.sel); | 2444 | wall_layout.relayout(w, shared.sel); |
| 2441 | }, | 2445 | }, |
| 2446 | .waiting => { | ||
| 2447 | asked = true; | ||
| 2448 | setNotice(&shared, "[waiting for its host - nothing attached to end yet]"); | ||
| 2449 | showRefusal(tiles[0..live], &shared, z); | ||
| 2450 | }, | ||
| 2442 | .none => {}, | 2451 | .none => {}, |
| 2443 | } | 2452 | } |
| 2444 | if (!asked) { | 2453 | if (!asked) { |