public void TestHistorySearchCursorMovesToEnd() { TestSetup(KeyMode.Cmd, new KeyHandler("UpArrow", PSConsoleReadLine.HistorySearchBackward), new KeyHandler("DownArrow", PSConsoleReadLine.HistorySearchForward)); PSConsoleReadLine.SetOptions(new SetPSReadlineOption { HistorySearchCursorMovesToEnd = true }); SetHistory("dosomething", "ps p*", "dir", "echo zzz"); Test("dosomething", Keys( "d", _.UpArrow, CheckThat(() => { AssertScreenIs(1, TokenClassification.Command, "dir"); AssertCursorLeftIs(3); }), _.UpArrow, CheckThat(() => { AssertScreenIs(1, TokenClassification.Command, "dosomething"); AssertCursorLeftIs(11); }), _.DownArrow, CheckThat(() => { AssertScreenIs(1, TokenClassification.Command, "dir"); AssertCursorLeftIs(3); }), _.UpArrow, CheckThat(() => { AssertScreenIs(1, TokenClassification.Command, "dosomething"); AssertCursorLeftIs(11); }))); }
public void TestGetSelectionStateAPI() { TestSetup(KeyMode.Cmd); Test("echo", Keys( "echo", CheckThat(() => { int start; int length; PSConsoleReadLine.GetSelectionState(out start, out length); Assert.AreEqual(start, -1); Assert.AreEqual(length, -1); }), _.ShiftHome, CheckThat(() => { int start; int length; PSConsoleReadLine.GetSelectionState(out start, out length); Assert.AreEqual(start, 0); Assert.AreEqual(length, 4); }), _.ShiftRightArrow, CheckThat(() => { int start; int length; PSConsoleReadLine.GetSelectionState(out start, out length); Assert.AreEqual(start, 1); Assert.AreEqual(length, 3); }))); }
private void AssertLineIs(string expected) { string input; int unused; PSConsoleReadLine.GetBufferState(out input, out unused); Assert.AreEqual(expected, input); }
public void TestGetBufferStateAPI() { TestSetup(KeyMode.Cmd); Test("echo", Keys( "echo", CheckThat(() => { string input; int cursor; PSConsoleReadLine.GetBufferState(out input, out cursor); Assert.AreEqual("echo", input); Assert.AreEqual(4, cursor); Ast ast; Token[] tokens; ParseError[] parseErrors; PSConsoleReadLine.GetBufferState(out ast, out tokens, out parseErrors, out cursor); Assert.IsNotNull(ast); Assert.IsTrue(ast is ScriptBlockAst && ((ScriptBlockAst)ast).EndBlock.Statements.Count == 1); Assert.IsTrue((tokens[0].TokenFlags & TokenFlags.CommandName) == TokenFlags.CommandName); Assert.AreEqual(0, parseErrors.Length); Assert.AreEqual(4, cursor); }))); }
private void SetPrompt(string prompt) { var options = new SetPSReadLineOption { ExtraPromptLineCount = 0 }; if (string.IsNullOrEmpty(prompt)) { options.PromptText = new [] { "" }; PSConsoleReadLine.SetOptions(options); return; } int i; for (i = prompt.Length - 1; i >= 0; i--) { if (!char.IsWhiteSpace(prompt[i])) { break; } } options.PromptText = new [] { prompt.Substring(i) }; var lineCount = 1 + prompt.Count(c => c == '\n'); if (lineCount > 1) { options.ExtraPromptLineCount = lineCount - 1; } PSConsoleReadLine.SetOptions(options); _console.Write(prompt); }
public void Inline_SetPredictionColor() { TestSetup(KeyMode.Cmd); var predictionColor = MakeCombinedColor(ConsoleColor.DarkYellow, ConsoleColor.Yellow); var predictionColorToCheck = Tuple.Create(ConsoleColor.DarkYellow, ConsoleColor.Yellow); using var disp = SetPrediction(PredictionSource.History, PredictionViewStyle.InlineView); PSConsoleReadLine.SetOptions(new SetPSReadLineOption { Colors = new Hashtable() { { "InlinePrediction", predictionColor } } }); SetHistory("echo -bar", "eca -zoo"); Test("ech", Keys( 'e', CheckThat(() => AssertScreenIs(1, TokenClassification.Command, 'e', predictionColorToCheck, "ca -zoo")), 'c', CheckThat(() => AssertScreenIs(1, TokenClassification.Command, "ec", predictionColorToCheck, "a -zoo")), 'h', CheckThat(() => AssertScreenIs(1, TokenClassification.Command, "ech", predictionColorToCheck, "o -bar")), // Once accepted, the suggestion text should be blanked out. _.Enter, CheckThat(() => AssertScreenIs(1, TokenClassification.Command, "ech")) )); }
public void ConvertPointToRenderDataOffset_ShouldWork() { InitializeTestData(); PSConsoleReadLine instance = GetPSConsoleReadLineSingleton(); foreach (ResizingTestData test in s_resizingTestData) { RenderData renderData = new() { lines = new RenderedLineData[test.Lines.Count], bufferWidth = test.OldBufferWidth }; for (int i = 0; i < test.Lines.Count; i++) { renderData.lines[i] = new RenderedLineData(test.Lines[i], isFirstLogicalLine: i == 0); } for (int j = 0; j < test.Context.Count; j++) { ResizingTestContext context = test.Context[j]; renderData.cursorLeft = context.OldCursor.X; renderData.cursorTop = context.OldCursor.Y; RenderDataOffset offset = instance.ConvertPointToRenderDataOffset(context.OldInitial.X, context.OldInitial.Y, renderData); Assert.True( context.Offset.LineIndex == offset.LogicalLineIndex && context.Offset.CharIndex == offset.VisibleCharIndex, $"{test.Name}-context_{j}: calculated offset is not what's expected [line: {offset.LogicalLineIndex}, char: {offset.VisibleCharIndex}]"); } } }
internal static void OneTimeInit(PSConsoleReadLine singleton) { _singleton = singleton; var breakHandlerGcHandle = GCHandle.Alloc(new BreakHandler(OnBreak)); SetConsoleCtrlHandler((BreakHandler)breakHandlerGcHandle.Target, true); }
protected override void EndProcessing() { using (UseRequestedDispatchTables()) { PSConsoleReadLine.RemoveKeyHandler(Chord); } }
public void SetInvalidColorOptions() { bool throws = false; try { PSConsoleReadLine.SetOptions(new SetPSReadLineOption { Colors = new Hashtable { { "InvalidProperty", ConsoleColor.Magenta } }, }); } catch (ArgumentException) { throws = true; } Assert.True(throws, "Invalid color property should throw"); throws = false; try { PSConsoleReadLine.SetOptions(new SetPSReadLineOption { Colors = new Hashtable { { "Default", "apple" } }, }); } catch (ArgumentException) { throws = true; } Assert.True(throws, "Invalid color value should throw"); }
protected IDisposable UseRequestedDispatchTables() { bool inViMode = PSConsoleReadLine.GetOptions().EditMode == EditMode.Vi; bool viModeParamPresent = MyInvocation.BoundParameters.ContainsKey("ViMode"); if (inViMode || viModeParamPresent) { if (!inViMode) { // "-ViMode" must have been specified explicitly. Well, okay... we can // modify the Vi tables... but isn't that an odd thing to do from // not-vi mode? WriteWarning(PSReadLineResources.NotInViMode); } if (ViMode == ViMode.Command) { return(PSConsoleReadLine.UseViCommandModeTables()); } else // default if -ViMode not specified, invalid, or "Insert" { return(PSConsoleReadLine.UseViInsertModeTables()); } } return(null); }
private void Test(string expectedResult, object[] items, bool resetCursor = true, string prompt = null, bool mustDing = false) { if (resetCursor) { _console.CursorLeft = 0; _console.CursorTop = 0; } SetPrompt(prompt); _console.Init(items); var result = PSConsoleReadLine.ReadLine(null, null); if (_console.validationFailure != null) { throw new Exception("", _console.validationFailure); } while (_console.index < _console.inputOrValidateItems.Length) { var item = _console.inputOrValidateItems[_console.index++]; ((Action)item)(); } Assert.AreEqual(expectedResult, result); if (mustDing) { Assert.IsTrue(_mockedMethods.didDing); } }
public static string GetText() { if (_clipboardSupported == false) { PSConsoleReadLine.Ding(); return(_internalClipboard ?? ""); } string tool = ""; string args = ""; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { string clipboardText = ""; ExecuteOnStaThread(() => GetTextImpl(out clipboardText)); return(clipboardText); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { tool = "xclip"; args = "-selection clipboard -out"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { tool = "pbpaste"; } else { _clipboardSupported = false; PSConsoleReadLine.Ding(); return(""); } return(StartProcess(tool, args)); }
public void TestCharacterSearchBackward() { TestSetup(KeyMode.Cmd); Test("cmd1 | cmd2 | cmd3", Keys( "cmd1 | cmd2 | cmd3", _.ShiftF3, '|', CheckThat(() => AssertCursorLeftIs(12)), _.ShiftF3, '|', CheckThat(() => AssertCursorLeftIs(5)))); TestSetup(KeyMode.Emacs); Test("cmd1 | cmd2 | cmd3", Keys( "cmd1 | cmd2 | cmd3", _.AltCtrlRBracket, '|', CheckThat(() => AssertCursorLeftIs(12)), _.AltCtrlRBracket, '|', CheckThat(() => AssertCursorLeftIs(5)), _.Home, _.AltMinus, _.Alt2, _.AltCtrlRBracket, '|', CheckThat(() => AssertCursorLeftIs(12)), _.End, _.Alt2, _.AltCtrlRBracket, '|', CheckThat(() => AssertCursorLeftIs(5)))); TestMustDing("cmd1 | cmd2 | cmd3", Keys( "cmd1 | cmd2 | cmd3", _.AltCtrlRBracket, 'z')); int i = 0; TestSetup(KeyMode.Cmd, new KeyHandler("Ctrl+z", (key, count) => PSConsoleReadLine.CharacterSearchBackward(null, i++ == 0 ? (object)'|' : "|"))); Test("cmd1 | cmd2 | cmd3", Keys( "cmd1 | cmd2 | cmd3", _.CtrlZ, CheckThat(() => AssertCursorLeftIs(12)), _.CtrlZ, CheckThat(() => AssertCursorLeftIs(5)))); }
public void ViGetKeyHandlers() { TestSetup(KeyMode.Vi); foreach (var handler in PSConsoleReadLine.GetKeyHandlers(includeBound: false, includeUnbound: true)) { Assert.Equal("Unbound", handler.Key); Assert.False(string.IsNullOrWhiteSpace(handler.Function)); Assert.False(string.IsNullOrWhiteSpace(handler.Description)); } foreach (var handler in PSConsoleReadLine.GetKeyHandlers(includeBound: true, includeUnbound: false)) { Assert.NotEqual("Unbound", handler.Key); Assert.False(string.IsNullOrWhiteSpace(handler.Function)); Assert.False(string.IsNullOrWhiteSpace(handler.Description)); } var handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "home" }); Assert.NotEmpty(handlers); foreach (var handler in handlers) { Assert.Contains("Home", handler.Key); } handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "d,0" }); Assert.NotEmpty(handlers); foreach (var handler in handlers) { Assert.Equal("<d,0>", handler.Key); } }
public void TestReplaceAPI() { TestSetup(KeyMode.Cmd); Test("echo zzz", Keys( "echo foobar", CheckThat(() => PSConsoleReadLine.Replace(5, 6, "zzz")))); bool throws = false; Test("echo", Keys( "echo", CheckThat(() => { try { PSConsoleReadLine.Replace(-1, 6, "zzz"); } catch (ArgumentException) { throws = true; } Assert.IsTrue(throws, "Negative start should throw"); try { PSConsoleReadLine.Replace(11, 6, "zzz"); } catch (ArgumentException) { throws = true; } Assert.IsTrue(throws, "Start beyond end of buffer should throw"); try { PSConsoleReadLine.Replace(0, 12, "zzz"); } catch (ArgumentException) { throws = true; } Assert.IsTrue(throws, "Length too long should throw"); }))); }
private void Test(string expectedResult, object[] items, bool resetCursor, string prompt, bool mustDing) { if (resetCursor) { _console.Clear(); } SetPrompt(prompt); _console.Init(items); var result = PSConsoleReadLine.ReadLine( runspace: null, engineIntrinsics: null, lastRunStatus: true); if (_console.validationFailure != null) { throw new Exception("", _console.validationFailure); } while (_console.index < _console.inputOrValidateItems.Length) { var item = _console.inputOrValidateItems[_console.index++]; ((Action)item)(); } Assert.Equal(expectedResult, result); if (mustDing) { Assert.True(_mockedMethods.didDing); } }
public void TestPossibleCompletionsPrompt() { TestSetup(KeyMode.Cmd); PSConsoleReadLine.GetOptions().CompletionQueryItems = 10; Console.Clear(); Test("Get-Many", Keys( "Get-Many", _.CtrlSpace, CheckThat(() => AssertScreenIs(2, TokenClassification.Command, "Get-Many", NextLine, TokenClassification.None, "Display all 15 possibilities? (y or n) _")), "n")); Console.Clear(); Test("Get-Many", Keys( "Get-Many", _.CtrlSpace, CheckThat(() => AssertScreenIs(2, TokenClassification.Command, "Get-Many", NextLine, TokenClassification.None, "Display all 15 possibilities? (y or n) _")), "y", CheckThat(() => AssertScreenIs(4, TokenClassification.Command, "Get-Many", NextLine, TokenClassification.None, "Get-Many0 Get-Many3 Get-Many6 Get-Many9 Get-Many12", NextLine, "Get-Many1 Get-Many4 Get-Many7 Get-Many10 Get-Many13", NextLine, "Get-Many2 Get-Many5 Get-Many8 Get-Many11 Get-Many14")))); }
public void TestHistoryNoDuplicates() { TestSetup(KeyMode.Cmd); PSConsoleReadLine.SetOptions(new SetPSReadlineOption { HistoryNoDuplicates = false }); SetHistory("zzzz", "aaaa", "bbbb", "bbbb", "cccc"); Test("aaaa", Keys(Enumerable.Repeat(_.UpArrow, 4))); // Changing the option should affect existing history. PSConsoleReadLine.SetOptions(new SetPSReadlineOption { HistoryNoDuplicates = true }); Test("zzzz", Keys(Enumerable.Repeat(_.UpArrow, 4))); SetHistory("aaaa", "bbbb", "bbbb", "cccc"); Test("aaaa", Keys(Enumerable.Repeat(_.UpArrow, 3))); SetHistory("aaaa", "bbbb", "bbbb", "cccc"); Test("cccc", Keys( Enumerable.Repeat(_.UpArrow, 3), Enumerable.Repeat(_.DownArrow, 2))); // No history SetHistory(); Test("", Keys(_.UpArrow, _.DownArrow)); }
public void TestYankLastArg() { TestSetup(KeyMode.Emacs); SetHistory(); TestMustDing("", Keys(_.AltPeriod)); SetHistory("echo def"); Test("def", Keys(_.AltPeriod)); SetHistory("echo abc", "echo def"); Test("abc", Keys(_.AltPeriod, _.AltPeriod)); SetHistory("echo aa bb cc 'zz zz $(1 2 3)'"); Test("echo bb 'zz zz $(1 2 3)' cc", Keys( _.Alt0, _.AltPeriod, ' ', _.Alt2, _.AltPeriod, ' ', _.AltMinus, _.AltPeriod, ' ', _.AltMinus, _.Alt2, _.AltPeriod)); SetHistory("echo a", "echo b"); TestMustDing("a", Keys( _.AltPeriod, _.AltPeriod, _.AltPeriod)); SetHistory("echo a", "echo b"); TestMustDing("b", Keys( _.AltPeriod, _.AltPeriod, _.AltMinus, _.AltPeriod, _.AltPeriod)); // Somewhat silly test to make sure invalid args are handled reasonably. TestSetup(KeyMode.Emacs, new[] { new KeyHandler("Ctrl+Z", (key, arg) => PSConsoleReadLine.YankLastArg(null, "zz")) }); SetHistory("echo a", "echo a"); TestMustDing("", Keys(_.CtrlZ)); TestMustDing("a", Keys(_.AltPeriod, _.CtrlZ)); }
protected override void EndProcessing() { using (UseRequestedDispatchTables()) { if (ParameterSetName.Equals(FunctionParameterSet)) { var function = (string)_dynamicParameters.Value[FunctionParameter].Value; MethodInfo mi = typeof(PSConsoleReadLine).GetMethod(function, BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase); string functionName = mi.Name; var keyHandler = (Action <ConsoleKeyInfo?, object>) mi.CreateDelegate(typeof(Action <ConsoleKeyInfo?, object>)); string longDescription = PSReadLineResources.ResourceManager.GetString( functionName + "Description"); PSConsoleReadLine.SetKeyHandler(Chord, keyHandler, functionName, longDescription); } else { PSConsoleReadLine.SetKeyHandler(Chord, ScriptBlock, BriefDescription, Description); } } }
static private void SetPrompt(string prompt) { if (string.IsNullOrEmpty(prompt)) { return; } var handle = NativeMethods.GetStdHandle((uint)StandardHandleId.Output); var lineCount = 1 + prompt.Count(c => c == '\n'); if (lineCount > 1) { var options = new SetPSReadlineOption { ExtraPromptLineCount = lineCount - 1 }; PSConsoleReadLine.SetOptions(options); } int bufferWidth = Console.BufferWidth; var consoleBuffer = new CHAR_INFO[lineCount * bufferWidth]; int j = 0; for (int i = 0; i < prompt.Length; i++, j++) { if (prompt[i] == '\n') { for (; j % Console.BufferWidth != 0; j++) { consoleBuffer[j] = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor); } Console.CursorTop += 1; Console.CursorLeft = 0; j -= 1; // We don't actually write the newline } else { consoleBuffer[j] = new CHAR_INFO(prompt[i], Console.ForegroundColor, Console.BackgroundColor); Console.CursorLeft += 1; } } var bufferSize = new COORD { X = (short)bufferWidth, Y = (short)lineCount }; var bufferCoord = new COORD { X = 0, Y = 0 }; var writeRegion = new SMALL_RECT { Top = 0, Left = 0, Bottom = (short)(lineCount - 1), Right = (short)bufferWidth }; NativeMethods.WriteConsoleOutput(handle, consoleBuffer, bufferSize, bufferCoord, ref writeRegion); }
internal static void Init(ref ICharMap charMap) { // If either stdin or stdout is redirected, PSReadLine doesn't really work, so throw // and let PowerShell call Console.ReadLine or do whatever else it decides to do. if (IsHandleRedirected(stdin: false) || IsHandleRedirected(stdin: true)) { // Some CI environments redirect stdin/stdout, but that doesn't affect our test runs // because the console is mocked, so we can skip the exception. if (!PSConsoleReadLine.IsRunningCI()) { throw new NotSupportedException(); } } if (_enableVtOutput) { // This is needed because PowerShell does not restore the console mode // after running external applications, and some popular applications // clear VT, e.g. git. SetConsoleOutputVirtualTerminalProcessing(); } // If input is redirected, we can't use console APIs and have to use VT input. if (IsHandleRedirected(stdin: true)) { EnableAnsiInput(ref charMap); } else { _prePSReadLineConsoleInputMode = GetConsoleInputMode(); // This envvar will force VT mode on or off depending on the setting 1 or 0. var overrideVtInput = Environment.GetEnvironmentVariable("PSREADLINE_VTINPUT"); if (overrideVtInput == "1") { _enableVtInput = true; } else if (overrideVtInput == "0") { _enableVtInput = false; } else { // If the console was already in VT mode, use the appropriate CharMap. // This handles the case where input was not redirected and the user // didn't specify a preference. The default is to use the pre-existing // console mode. _enableVtInput = (_prePSReadLineConsoleInputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) == ENABLE_VIRTUAL_TERMINAL_INPUT; } if (_enableVtInput) { EnableAnsiInput(ref charMap); } SetOurInputMode(); } }
private void SetHistory(params string[] historyItems) { PSConsoleReadLine.ClearHistory(); foreach (var item in historyItems) { PSConsoleReadLine.AddToHistory(item); } }
public void TestDeleteAPI() { TestSetup(KeyMode.Cmd); Test("echo", Keys( "echo zzz", CheckThat(() => PSConsoleReadLine.Delete(4, 4)))); }
public void ShowTooltips() { TestSetup(KeyMode.Cmd, new KeyHandler("Ctrl+Spacebar", PSConsoleReadLine.PossibleCompletions)); PSConsoleReadLine.GetOptions().ShowToolTips = true; _console.Clear(); // TODO: }
public void BackwardKillLine() { TestSetup(KeyMode.Emacs); PSConsoleReadLine.SetKeyHandler(new[] { "Shift+Tab" }, PSConsoleReadLine.BackwardKillLine, "", ""); Test("", Keys("dir", _.Shift_Tab)); }
public void PossibleCompletions() { TestSetup(KeyMode.Emacs); _console.Clear(); // Test empty input, make sure line after the cursor is blank and cursor didn't move Test("", Keys( _.Alt_Equals, CheckThat(() => { AssertCursorLeftTopIs(0, 0); AssertScreenIs(2, NextLine); }))); const string promptLine1 = "c:\\windows"; const string promptLine2 = "PS> "; using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace)) { ps.AddScript($@"function prompt {{ ""{promptLine1}`n{promptLine2}"" }}"); ps.Invoke(); } PSConsoleReadLine.SetOptions(new SetPSReadLineOption { ExtraPromptLineCount = 1 }); _console.Clear(); Test("psvar", Keys( "psvar", _.Alt_Equals, CheckThat(() => AssertScreenIs(5, TokenClassification.None, promptLine1, NextLine, promptLine2, TokenClassification.Command, "psvar", NextLine, "$pssomething", NextLine, TokenClassification.None, promptLine1, NextLine, promptLine2, TokenClassification.Command, "psvar"))), prompt: promptLine1 + "\n" + promptLine2); using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace)) { ps.AddCommand("Remove-Item").AddArgument("function:prompt"); ps.Invoke(); } _console.Clear(); TestMustDing("none", Keys( "none", _.Alt_Equals, CheckThat(() => AssertScreenIs(2, TokenClassification.Command, "none", NextLine)))); }
public void TestAddToHistoryHandler() { TestSetup(KeyMode.Cmd); PSConsoleReadLine.SetOptions(new SetPSReadlineOption { AddToHistoryHandler = s => s.StartsWith("z") }); SetHistory("zzzz", "azzz"); Test("zzzz", Keys(_.UpArrow)); }
internal static IConsole OneTimeInit(PSConsoleReadLine singleton) { _singleton = singleton; var breakHandlerGcHandle = GCHandle.Alloc(new BreakHandler(OnBreak)); SetConsoleCtrlHandler((BreakHandler)breakHandlerGcHandle.Target, true); _enableVtOutput = !Console.IsOutputRedirected && SetConsoleOutputVirtualTerminalProcessing(); return(_enableVtOutput ? new VirtualTerminal() : new LegacyWin32Console()); }