/// <summary> /// Creates a new instance of the ConsoleServicePSHostUserInterface /// class with the given IConsoleHost implementation. /// </summary> /// <param name="powerShellContext">The PowerShellContext to use for executing commands.</param> /// <param name="logger">An ILogger implementation to use for this host.</param> /// <param name="internalHost">The InternalHost instance from the origin runspace.</param> public TerminalPSHostUserInterface( PowerShellContextService powerShellContext, ILogger logger, PSHost internalHost) : base( powerShellContext, new TerminalPSHostRawUserInterface(logger, internalHost), logger) { this.internalHostUI = internalHost.UI; this.consoleReadLine = new ConsoleReadLine(powerShellContext); // Set the output encoding to UTF-8 so that special // characters are written to the console correctly System.Console.OutputEncoding = System.Text.Encoding.UTF8; System.Console.CancelKeyPress += (obj, args) => { if (!this.IsNativeApplicationRunning) { // We'll handle Ctrl+C args.Cancel = true; this.SendControlC(); } }; }
/// <summary> /// Creates an instance of the ConsoleInputPromptHandler class. /// </summary> /// <param name="consoleReadLine"> /// The ConsoleReadLine instance to use for interacting with the terminal. /// </param> /// <param name="hostOutput"> /// The IHostOutput implementation to use for writing to the /// console. /// </param> /// <param name="logger">An ILogger implementation used for writing log messages.</param> public TerminalInputPromptHandler( ConsoleReadLine consoleReadLine, IHostOutput hostOutput, ILogger logger) : base(hostOutput, logger) { this.consoleReadLine = consoleReadLine; }
/// <summary> /// Reads a SecureString from the user. /// </summary> /// <param name="cancellationToken">A CancellationToken that can be used to cancel the prompt.</param> /// <returns>A Task that can be awaited to get the user's response.</returns> protected override async Task <SecureString> ReadSecureStringAsync(CancellationToken cancellationToken) { SecureString secureString = await ConsoleReadLine.ReadSecureLineAsync(cancellationToken).ConfigureAwait(false); this.hostOutput.WriteOutput(string.Empty); return(secureString); }
internal PSReadLinePromptContext( PowerShellContextService powerShellContext, PromptNest promptNest, InvocationEventQueue invocationEventQueue, PSReadLineProxy readLineProxy) { _promptNest = promptNest; _powerShellContext = powerShellContext; _invocationEventQueue = invocationEventQueue; _consoleReadLine = new ConsoleReadLine(powerShellContext); _readLineProxy = readLineProxy; _readLineProxy.OverrideReadKey( intercept => ConsoleProxy.SafeReadKey( intercept, _readLineCancellationSource.Token)); }
internal LegacyReadLineContext(PowerShellContextService powerShellContext) { _legacyReadLine = new ConsoleReadLine(powerShellContext); }
/// <summary> /// Invokes a custom ReadLine method that is similar to but more basic than PSReadLine. /// This method should be used when PSReadLine is disabled, either by user settings or /// unsupported PowerShell versions. /// </summary> /// <param name="isCommandLine"> /// Indicates whether ReadLine should act like a command line. /// </param> /// <param name="cancellationToken"> /// The cancellation token that will be checked prior to completing the returned task. /// </param> /// <returns> /// A task object representing the asynchronus operation. The Result property on /// the task object returns the user input string. /// </returns> internal async Task <string> InvokeLegacyReadLineAsync(bool isCommandLine, CancellationToken cancellationToken) { // TODO: Is inputBeforeCompletion used? string inputBeforeCompletion = null; string inputAfterCompletion = null; CommandCompletion currentCompletion = null; int historyIndex = -1; Collection <PSObject> currentHistory = null; StringBuilder inputLine = new StringBuilder(); int initialCursorCol = await ConsoleProxy.GetCursorLeftAsync(cancellationToken).ConfigureAwait(false); int initialCursorRow = await ConsoleProxy.GetCursorTopAsync(cancellationToken).ConfigureAwait(false); // TODO: Are these used? int initialWindowLeft = Console.WindowLeft; int initialWindowTop = Console.WindowTop; int currentCursorIndex = 0; Console.TreatControlCAsInput = true; try { while (!cancellationToken.IsCancellationRequested) { ConsoleKeyInfo keyInfo = await ReadKeyAsync(cancellationToken).ConfigureAwait(false); // Do final position calculation after the key has been pressed // because the window could have been resized before then int promptStartCol = initialCursorCol; int promptStartRow = initialCursorRow; int consoleWidth = Console.WindowWidth; if ((int)keyInfo.Key == 3 || keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control)) { throw new PipelineStoppedException(); } else if (keyInfo.Key == ConsoleKey.Tab && isCommandLine) { if (currentCompletion == null) { inputBeforeCompletion = inputLine.ToString(); inputAfterCompletion = null; // TODO: This logic should be moved to AstOperations or similar! if (this.powerShellContext.IsDebuggerStopped) { PSCommand command = new PSCommand(); command.AddCommand("TabExpansion2"); command.AddParameter("InputScript", inputBeforeCompletion); command.AddParameter("CursorColumn", currentCursorIndex); command.AddParameter("Options", null); var results = await this.powerShellContext.ExecuteCommandAsync <CommandCompletion>( command, sendOutputToHost : false, sendErrorToHost : false, cancellationToken).ConfigureAwait(false); currentCompletion = results.FirstOrDefault(); } else { using (RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandleAsync(cancellationToken).ConfigureAwait(false)) using (PowerShell powerShell = PowerShell.Create()) { powerShell.Runspace = runspaceHandle.Runspace; currentCompletion = CommandCompletion.CompleteInput( inputBeforeCompletion, currentCursorIndex, null, powerShell); if (currentCompletion.CompletionMatches.Count > 0) { int replacementEndIndex = currentCompletion.ReplacementIndex + currentCompletion.ReplacementLength; inputAfterCompletion = inputLine.ToString( replacementEndIndex, inputLine.Length - replacementEndIndex); } else { currentCompletion = null; } } } } CompletionResult completion = currentCompletion?.GetNextResult( !keyInfo.Modifiers.HasFlag(ConsoleModifiers.Shift)); if (completion != null) { currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, $"{completion.CompletionText}{inputAfterCompletion}", currentCursorIndex, insertIndex: currentCompletion.ReplacementIndex, replaceLength: inputLine.Length - currentCompletion.ReplacementIndex, finalCursorIndex: currentCompletion.ReplacementIndex + completion.CompletionText.Length); } } else if (keyInfo.Key == ConsoleKey.LeftArrow) { currentCompletion = null; if (currentCursorIndex > 0) { currentCursorIndex = ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, currentCursorIndex - 1); } } else if (keyInfo.Key == ConsoleKey.Home) { currentCompletion = null; currentCursorIndex = ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, 0); } else if (keyInfo.Key == ConsoleKey.RightArrow) { currentCompletion = null; if (currentCursorIndex < inputLine.Length) { currentCursorIndex = ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, currentCursorIndex + 1); } } else if (keyInfo.Key == ConsoleKey.End) { currentCompletion = null; currentCursorIndex = ConsoleReadLine.MoveCursorToIndex( promptStartCol, promptStartRow, consoleWidth, inputLine.Length); } else if (keyInfo.Key == ConsoleKey.UpArrow && isCommandLine) { currentCompletion = null; // TODO: Ctrl+Up should allow navigation in multi-line input if (currentHistory == null) { historyIndex = -1; PSCommand command = new PSCommand(); command.AddCommand("Get-History"); currentHistory = await this.powerShellContext.ExecuteCommandAsync <PSObject>( command, sendOutputToHost : false, sendErrorToHost : false, cancellationToken).ConfigureAwait(false) as Collection <PSObject>; if (currentHistory != null) { historyIndex = currentHistory.Count; } } if (currentHistory != null && currentHistory.Count > 0 && historyIndex > 0) { historyIndex--; currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, (string)currentHistory[historyIndex].Properties["CommandLine"].Value, currentCursorIndex, insertIndex: 0, replaceLength: inputLine.Length); } } else if (keyInfo.Key == ConsoleKey.DownArrow && isCommandLine) { currentCompletion = null; // The down arrow shouldn't cause history to be loaded, // it's only for navigating an active history array if (historyIndex > -1 && historyIndex < currentHistory.Count && currentHistory != null && currentHistory.Count > 0) { historyIndex++; if (historyIndex < currentHistory.Count) { currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, (string)currentHistory[historyIndex].Properties["CommandLine"].Value, currentCursorIndex, insertIndex: 0, replaceLength: inputLine.Length); } else if (historyIndex == currentHistory.Count) { currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, string.Empty, currentCursorIndex, insertIndex: 0, replaceLength: inputLine.Length); } } } else if (keyInfo.Key == ConsoleKey.Escape) { currentCompletion = null; historyIndex = currentHistory != null ? currentHistory.Count : -1; currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, string.Empty, currentCursorIndex, insertIndex: 0, replaceLength: inputLine.Length); } else if (keyInfo.Key == ConsoleKey.Backspace) { currentCompletion = null; if (currentCursorIndex > 0) { currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, string.Empty, currentCursorIndex, insertIndex: currentCursorIndex - 1, replaceLength: 1, finalCursorIndex: currentCursorIndex - 1); } } else if (keyInfo.Key == ConsoleKey.Delete) { currentCompletion = null; if (currentCursorIndex < inputLine.Length) { currentCursorIndex = ConsoleReadLine.InsertInput( inputLine, promptStartCol, promptStartRow, string.Empty, currentCursorIndex, replaceLength: 1, finalCursorIndex: currentCursorIndex); } } else if (keyInfo.Key == ConsoleKey.Enter) { string completedInput = inputLine.ToString(); currentCompletion = null; currentHistory = null; //if ((keyInfo.Modifiers & ConsoleModifiers.Shift) == ConsoleModifiers.Shift) //{ // // TODO: Start a new line! // continue; //} Parser.ParseInput( completedInput, out Token[] tokens, out ParseError[] parseErrors);