mirror of
https://github.com/PowerShell/PowerShell.git
synced 2024-11-24 02:04:07 +08:00
Introduce TTYConsole for UNIX
This commit is contained in:
parent
8e234322c4
commit
e79c62f9ec
@ -307,9 +307,9 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
int j = i + start;
|
||||
#if LINUX // TODO: use real inverse
|
||||
ConsoleColor tempColor = (int)buffer[j].ForegroundColor == -1
|
||||
ConsoleColor tempColor = buffer[j].ForegroundColor == UnknownColor
|
||||
? ConsoleColor.White : buffer[j].ForegroundColor;
|
||||
buffer[j].ForegroundColor = (int)buffer[j].BackgroundColor == -1
|
||||
buffer[j].ForegroundColor = buffer[j].BackgroundColor == UnknownColor
|
||||
? ConsoleColor.Black : buffer[j].BackgroundColor;
|
||||
buffer[j].BackgroundColor = tempColor;
|
||||
#else
|
||||
|
@ -317,7 +317,7 @@ namespace Microsoft.PowerShell.Internal
|
||||
public CHAR_INFO(char c, ConsoleColor foreground, ConsoleColor background)
|
||||
{
|
||||
UnicodeChar = c;
|
||||
Attributes = (ushort)(((int)background << 4) | (int)foreground);
|
||||
Attributes = (ushort)((((int)background << 4) & 0xf) | ((int)foreground & 0xf));
|
||||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
@ -330,7 +330,7 @@ namespace Microsoft.PowerShell.Internal
|
||||
[ExcludeFromCodeCoverage]
|
||||
public ConsoleColor BackgroundColor
|
||||
{
|
||||
get { return (ConsoleColor)((Attributes & 0xf0) >> 4); }
|
||||
get { return (ConsoleColor)((Attributes & 0x00f0) >> 4); }
|
||||
set { Attributes = (ushort)((Attributes & 0xff0f) | (((int)value & 0xf) << 4)); }
|
||||
}
|
||||
|
||||
@ -426,6 +426,7 @@ namespace Microsoft.PowerShell.Internal
|
||||
}
|
||||
}
|
||||
|
||||
#if !LINUX
|
||||
internal class ConhostConsole : IConsole
|
||||
{
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
|
||||
@ -482,18 +483,42 @@ namespace Microsoft.PowerShell.Internal
|
||||
return new SafeFileHandle(handle, true);
|
||||
});
|
||||
|
||||
public uint GetConsoleInputMode()
|
||||
public object GetConsoleInputMode()
|
||||
{
|
||||
uint mode;
|
||||
var handle = _inputHandle.Value.DangerousGetHandle();
|
||||
uint result;
|
||||
NativeMethods.GetConsoleMode(handle, out result);
|
||||
return result;
|
||||
NativeMethods.GetConsoleMode(handle, out mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void SetConsoleInputMode(uint mode)
|
||||
public void SetConsoleInputMode(object modeObj)
|
||||
{
|
||||
var handle = _inputHandle.Value.DangerousGetHandle();
|
||||
NativeMethods.SetConsoleMode(handle, mode);
|
||||
if (modeObj is uint)
|
||||
{
|
||||
// Clear a couple flags so we can actually receive certain keys:
|
||||
// ENABLE_PROCESSED_INPUT - enables Ctrl+C
|
||||
// ENABLE_LINE_INPUT - enables Ctrl+S
|
||||
// Also clear a couple flags so we don't mask the input that we ignore:
|
||||
// ENABLE_MOUSE_INPUT - mouse events
|
||||
// ENABLE_WINDOW_INPUT - window resize events
|
||||
var mode = (uint)modeObj &
|
||||
~(NativeMethods.ENABLE_PROCESSED_INPUT |
|
||||
NativeMethods.ENABLE_LINE_INPUT |
|
||||
NativeMethods.ENABLE_WINDOW_INPUT |
|
||||
NativeMethods.ENABLE_MOUSE_INPUT);
|
||||
|
||||
var handle = _inputHandle.Value.DangerousGetHandle();
|
||||
NativeMethods.SetConsoleMode(handle, mode);
|
||||
}
|
||||
}
|
||||
|
||||
public void RestoreConsoleInputMode(object modeObj)
|
||||
{
|
||||
if (modeObj is uint)
|
||||
{
|
||||
var handle = _inputHandle.Value.DangerousGetHandle();
|
||||
NativeMethods.SetConsoleMode(handle, (uint)modeObj);
|
||||
}
|
||||
}
|
||||
|
||||
public ConsoleKeyInfo ReadKey()
|
||||
@ -601,24 +626,7 @@ namespace Microsoft.PowerShell.Internal
|
||||
ScrollBuffer(scrollCount);
|
||||
top -= scrollCount;
|
||||
}
|
||||
#if LINUX
|
||||
ConsoleColor foregroundColor = Console.ForegroundColor;
|
||||
ConsoleColor backgroundColor = Console.BackgroundColor;
|
||||
|
||||
Console.SetCursorPosition(0, (top>=0) ? top : 0);
|
||||
|
||||
for (int i = 0; i < buffer.Length; ++i)
|
||||
{
|
||||
// TODO: use escape sequences for better perf
|
||||
Console.ForegroundColor = buffer[i].ForegroundColor;
|
||||
Console.BackgroundColor = buffer[i].BackgroundColor;
|
||||
|
||||
Console.Write((char)buffer[i].UnicodeChar);
|
||||
}
|
||||
|
||||
Console.BackgroundColor = backgroundColor;
|
||||
Console.ForegroundColor = foregroundColor;
|
||||
#else
|
||||
var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output);
|
||||
var bufferSize = new COORD
|
||||
{
|
||||
@ -643,18 +651,10 @@ namespace Microsoft.PowerShell.Internal
|
||||
{
|
||||
Console.CursorTop = bottom;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ScrollBuffer(int lines)
|
||||
{
|
||||
#if LINUX
|
||||
for (int i=0; i<lines; ++i)
|
||||
{
|
||||
Console.SetCursorPosition(Console.BufferWidth, Console.BufferHeight - 1);
|
||||
Console.WriteLine();
|
||||
}
|
||||
#else
|
||||
var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output);
|
||||
|
||||
var scrollRectangle = new SMALL_RECT
|
||||
@ -667,20 +667,11 @@ namespace Microsoft.PowerShell.Internal
|
||||
var destinationOrigin = new COORD {X = 0, Y = 0};
|
||||
var fillChar = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor);
|
||||
NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar);
|
||||
#endif
|
||||
}
|
||||
|
||||
public CHAR_INFO[] ReadBufferLines(int top, int count)
|
||||
{
|
||||
var result = new CHAR_INFO[BufferWidth * count];
|
||||
#if LINUX
|
||||
for (int i=0; i<BufferWidth*count; ++i)
|
||||
{
|
||||
result[i].UnicodeChar = ' ';
|
||||
result[i].ForegroundColor = Console.ForegroundColor;
|
||||
result[i].BackgroundColor = Console.BackgroundColor;
|
||||
}
|
||||
#else
|
||||
var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output);
|
||||
|
||||
var readBufferSize = new COORD {
|
||||
@ -696,7 +687,7 @@ namespace Microsoft.PowerShell.Internal
|
||||
};
|
||||
NativeMethods.ReadConsoleOutput(handle, result,
|
||||
readBufferSize, readBufferCoord, ref readRegion);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -891,14 +882,196 @@ namespace Microsoft.PowerShell.Internal
|
||||
NativeMethods.ReleaseDC(_hwnd, _hDC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX // TODO: this is not correct, PSReadline never clears the screen, it should only scroll
|
||||
#else
|
||||
|
||||
internal class TTYConsole : IConsole
|
||||
{
|
||||
public object GetConsoleInputMode()
|
||||
{
|
||||
return Console.TreatControlCAsInput;
|
||||
}
|
||||
|
||||
public void SetConsoleInputMode(object modeObj)
|
||||
{
|
||||
Console.TreatControlCAsInput = true;
|
||||
}
|
||||
|
||||
public void RestoreConsoleInputMode(object modeObj)
|
||||
{
|
||||
if (modeObj is bool)
|
||||
{
|
||||
Console.TreatControlCAsInput = (bool)modeObj;
|
||||
}
|
||||
}
|
||||
|
||||
public ConsoleKeyInfo ReadKey()
|
||||
{
|
||||
return Console.ReadKey(true);
|
||||
}
|
||||
|
||||
public bool KeyAvailable
|
||||
{
|
||||
get { return Console.KeyAvailable; }
|
||||
}
|
||||
|
||||
public int CursorLeft
|
||||
{
|
||||
get { return Console.CursorLeft; }
|
||||
set { Console.CursorLeft = value; }
|
||||
}
|
||||
|
||||
public int CursorTop
|
||||
{
|
||||
get { return Console.CursorTop; }
|
||||
set { Console.CursorTop = value; }
|
||||
}
|
||||
|
||||
public int CursorSize
|
||||
{
|
||||
get { return Console.CursorSize; }
|
||||
set { Console.CursorSize = value; }
|
||||
}
|
||||
|
||||
public int BufferWidth
|
||||
{
|
||||
get { return Console.BufferWidth; }
|
||||
set { Console.BufferWidth = value; }
|
||||
}
|
||||
|
||||
public int BufferHeight
|
||||
{
|
||||
get { return Console.BufferHeight; }
|
||||
set { Console.BufferHeight = value; }
|
||||
}
|
||||
|
||||
public int WindowWidth
|
||||
{
|
||||
get { return Console.WindowWidth; }
|
||||
set { Console.WindowWidth = value; }
|
||||
}
|
||||
|
||||
public int WindowHeight
|
||||
{
|
||||
get { return Console.WindowHeight; }
|
||||
set { Console.WindowHeight = value; }
|
||||
}
|
||||
|
||||
public int WindowTop
|
||||
{
|
||||
get { return Console.WindowTop; }
|
||||
set { Console.WindowTop = value; }
|
||||
}
|
||||
|
||||
public ConsoleColor BackgroundColor
|
||||
{
|
||||
get { return Console.BackgroundColor; }
|
||||
set { Console.BackgroundColor = value; }
|
||||
}
|
||||
|
||||
public ConsoleColor ForegroundColor
|
||||
{
|
||||
get { return Console.ForegroundColor; }
|
||||
set { Console.ForegroundColor = value; }
|
||||
}
|
||||
|
||||
public void SetWindowPosition(int left, int top)
|
||||
{
|
||||
Console.SetWindowPosition(left, top);
|
||||
}
|
||||
|
||||
public void SetCursorPosition(int left, int top)
|
||||
{
|
||||
Console.SetCursorPosition(left, top);
|
||||
}
|
||||
|
||||
public void Write(string value)
|
||||
{
|
||||
Console.Write(value);
|
||||
}
|
||||
|
||||
public void WriteLine(string value)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
|
||||
public void WriteBufferLines(CHAR_INFO[] buffer, ref int top)
|
||||
{
|
||||
WriteBufferLines(buffer, ref top, true);
|
||||
}
|
||||
|
||||
public void WriteBufferLines(CHAR_INFO[] buffer, ref int top, bool ensureBottomLineVisible)
|
||||
{
|
||||
int bufferWidth = Console.BufferWidth;
|
||||
int bufferLineCount = buffer.Length / bufferWidth;
|
||||
if ((top + bufferLineCount) > Console.BufferHeight)
|
||||
{
|
||||
var scrollCount = (top + bufferLineCount) - Console.BufferHeight;
|
||||
ScrollBuffer(scrollCount);
|
||||
top -= scrollCount;
|
||||
}
|
||||
|
||||
ConsoleColor foregroundColor = Console.ForegroundColor;
|
||||
ConsoleColor backgroundColor = Console.BackgroundColor;
|
||||
|
||||
Console.SetCursorPosition(0, (top>=0) ? top : 0);
|
||||
|
||||
for (int i = 0; i < buffer.Length; ++i)
|
||||
{
|
||||
// TODO: use escape sequences for better perf
|
||||
Console.ForegroundColor = buffer[i].ForegroundColor;
|
||||
Console.BackgroundColor = buffer[i].BackgroundColor;
|
||||
|
||||
Console.Write((char)buffer[i].UnicodeChar);
|
||||
}
|
||||
|
||||
Console.BackgroundColor = backgroundColor;
|
||||
Console.ForegroundColor = foregroundColor;
|
||||
}
|
||||
|
||||
public void ScrollBuffer(int lines)
|
||||
{
|
||||
for (int i=0; i<lines; ++i)
|
||||
{
|
||||
Console.SetCursorPosition(Console.BufferWidth, Console.BufferHeight - 1);
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public CHAR_INFO[] ReadBufferLines(int top, int count)
|
||||
{
|
||||
var result = new CHAR_INFO[BufferWidth * count];
|
||||
for (int i=0; i<BufferWidth*count; ++i)
|
||||
{
|
||||
result[i].UnicodeChar = ' ';
|
||||
result[i].ForegroundColor = Console.ForegroundColor;
|
||||
result[i].BackgroundColor = Console.BackgroundColor;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int LengthInBufferCells(char c)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
public void StartRender()
|
||||
{
|
||||
}
|
||||
|
||||
public void EndRender()
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: this is not correct, PSReadline never clears the screen, it should only scroll
|
||||
public void Clear()
|
||||
{
|
||||
Console.Clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CORECLR // TODO: remove if CORECLR adds this attribute back
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)]
|
||||
|
@ -28,8 +28,9 @@ namespace Microsoft.PowerShell
|
||||
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]
|
||||
public interface IConsole
|
||||
{
|
||||
uint GetConsoleInputMode();
|
||||
void SetConsoleInputMode(uint mode);
|
||||
object GetConsoleInputMode();
|
||||
void SetConsoleInputMode(object mode);
|
||||
void RestoreConsoleInputMode(object mode);
|
||||
ConsoleKeyInfo ReadKey();
|
||||
bool KeyAvailable { get; }
|
||||
int CursorLeft { get; set; }
|
||||
|
@ -43,11 +43,7 @@ namespace Microsoft.PowerShell
|
||||
private ManualResetEvent _closingWaitHandle;
|
||||
private WaitHandle[] _threadProcWaitHandles;
|
||||
private WaitHandle[] _requestKeyWaitHandles;
|
||||
#if LINUX // TODO: move to IConsole when there is a Linux IConsole implementation
|
||||
private bool _prePSReadlineControlCMode;
|
||||
#else
|
||||
private uint _prePSReadlineConsoleMode;
|
||||
#endif
|
||||
private object _savedConsoleInputMode;
|
||||
|
||||
private readonly StringBuilder _buffer;
|
||||
private readonly StringBuilder _statusBuffer;
|
||||
@ -266,32 +262,13 @@ namespace Microsoft.PowerShell
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#if LINUX // TODO: move to IConsole when there is a Linux IConsole implementation
|
||||
_singleton._prePSReadlineControlCMode = Console.TreatControlCAsInput;
|
||||
#else
|
||||
_singleton._prePSReadlineConsoleMode = console.GetConsoleInputMode();
|
||||
#endif
|
||||
_singleton._savedConsoleInputMode = _singleton._console.GetConsoleInputMode();
|
||||
bool firstTime = true;
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if LINUX // TODO: move to IConsole when there is a Linux IConsole implementation
|
||||
Console.TreatControlCAsInput = true;
|
||||
#else
|
||||
// Clear a couple flags so we can actually receive certain keys:
|
||||
// ENABLE_PROCESSED_INPUT - enables Ctrl+C
|
||||
// ENABLE_LINE_INPUT - enables Ctrl+S
|
||||
// Also clear a couple flags so we don't mask the input that we ignore:
|
||||
// ENABLE_MOUSE_INPUT - mouse events
|
||||
// ENABLE_WINDOW_INPUT - window resize events
|
||||
var mode = _singleton._prePSReadlineConsoleMode &
|
||||
~(NativeMethods.ENABLE_PROCESSED_INPUT |
|
||||
NativeMethods.ENABLE_LINE_INPUT |
|
||||
NativeMethods.ENABLE_WINDOW_INPUT |
|
||||
NativeMethods.ENABLE_MOUSE_INPUT);
|
||||
console.SetConsoleInputMode(mode);
|
||||
#endif
|
||||
_singleton._console.SetConsoleInputMode(_singleton._savedConsoleInputMode);
|
||||
|
||||
if (firstTime)
|
||||
{
|
||||
@ -362,11 +339,7 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if LINUX // TODO: move to IConsole when there is a Linux IConsole implementation
|
||||
Console.TreatControlCAsInput = _singleton._prePSReadlineControlCMode;
|
||||
#else
|
||||
console.SetConsoleInputMode(_singleton._prePSReadlineConsoleMode);
|
||||
#endif
|
||||
_singleton._console.RestoreConsoleInputMode(_singleton._savedConsoleInputMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -454,29 +427,16 @@ namespace Microsoft.PowerShell
|
||||
|
||||
T CalloutUsingDefaultConsoleMode<T>(Func<T> func)
|
||||
{
|
||||
#if LINUX // TODO: move to IConsole when there is a Linux IConsole implementation
|
||||
bool psReadlineControlCMode = Console.TreatControlCAsInput;
|
||||
var currentMode = _console.GetConsoleInputMode();
|
||||
try
|
||||
{
|
||||
Console.TreatControlCAsInput = _prePSReadlineControlCMode;
|
||||
_console.RestoreConsoleInputMode(_savedConsoleInputMode);
|
||||
return func();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.TreatControlCAsInput = psReadlineControlCMode;
|
||||
_console.RestoreConsoleInputMode(currentMode);
|
||||
}
|
||||
#else
|
||||
uint psReadlineConsoleMode = _console.GetConsoleInputMode();
|
||||
try
|
||||
{
|
||||
_console.SetConsoleInputMode(_prePSReadlineConsoleMode);
|
||||
return func();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_console.SetConsoleInputMode(psReadlineConsoleMode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CalloutUsingDefaultConsoleMode(Action action)
|
||||
@ -519,7 +479,11 @@ namespace Microsoft.PowerShell
|
||||
private PSConsoleReadLine()
|
||||
{
|
||||
_mockableMethods = this;
|
||||
#if LINUX
|
||||
_console = new TTYConsole();
|
||||
#else
|
||||
_console = new ConhostConsole();
|
||||
#endif
|
||||
|
||||
SetDefaultWindowsBindings();
|
||||
|
||||
@ -788,13 +752,11 @@ namespace Microsoft.PowerShell
|
||||
return;
|
||||
}
|
||||
|
||||
#region VI special case
|
||||
if (_singleton._options.EditMode == EditMode.Vi && key.Value.KeyChar == '0')
|
||||
{
|
||||
BeginningOfLine();
|
||||
return;
|
||||
}
|
||||
#endregion VI special case
|
||||
|
||||
bool sawDigit = false;
|
||||
_singleton._statusLinePrompt = "digit-argument: ";
|
||||
|
@ -13,6 +13,7 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
public partial class PSConsoleReadLine
|
||||
{
|
||||
private const ConsoleColor UnknownColor = (ConsoleColor) (-1);
|
||||
private CHAR_INFO[] _consoleBuffer;
|
||||
private int _initialX;
|
||||
private int _initialY;
|
||||
@ -464,8 +465,8 @@ namespace Microsoft.PowerShell
|
||||
// but looks best with the 2 default color schemes - starting PowerShell
|
||||
// from it's shortcut or from a cmd shortcut.
|
||||
#if LINUX // TODO: set Inverse attribute and let render choose what to do.
|
||||
ConsoleColor tempColor = ((int)foregroundColor == -1) ? ConsoleColor.White : foregroundColor;
|
||||
foregroundColor = ((int)backgroundColor == -1) ? ConsoleColor.Black : backgroundColor;
|
||||
ConsoleColor tempColor = (foregroundColor == UnknownColor) ? ConsoleColor.White : foregroundColor;
|
||||
foregroundColor = (backgroundColor == UnknownColor) ? ConsoleColor.Black : backgroundColor;
|
||||
backgroundColor = tempColor;
|
||||
#else
|
||||
foregroundColor = (ConsoleColor)((int)foregroundColor ^ 7);
|
||||
|
Loading…
Reference in New Issue
Block a user