Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upUse public InternalHost from origin runspace #874
Conversation
SeeminglyScience
requested review from
TylerLeonhardt,
rkeithhill and
rjmholt
Mar 5, 2019
SeeminglyScience
added some commits
Mar 7, 2019
SeeminglyScience
changed the title
WIP: Use public InternalHost from origin runspace
Use public InternalHost from origin runspace
Mar 7, 2019
TylerLeonhardt
added
the
Triage
label
Mar 8, 2019
TylerLeonhardt
reviewed
Mar 10, 2019
| @@ -184,11 +145,87 @@ public override Size MaxWindowSize | |||
| /// <returns>A KeyInfo struct with details about the current keypress.</returns> | |||
| public override KeyInfo ReadKey(ReadKeyOptions options) | |||
This comment has been minimized.
This comment has been minimized.
TylerLeonhardt
Mar 10, 2019
Member
@SteveL-MSFT @daxian-dbw would you mind taking a look at this ReadKey implementation if you have a sec? This will be the implementation for $Host.UI.RawUI.ReadKey() in the Integrated Console.
I think it looks ok.
TylerLeonhardt
approved these changes
Mar 10, 2019
|
LGTM I'd like to do 2 things before this goes in:
|
This comment has been minimized.
This comment has been minimized.
potatoqualitee
commented
Mar 11, 2019
This comment has been minimized.
This comment has been minimized.
|
@potatoqualitee I think they might go by a different name on GitHub? Looks like no one was tagged. |
This comment has been minimized.
This comment has been minimized.
potatoqualitee
commented
Mar 11, 2019
|
unfortunately, i dont know his github address :/ hopefully he'll notice the twitter ping |
This comment has been minimized.
This comment has been minimized.
wsmelton
commented
Mar 11, 2019
This comment has been minimized.
This comment has been minimized.
potatoqualitee
commented
Mar 11, 2019
|
yay that is him |
This comment has been minimized.
This comment has been minimized.
|
@potatoqualitee Doesn't look like that uses |
This comment has been minimized.
This comment has been minimized.
potatoqualitee
commented
Mar 11, 2019
|
daw sorry, i didnt check the code, i was just a lil familiar with his project. my own write-progresses are pretty straightforward |
This comment has been minimized.
This comment has been minimized.
daxian-dbw
reviewed
Mar 11, 2019
|
No much experience in this area, so my questions are mainly for my own education ;) |
| info.Character, | ||
| info.ControlKeyState, | ||
| keyDown: false); | ||
| } |
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 11, 2019
Member
KeyUp is requested, but why are you returning a KeyDown, especially that this KeyDown has already been returned previously?
This comment has been minimized.
This comment has been minimized.
| var result = new KeyInfo((int)key.Key, key.KeyChar, states, isDown); | ||
| if (isDown) | ||
| { | ||
| this.lastKeyDown = result; |
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 11, 2019
Member
The returned value from this local function is returned immediately at all call sites of this local function, which means the cached KeyDown returned below in if (includeUp && this.lastKeyDown != null) has already been returned previously.
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 11, 2019
•
Author
Collaborator
The returned value from this local function is returned immediately at all call sites of this local function, which means the cached KeyDown returned below in if (includeUp && this.lastKeyDown != null) has already been returned previously.
Yeah, that's an attempt match the behavior of ConsoleHost without dipping into native API's.
Here's an example to demonstrate what I'm trying emulate.
while ($true) {
$Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
$Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyUp')
}With that running outside of PSES, every one key press will return two KeyInfo objects. One for down, and one for up. Example output:
VirtualKeyCode Character ControlKeyState KeyDown
-------------- --------- --------------- -------
70 f NumLockOn True
70 f NumLockOn False
Now obviously ConsoleHost does this a lot better using native API's directly, but this route saves a lot of complexity. The only difference in behavior is when holding down a key with both IncludeKeyUp and IncludeKeyDown set. In that scenario ConsoleHost will continuously return key down KeyInfo objects until they key is released where we will continuously return both key down and key up objects. That difference is negated a little bit though. Even ConsoleHost act the same under winpty as it doesn't translate input one to one.
This comment has been minimized.
This comment has been minimized.
TylerLeonhardt
Mar 11, 2019
Member
Yeah on non-consolehost I think it typically only supports KeyDown events and not KeyUp at all.
If I tried that while loop on macOS, I only get KeyDown events.
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 11, 2019
Author
Collaborator
Just to clarify because the terms are confusing, when I sayConsoleHost I'm referring to Microsoft.PowerShell.ConsoleHost (the PSHost started by powershell.exe/pwsh) not conhost.exe
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
I think I'm good with this. Tomorrow I'll test on non-Windows while we wait for more feedback. |
This comment has been minimized.
This comment has been minimized.
|
https://twitter.com/mrhvid/status/1105230923887464450 more from Twitter |
daxian-dbw
reviewed
Mar 12, 2019
| // Caller doesn't want CtrlC so throw a PipelineStoppedException to emulate | ||
| // a real stop. This will not show an exception to a script based caller and it | ||
| // will avoid having to return something like default(KeyInfo). | ||
| throw new PipelineStoppedException(); |
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 12, 2019
Member
Caller doesn't want CtrlC so throw a PipelineStoppedException to emulate a real stop.
@SeeminglyScience I'm a little confused about the comment on this throw statement. Can you please explain a bit?
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 12, 2019
•
Author
Collaborator
Sure, so at that point we've received the input Ctrl + C. If the caller did not include AllowCtrlC in the options, then we should treat it like a break event instead and terminate the pipeline.
Emulate is probably not really the right word there, I chose it because we aren't going through PowerShell.Stop or Pipeline.Stop like a normal break event would.
Another route would be to not set Console.TreatControlCAsInput, and allow our break handler to call PowerShell.Stop like normal. This actually would be more similar to what ConsoleHost does as it will actually return default(KeyInfo), but triggers a pipeline stop.
The issue I have with this is that if RawUI.ReadKey is in an assignment statement, the pipeline stop won't actually happen until the next sequence point. PowerShell doesn't check if the current command is stopping between the RHS being evaluated and it's result being set to the LHS. So the LHS will actually be set to default(KeyInfo) instead of remaining unchanged. That doesn't happen if we throw instead.
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 12, 2019
Member
Another route would be to not set Console.TreatControlCAsInput
Thanks! My confusion was mainly around this case. It makes sense now.
So the LHS will actually be set to default(KeyInfo) instead of remaining unchanged.
Why does this matter if the pipeline stop will kick in at the next sequence point? Even if it's set to default(KeyInfo), the script execution gets killed and that assignment shouldn't have any real effect anymore, right?
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 12, 2019
•
Author
Collaborator
the script execution gets killed and that assignment shouldn't have any real effect anymore, right?
There's a few scenarios where it can linger:
- LHS is a global scoped variable (or script scoped variable in a module)
- LHS is a property or index expression
- Current command is a prompt evaluation (or is otherwise running within the top level scope of it's
SessionState) - If the assignment is in a
trywith afinallyblock (though it will only linger within thefinally)
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 12, 2019
Member
Can you please provide a repro of the problems? For example, LHS is a global scoped variable and it gets assigned with default(KeyInfo)
I tried with this in pwsh console
function Test{
$global:abc = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
}
Test
<ctrl+c>
It seems ReadKey will get either the LeftCtrlPressed or c, but not default(KeyInfo).
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 12, 2019
•
Author
Collaborator
Here's the easiest way:
$key = $null
# Drain "Enter" key up from accepting prompt. Maybe comment
# this line for non-Windows.
$null = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyUp')
$key = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyUp')Then press Ctrl + C and $key will hold:
VirtualKeyCode Character ControlKeyState KeyDown
-------------- --------- --------------- -------
0 0 False
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 12, 2019
Member
OK, I can repro it now after removing PSReadline.
Interesting that if I change IncludeKeyUp to IncludeKeyDown, it doesn't repro anymore
$null = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
$key = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
VirtualKeyCode Character ControlKeyState KeyDown
-------------- --------- --------------- -------
17 LeftCtrlPressed, NumLockOn True
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 12, 2019
•
Author
Collaborator
OK, I can repro it now after removing PSReadline.
Huh that's surprising... mine was with PSRL as well. Though I'm on 2.0 beta 3 (or more likely one of the appveyor builds...)
Interesting that if I change IncludeKeyUp to IncludeKeyDown, it doesn't repro anymore
Wellll sorta. IncludeKeyDown makes it a lot harder to reproduce because it can trigger on a single press of Ctrl. So by the time you type C, you're actually already back to a prompt. But if you do something like this, it'll still show up
$key = $null
while ($true) {
$key = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
}That will continously ReadKey until it registers Ctrl + C and a pipeline stop is triggered.
BTW, my comment is not blocking on this PR. I'm just curious :)
No worries, I could talk about it forever
This comment has been minimized.
This comment has been minimized.
daxian-dbw
Mar 13, 2019
Member
Huh that's surprising... mine was with PSRL as well. Though I'm on 2.0 beta 3 (or more likely one of the appveyor builds...)
Ha, I'm using 6.2.0-rc.1.
IncludeKeyDown makes it a lot harder to reproduce because it can trigger on a single press of Ctrl. So by the time you type C, you're actually already back to a prompt.
That makes perfect sense!
TylerLeonhardt
reviewed
Mar 13, 2019
| @@ -32,6 +32,7 @@ public abstract class EditorServicesPSHostUserInterface : | |||
| { | |||
| #region Private Fields | |||
|
|
|||
| private readonly HashSet<ProgressKey> currentProgressMessages = new HashSet<ProgressKey>(); | |||
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
SeeminglyScience
Mar 13, 2019
Author
Collaborator
Changed to using ConcurrentDictionary<,>, but haven't tested it yet so hold off on merge pls
rjmholt
approved these changes
Mar 13, 2019
TylerLeonhardt
approved these changes
Mar 13, 2019
|
LGTM just one nit |
| } | ||
| else | ||
| { | ||
| this.currentProgressMessages.TryAdd(new ProgressKey(sourceId, record), null); |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
potatoqualitee
commented
Mar 19, 2019
|
|

SeeminglyScience commentedMar 5, 2019
•
edited
ConsoleHostfrompowershell.exe/pwshstill exists within the runspace created at process start. This change grabs the public reference to that host while initializing EditorServicesHost. We can then leverage that host so we can have a much closer to "default" experience.Resolves #865, #384, PowerShell/vscode-powershell#140, PowerShell/vscode-powershell#1403
This adds support for the following host members:
$Host.UI
Write-Progress)$Host.UI.RawUI
TODO
Maybe avoid TerminalPSHost* breaking changes (constructors)I can't really think of any scenarios where folks would be creating their ownTerminalPSHost*instancesConsider thread safety for progress record andNot sure it's necessary, open to suggestions though.ReadKeybuffers