From 22baef55a544e2ba06751778537e6fb769be5bf3 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Sat, 22 Aug 2026 14:57:24 +1000 Subject: [PATCH] Leave the window command for a surface that has a window The stashed Focus or Close was taken by whichever listing arrived first, including a plain List. That one is the documented IDE plugin API - InlineQueueClient.TryListKeys - and has no window to raise, so taking the command threw it away: the plugin could do nothing with what it was handed, and the attached viewer polling beside it never raised for the new snapshot. Only a listing that carries patches takes it, which is the one a viewer asks for. A plain listing now reads through without clearing the stash. --- .../OwnedInlineHostTest.cs | 24 +++++++++++++++++++ src/DiffEngineTray/OwnedInlineHost.cs | 24 +++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/DiffEngineTray.Tests/OwnedInlineHostTest.cs b/src/DiffEngineTray.Tests/OwnedInlineHostTest.cs index 61529c66..8b7478c5 100644 --- a/src/DiffEngineTray.Tests/OwnedInlineHostTest.cs +++ b/src/DiffEngineTray.Tests/OwnedInlineHostTest.cs @@ -214,6 +214,30 @@ public async Task FocusRidesBackOnTheNextListing() await Assert.That(second.Window).IsNull(); } + /// + /// A plain List does not take the stashed window command. It is the documented IDE plugin API + /// - InlineQueueClient.TryListKeys - and has no window to raise, so taking the command threw + /// it away: whoever asked could not act on it, and the attached viewer polling beside it never + /// raised for the new snapshot. + /// + [Test] + public async Task APlainListingLeavesTheWindowCommandForAViewer() + { + using var owner = new Owner(); + owner.Queue(); + var snapshot = owner.Host.List().Single(); + + owner.Host.Focus(snapshot); + + var plain = owner.Send(new(ViewerVerb.List)); + await Assert.That(plain.Window).IsNull(); + + // Still there for the surface that has a window + var full = owner.Send(new(ViewerVerb.ListFull)); + await Assert.That(full.Window).IsEqualTo(WindowCommand.Focus); + await Assert.That(full.WindowKey).IsEqualTo(snapshot.Key); + } + [Test] public async Task ClosingTheViewerLeavesTheQueue() { diff --git a/src/DiffEngineTray/OwnedInlineHost.cs b/src/DiffEngineTray/OwnedInlineHost.cs index 4b394629..14b98b60 100644 --- a/src/DiffEngineTray/OwnedInlineHost.cs +++ b/src/DiffEngineTray/OwnedInlineHost.cs @@ -217,11 +217,25 @@ ViewerResponse IQueueOwner.Listing(bool withPatches) // Taken rather than read, so a focus happens once, on whichever viewer refreshes // first, rather than five times a second forever. - var command = window; - var key = windowKey; - window = null; - windowKey = null; - return ViewerResponse.Listing(items, command, key, moves, deletes); + // + // Only for a listing that carries patches, which is the one a viewer asks for. A plain + // List is the documented IDE plugin API - InlineQueueClient.TryListKeys - and has no + // window to raise, so handing it the stashed command threw the command away: the + // attached viewer polling beside it never raised for the new snapshot, and the plugin + // did nothing with what it was given. + ViewerResponse response; + if (withPatches) + { + response = ViewerResponse.Listing(items, window, windowKey, moves, deletes); + window = null; + windowKey = null; + } + else + { + response = ViewerResponse.Listing(items, null, null, moves, deletes); + } + + return response; } }