mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Merge pull request #2336 from lzybkr/stdin_fixes
Fix some issues with `powershell -Command -`
This commit is contained in:
@@ -3467,6 +3467,9 @@ namespace Microsoft.PowerShell
|
||||
[DllImport(PinvokeDllNames.GetLargestConsoleWindowSizeDllName, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern COORD GetLargestConsoleWindowSize(NakedWin32Handle consoleOutput);
|
||||
|
||||
[DllImport(PinvokeDllNames.GetStdHandleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr GetStdHandle(int handleId);
|
||||
|
||||
[DllImport(PinvokeDllNames.ReadConsoleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern bool ReadConsole
|
||||
(
|
||||
|
||||
@@ -2868,6 +2868,25 @@ namespace Microsoft.PowerShell
|
||||
private System.Threading.Thread _breakHandlerThread;
|
||||
private bool _isDisposed;
|
||||
internal ConsoleHostUserInterface ui;
|
||||
|
||||
#if CORECLR
|
||||
internal Lazy<TextReader> ConsoleIn { get; } = new Lazy<TextReader>(() => Console.In);
|
||||
#else
|
||||
internal Lazy<TextReader> ConsoleIn { get; } = new Lazy<TextReader>(() =>
|
||||
{
|
||||
// This is a workaround for a full clr issue that causes a hang when calling PowerShell from ruby.
|
||||
// They use named pipes instead of anonymous pipes, and for some reason that triggers a hang
|
||||
// reading from Console.In.
|
||||
var inputHandle = ConsoleControl.NativeMethods.GetStdHandle(-10);
|
||||
var s = new FileStream(new ConsoleHandle(inputHandle, false), FileAccess.Read);
|
||||
|
||||
uint codePage = (uint) ConsoleControl.NativeMethods.GetConsoleCP();
|
||||
Encoding encoding = Encoding.GetEncoding((int) codePage);
|
||||
|
||||
return TextReader.Synchronized(new StreamReader(s, encoding, false));
|
||||
});
|
||||
#endif
|
||||
|
||||
private string _savedWindowTitle = "";
|
||||
private Version _ver = PSVersionInfo.PSVersion;
|
||||
private int _exitCodeFromRunspace;
|
||||
|
||||
@@ -1554,19 +1554,22 @@ namespace Microsoft.PowerShell
|
||||
private string ReadLineFromFile(string initialContent)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (initialContent != null)
|
||||
if (!string.IsNullOrEmpty(initialContent))
|
||||
{
|
||||
sb.Append(initialContent);
|
||||
sb.Append('\n');
|
||||
}
|
||||
|
||||
var consoleIn = _parent.ConsoleIn.Value;
|
||||
while (true)
|
||||
{
|
||||
var inC = Console.In.Read();
|
||||
var inC = consoleIn.Read();
|
||||
if (inC == -1)
|
||||
{
|
||||
// EOF - we return null which tells our caller to exit
|
||||
return null;
|
||||
// but only if we don't have any input, we could have
|
||||
// input and then stdin was closed, but never saw a newline.
|
||||
return sb.Length == 0 ? null : sb.ToString();
|
||||
}
|
||||
|
||||
var c = unchecked((char)inC);
|
||||
@@ -1575,10 +1578,10 @@ namespace Microsoft.PowerShell
|
||||
if (c == '\r')
|
||||
{
|
||||
// Treat as newline, but consume \n if there is one.
|
||||
if (Console.In.Peek() == '\n')
|
||||
if (consoleIn.Peek() == '\n')
|
||||
{
|
||||
if (!NoPrompt) Console.Out.Write('\n');
|
||||
Console.In.Read();
|
||||
consoleIn.Read();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1588,7 +1591,9 @@ namespace Microsoft.PowerShell
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\b')
|
||||
// If NoPrompt is true, we are in a sort of server mode where we shouldn't
|
||||
// do anything like edit the command line - every character is part of the input.
|
||||
if (c == '\b' && !NoPrompt)
|
||||
{
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
}
|
||||
|
||||
@@ -212,8 +212,7 @@ namespace Microsoft.PowerShell
|
||||
if ((options & ExecutionOptions.ReadInputObjects) > 0 && Console.IsInputRedirected)
|
||||
{
|
||||
// read input objects from stdin
|
||||
|
||||
WrappedDeserializer des = new WrappedDeserializer(_parent.InputFormat, "Input", Console.In);
|
||||
WrappedDeserializer des = new WrappedDeserializer(_parent.InputFormat, "Input", _parent.ConsoleIn.Value);
|
||||
while (!des.AtEnd)
|
||||
{
|
||||
object o = des.Deserialize();
|
||||
|
||||
@@ -227,6 +227,12 @@ Describe "ConsoleHost unit tests" -tags "Feature" {
|
||||
$process.StandardInput.Write("1+2`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS> 1+2"
|
||||
$process.StandardOutput.ReadLine() | Should Be "3"
|
||||
|
||||
# Backspace should work as expected
|
||||
$process.StandardInput.Write("1+2`b3`n")
|
||||
# A real console should render 2`b3 as just 3, but we're just capturing exactly what is written
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS> 1+2`b3"
|
||||
$process.StandardOutput.ReadLine() | Should Be "4"
|
||||
$process.StandardInput.Close()
|
||||
$process.StandardOutput.ReadToEnd() | Should Be "PS> "
|
||||
EnsureChildHasExited $process
|
||||
@@ -279,7 +285,16 @@ foo
|
||||
"@)
|
||||
$process.StandardOutput.ReadLine() | Should Be "in foo"
|
||||
|
||||
# Backspace sent through stdin should be in the final string
|
||||
$process.StandardInput.Write("`"a`bc`".Length`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "3"
|
||||
|
||||
# Last command with no newline - should be accepted and
|
||||
# produce output after closing stdin.
|
||||
$process.StandardInput.Write('22 + 22')
|
||||
$process.StandardInput.Close()
|
||||
$process.StandardOutput.ReadLine() | Should Be "44"
|
||||
|
||||
EnsureChildHasExited $process
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user