mirror of
https://github.com/PowerShell/PSReadLine
synced 2026-06-08 12:12:13 +00:00
124 lines
6.0 KiB
C#
124 lines
6.0 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Management.Automation;
|
|
using System.Management.Automation.Runspaces;
|
|
using System.Runtime.InteropServices;
|
|
using Microsoft.PowerShell;
|
|
|
|
namespace MockPSConsole
|
|
{
|
|
public enum StandardHandleId : uint
|
|
{
|
|
Error = unchecked((uint)-12),
|
|
Output = unchecked((uint)-11),
|
|
Input = unchecked((uint)-10),
|
|
}
|
|
|
|
class Program
|
|
{
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
public static extern bool GetConsoleMode(IntPtr hConsoleOutput, out uint dwMode);
|
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
public static extern bool SetConsoleMode(IntPtr hConsoleOutput, uint dwMode);
|
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
public static extern IntPtr GetStdHandle(uint handleId);
|
|
|
|
static void CauseCrash(ConsoleKeyInfo? key = null, object arg = null)
|
|
{
|
|
throw new Exception("intentional crash for test purposes");
|
|
}
|
|
|
|
public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x04;
|
|
public const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200;
|
|
|
|
[STAThread]
|
|
static void Main()
|
|
{
|
|
var handle = GetStdHandle((uint)StandardHandleId.Output);
|
|
GetConsoleMode(handle, out var mode);
|
|
var vtEnabled = SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
|
|
|
var iss = InitialSessionState.CreateDefault2();
|
|
var rs = RunspaceFactory.CreateRunspace(iss);
|
|
rs.Open();
|
|
Runspace.DefaultRunspace = rs;
|
|
|
|
PSConsoleReadLine.SetOptions(new SetPSReadLineOption
|
|
{
|
|
EditMode = EditMode.Emacs,
|
|
HistoryNoDuplicates = false,
|
|
});
|
|
|
|
if (vtEnabled)
|
|
{
|
|
var options = PSConsoleReadLine.GetOptions();
|
|
options.CommandColor = "#8181f7";
|
|
options.StringColor = "\x1b[38;5;100m";
|
|
}
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+LeftArrow"}, PSConsoleReadLine.ShellBackwardWord, "ShellBackwardWord", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+RightArrow"}, PSConsoleReadLine.ShellNextWord, "ShellNextWord", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"F4"}, PSConsoleReadLine.HistorySearchBackward, "HistorySearchBackward", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"F5"}, PSConsoleReadLine.HistorySearchForward, "HistorySearchForward", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+d,Ctrl+c"}, PSConsoleReadLine.CaptureScreen, "CaptureScreen", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+d,Ctrl+p"}, PSConsoleReadLine.InvokePrompt, "InvokePrompt", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+d,Ctrl+x"}, CauseCrash, "CauseCrash", "Throw exception to test error handling");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"F6"}, PSConsoleReadLine.PreviousLine, "PreviousLine", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"F7"}, PSConsoleReadLine.NextLine, "NextLine", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"F2"}, PSConsoleReadLine.ValidateAndAcceptLine, "ValidateAndAcceptLine", "");
|
|
PSConsoleReadLine.SetKeyHandler(new[] {"Enter"}, PSConsoleReadLine.AcceptLine, "AcceptLine", "");
|
|
|
|
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
|
|
{
|
|
var executionContext = ps.AddScript("$ExecutionContext").Invoke<EngineIntrinsics>().First();
|
|
|
|
// Detect if the read loop will enter VT input mode.
|
|
var vtInputEnvVar = Environment.GetEnvironmentVariable("PSREADLINE_VTINPUT");
|
|
var stdin = GetStdHandle((uint)StandardHandleId.Input);
|
|
GetConsoleMode(stdin, out var inputMode);
|
|
if (vtInputEnvVar == "1" || (inputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) != 0)
|
|
{
|
|
Console.WriteLine("\x1b[33mDefault input mode = virtual terminal\x1b[m");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("\x1b[33mDefault input mode = Windows\x1b[m");
|
|
}
|
|
|
|
// This is a workaround to ensure the command analysis cache has been created before
|
|
// we enter into ReadLine. It's a little slow and infrequently needed, so just
|
|
// uncomment if you hit a hang, run it once, then comment it out again.
|
|
//ps.Commands.Clear();
|
|
//ps.AddCommand("Get-Command").Invoke();
|
|
|
|
executionContext.InvokeProvider.Item.Set("function:prompt", ScriptBlock.Create("'TestHostPS> '"));
|
|
|
|
while (true)
|
|
{
|
|
ps.Commands.Clear();
|
|
Console.Write(string.Join("", ps.AddCommand("prompt").Invoke<string>()));
|
|
|
|
var line = PSConsoleReadLine.ReadLine(rs, executionContext, lastRunStatus: null);
|
|
Console.WriteLine(line);
|
|
line = line.Trim();
|
|
if (line.Equals("exit"))
|
|
Environment.Exit(0);
|
|
if (line.Equals("cmd"))
|
|
PSConsoleReadLine.SetOptions(new SetPSReadLineOption {EditMode = EditMode.Windows});
|
|
if (line.Equals("emacs"))
|
|
PSConsoleReadLine.SetOptions(new SetPSReadLineOption {EditMode = EditMode.Emacs});
|
|
if (line.Equals("vi"))
|
|
PSConsoleReadLine.SetOptions(new SetPSReadLineOption {EditMode = EditMode.Vi});
|
|
if (line.Equals("nodupes"))
|
|
PSConsoleReadLine.SetOptions(new SetPSReadLineOption {HistoryNoDuplicates = true});
|
|
if (line.Equals("vtinput"))
|
|
Environment.SetEnvironmentVariable("PSREADLINE_VTINPUT", "1");
|
|
if (line.Equals("novtinput"))
|
|
Environment.SetEnvironmentVariable("PSREADLINE_VTINPUT", "0");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|