-
Notifications
You must be signed in to change notification settings - Fork 315
Add private contract delegate for PSES to handle idle on readline #1679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
28925f0
b34cb1c
4a1138a
7ea0e5c
b51398b
c6f29e7
3d556aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,10 @@ public partial class PSConsoleReadLine : IPSConsoleReadLineMockableMethods | |
|
||
private static readonly CancellationToken _defaultCancellationToken = new CancellationTokenSource().Token; | ||
|
||
// This exists for PowerShell Editor Services (the backend of the PowerShell VSCode extension) | ||
// so that it can call PSReadLine from a delegate and not hit nested pipeline issues | ||
private static Action<CancellationToken> _handleIdleOverride; | ||
|
||
private bool _delayedOneTimeInitCompleted; | ||
|
||
private IPSConsoleReadLineMockableMethods _mockableMethods; | ||
|
@@ -196,12 +200,17 @@ internal static PSKeyInfo ReadKey() | |
// - a key is pressed | ||
// - the console is exiting | ||
// - 300ms - to process events if we're idle | ||
// - processing of events is requested externally | ||
// - ReadLine cancellation is requested externally | ||
handleId = WaitHandle.WaitAny(_singleton._requestKeyWaitHandles, 300); | ||
if (handleId != WaitHandle.WaitTimeout && handleId != EventProcessingRequested) | ||
break; | ||
|
||
if (_handleIdleOverride is not null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By removing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we just cancel in that scenario. It's not perfect because of how PSRL handles cancellation (i.e. it returns a value rather than throwing an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chatted with @rjmholt offline, and we decided to remove the |
||
{ | ||
_handleIdleOverride(_singleton._cancelReadCancellationToken); | ||
daxian-dbw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
continue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Won't this continue hard stop event processing/cancellation handling? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the current wait handle will handle cancellation -- that happens above the delegate call. We also own the cancellation token, so we have a lot of control there. Event processing is what we need to prevent, because if we invoke PSRL directly as a delegate with no pipeline running above it, event handling will fail. PSES owns the pipeline and pretty much everything else at this point, so I think it's up to us to handle events in our own way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Even if you set Or is it failing some other way?
Yeah that's fine if it comes to that, just a shame to implement the same logic in two places I suppose. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, well in fact looking into this, it may be that I'm not quite invoking the delegate the right way (i.e. not on the pipeline thread). I'll look into it and get back to you, because you may well be right! (Will keep this in draft until kinks like this are resolved) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just looked into this, and yeah the delegate is marshalled back to the pipeline thread and called there (and we have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the event handling doesn't work, make sure I worry that if PSRL's event handling doesn't work, I'm not 100% sure how we're going to handle that better in PSES you know? If we lose the ability to process events it might be better to ditch the delegate. |
||
} | ||
|
||
// If we timed out, check for event subscribers (which is just | ||
// a hint that there might be an event waiting to be processed.) | ||
var eventSubscribers = _singleton._engineIntrinsics?.Events.Subscribers; | ||
|
@@ -666,10 +675,6 @@ private PSConsoleReadLine() | |
_savedCurrentLine = new HistoryItem(); | ||
_queuedKeys = new Queue<PSKeyInfo>(); | ||
|
||
// Initialize this event handler early because it could be used by PowerShell | ||
// Editor Services before 'DelayedOneTimeInitialize' runs. | ||
_forceEventWaitHandle = new AutoResetEvent(false); | ||
|
||
string hostName = null; | ||
// This works mostly by luck - we're not doing anything to guarantee the constructor for our | ||
// singleton is called on a thread with a runspace, but it is happening by coincidence. | ||
|
@@ -860,7 +865,7 @@ private void DelayedOneTimeInitialize() | |
_singleton._readKeyWaitHandle = new AutoResetEvent(false); | ||
_singleton._keyReadWaitHandle = new AutoResetEvent(false); | ||
_singleton._closingWaitHandle = new ManualResetEvent(false); | ||
_singleton._requestKeyWaitHandles = new WaitHandle[] {_singleton._keyReadWaitHandle, _singleton._closingWaitHandle, _defaultCancellationToken.WaitHandle, _singleton._forceEventWaitHandle}; | ||
_singleton._requestKeyWaitHandles = new WaitHandle[] {_singleton._keyReadWaitHandle, _singleton._closingWaitHandle, _defaultCancellationToken.WaitHandle}; | ||
_singleton._threadProcWaitHandles = new WaitHandle[] {_singleton._readKeyWaitHandle, _singleton._closingWaitHandle}; | ||
|
||
// This is for a "being hosted in an alternate appdomain scenario" (the | ||
|
@@ -880,17 +885,6 @@ private void DelayedOneTimeInitialize() | |
_singleton._readKeyThread.Start(); | ||
} | ||
|
||
/// <summary> | ||
/// Used by PowerShellEditorServices to force immediate | ||
/// event handling during the <see cref="PSConsoleReadLine.ReadKey" /> | ||
/// method. This is not a public API, but it is part of a private contract | ||
/// with that project. | ||
/// </summary> | ||
private static void ForcePSEventHandling() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Woo! 🥳 |
||
{ | ||
_singleton._forceEventWaitHandle.Set(); | ||
} | ||
|
||
private static void Chord(ConsoleKeyInfo? key = null, object arg = null) | ||
{ | ||
if (!key.HasValue) | ||
|
Uh oh!
There was an error while loading. Please reload this page.