From 63ffd1632da40ee52cddedc75c83d70fb18c5ccf Mon Sep 17 00:00:00 2001 From: "jason@truewheels.net" Date: Tue, 14 Oct 2014 19:29:35 -0700 Subject: [PATCH] Raise PowerShell.OnIdle if needed If there are any registered handlers for the engine event PowerShell.OnIdle, raise the event that PowerShell would have raised so the event handler can do it's work. Fixes #169 --- PSReadLine/Changes.txt | 1 + PSReadLine/ReadLine.cs | 56 ++++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/PSReadLine/Changes.txt b/PSReadLine/Changes.txt index d927e9b..8059c7f 100644 --- a/PSReadLine/Changes.txt +++ b/PSReadLine/Changes.txt @@ -11,6 +11,7 @@ New features: Bug fixes: * Occasional exception with AcceptAndGetNext (Ctrl+O) followed by something other than Enter +* Event handlers that register for the engine event PowerShell.OnIdle should work now. New functions: * ValidateAndAcceptLine diff --git a/PSReadLine/ReadLine.cs b/PSReadLine/ReadLine.cs index 3e46491..041f3c1 100644 --- a/PSReadLine/ReadLine.cs +++ b/PSReadLine/ReadLine.cs @@ -133,27 +133,51 @@ namespace PSConsoleUtilities // If we timed out, check for event subscribers (which is just // a hint that there might be an event waiting to be processed.) - // If there are any event subscribers that have an action (which might - // write to the console) and have a source object (i.e. aren't engine - // events), run a tiny useless bit of PowerShell so that the events - // can be processed. - var eventSubscribers = Runspace.DefaultRunspace.Events.Subscribers; - if (eventSubscribers.Any(sub => sub.Action != null && sub.SourceObject != null)) + var eventSubscribers = _singleton._engineIntrinsics.Events.Subscribers; + if (eventSubscribers.Count > 0) { - if (ps == null) + bool runPipelineForEventProcessing = false; + foreach (var sub in eventSubscribers) { - ps = PowerShell.Create(RunspaceMode.CurrentRunspace); - ps.AddScript("0"); + if (sub.SourceIdentifier.Equals("PowerShell.OnIdle", StringComparison.OrdinalIgnoreCase)) + { + // There is an OnIdle event. We're idle because we timed out. Normally + // PowerShell generates this event, but PowerShell assumes the engine is not + // idle because it called PSConsoleHostReadline which isn't returning. + // So we generate the event intstead. + _singleton._engineIntrinsics.Events.GenerateEvent("PowerShell.OnIdle", null, null, null); + runPipelineForEventProcessing = true; + break; + } + + // If there are any event subscribers that have an action (which might + // write to the console) and have a source object (i.e. aren't engine + // events), run a tiny useless bit of PowerShell so that the events + // can be processed. + if (sub.Action != null && sub.SourceObject != null) + { + runPipelineForEventProcessing = true; + break; + } } - // To detect output during possible event processing, see if the cursor moved - // and rerender if so. - var y = Console.CursorTop; - ps.Invoke(); - if (y != Console.CursorTop) + if (runPipelineForEventProcessing) { - _singleton._initialY = Console.CursorTop; - _singleton.Render(); + if (ps == null) + { + ps = PowerShell.Create(RunspaceMode.CurrentRunspace); + ps.AddScript("0"); + } + + // To detect output during possible event processing, see if the cursor moved + // and rerender if so. + var y = Console.CursorTop; + ps.Invoke(); + if (y != Console.CursorTop) + { + _singleton._initialY = Console.CursorTop; + _singleton.Render(); + } } } }