8000 Enable PSReadline to work on NanoServer by SteveL-MSFT · Pull Request #3815 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Enable PSReadline to work on NanoServer #3815

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 clickin 8000 g “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

Merged
merged 4 commits into from
May 31, 2017

Conversation

SteveL-MSFT
Copy link
Member
@SteveL-MSFT SteveL-MSFT commented May 18, 2017

PSReadline uses two native Win32 apis to determine font and unicode information which is not available on NanoServer. Fix is to assume the input is one byte in character in size and not using a truetype font. This should work for most use cases.

Manually tested this change with our published dockerfile for NanoServer.

Fix #3463

…ont and unicode which causes PSReadline to not be usable

on NanoServer docker images.  Fix is to assume single byte characters if these APIs are not available.
int charCount = 1;
try
{
charCount = NativeMethods.ToUnicode(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should find a better way - this will cause an exception on every character typed, not good for performance and extremely annoying when debugging.

There is some one-time initialization code - so one less ugly option is to add a P/Invoke call there just to detect if the api is present or not, setting a flag that is checked here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will make the change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into putting the check in Readline.Initialize() but since it was a different class I would have to expose two additional members. Seemed simpler to keep the state within the classes needing those apis.

bool result = true;
try
{
result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should do the same here - detect once so we don't have frequent exceptions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change

@SteveL-MSFT
Copy link
Member Author

@lzybkr fixed

int charCount = NativeMethods.ToUnicode(
virtualKey, scanCode, state, chars, chars.Length, NativeMethods.MENU_IS_INACTIVE);
int charCount = 1;
if (_toUnicodeApiAvailable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a closer look, I don't think this is the right fix for this case - custom key bindings need a valid results, you'll just return \0.

I think we'll need the Unix variant of this code as a fallback, or potentially use it unconditionally, though that might break some more obscure key bindings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a comment in the code that GetCharFromConsoleKey() is needed to support chords like Ctrl+[. Seems like the best approach here is to defer to the Unix code if this API isn't available. I'll make that change.

@SteveL-MSFT
Copy link
Member Author

Manually verified, you can use something like this:

docker run -it --entrypoint cmd -v C:\users\slee\repos\PowerShell\src\powershell-win-core\bin\Debug\netcoreapp2.0\win10-x64\publish:c:\powershell microsoft/powershell:nanoserver

After the container starts in cmd, you can start powershell using c:\powershell\powershell

@SteveL-MSFT SteveL-MSFT force-pushed the psreadline-docker branch 5 times, most recently from e983193 to 3f005a5 Compare May 24, 2017 01:58
@SteveL-MSFT
Copy link
Member Author

@lzybkr good to go?

char c = ConsoleKeyChordConverter.GetCharFromConsoleKey(key.Key,
(mods & ConsoleModifiers.Shift) != 0 ? ConsoleModifiers.Shift : 0);
#if !UNIX
if (_toUnicodeApiAvailable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this api is not available, based on the comment, I would expect to see some garbage in the output of Get-PSReadlineKeyHandler -Bound, e.g. on this line:

Ctrl+]                GotoBrace               Go to matching brace

(or if you are using Emacs mode):

Ctrl+]           CharacterSearch         Read a character and move the cursor to the next occurence of that character
Ctrl+Alt+]       CharacterSearchBackward Read a character and move the cursor to the previous occurence of that char...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can check next week when back in office where I have Docker and a Nano container, but not sure what you are proposing here when the api is not available.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm proposing not degrading the default user experience if possible - which might require a few special cases. I would guess a more general fix isn't possible because this api is that general fix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this is a decision the Nano team should make. If they want the full experience, they need those apis on Nano. I'll certainly let them know of the limitation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a Nano container that line says:

Ctrl+Oem6             GotoBrace               Go to matching brace

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, not very helpful :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want, I can add specialized code so that if those apis aren't available, we don't have those bindings by default. Seems like over optimizing for what is today an edge case. Alternatively, I could have PSReadline fail to load if those apis aren't available even though most of the PSReadline capability seems to run fine on Nano. Seems like the best option is to document this and have Nano team make the call to add that api.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few special cases is not over optimizing and is a practical assuming those apis aren't really generally useful.
The default output of Get-PSReadlineKeyBindings should not contain Oem.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created #3890 to track this issue, so we can at least unblock Nano for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0